com.POLIS.licensing.frontend.AnnotationEnabledFrontendTest.java Source code

Java tutorial

Introduction

Here is the source code for com.POLIS.licensing.frontend.AnnotationEnabledFrontendTest.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.POLIS.licensing.frontend;

import com.POLIS.licensing.frontend.FrontendSystemConnector;
import com.POLIS.licensing.frontend.AnnotationEnabledFrontend;
import com.POLIS.licensing.common.decorator.LicenseDecorator;
import com.POLIS.licensing.common.annotation.LicenseElement;
import com.POLIS.licensing.common.exception.BadLicenseException;
import com.POLIS.licensing.common.exception.OperationException;
import com.POLIS.licensing.common.exception.SystemStateException;
import com.POLIS.licensing.common.license.AbstractSerializationBasedLicense;
import com.POLIS.licensing.common.license.AbstractSerializationBasedLicenseFactory;
import com.POLIS.licensing.common.license.License;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.codec.binary.Base64;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Martin
 */
public class AnnotationEnabledFrontendTest {

    AnnotationEnabledFrontend<TestLicense> frontend;
    PublicKey serverPubKey;
    PrivateKey serverPrivKey;

    public AnnotationEnabledFrontendTest() {
    }

    @BeforeClass
    public static void setUpClass() {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    @AfterClass
    public static void tearDownClass() {
    }

    @Before
    public void setUp()
            throws NoSuchAlgorithmException, NoSuchProviderException, SystemStateException, OperationException {
        frontend = new AnnotationEnabledFrontend<>(new TestFactory(), new TestConnector(), new TestDecorator());

        SecureRandom random = new SecureRandom();
        KeyPairGenerator rsagenerator = KeyPairGenerator.getInstance("RSA", "BC");
        rsagenerator.initialize(1024, random);
        KeyPair pair = rsagenerator.generateKeyPair();
        serverPubKey = pair.getPublic();
        serverPrivKey = pair.getPrivate();
        frontend.initialize(serverPubKey);
    }

    @After
    public void tearDown() {
    }

    /**
     * Test of licenseToDisk method, of class AbstractAnnotationEnabledFrontend.
     */
    @Test
    public void testLicenseToDisk() throws Exception {
        File licenseFile = new File("request.license");

        TestLicense license = frontend.blankLicense();
        license.hostname = "test.host";
        license.initiator = "some bloke";
        license.created = System.currentTimeMillis();
        license.signLicense(frontend.getFrontendPrivKey());
        frontend.licenseToDisk(licenseFile, license);

        TestFactory factory = new TestFactory();
        String licenseString = "";
        TestLicense retrievedLicense;
        try (FileInputStream stream = new FileInputStream(licenseFile);
                InputStreamReader input = new InputStreamReader(stream, "UTF-8");
                BufferedReader reader = new BufferedReader(input)) {
            while (reader.ready()) {
                licenseString = licenseString + reader.readLine();
            }
        }

        retrievedLicense = factory.loadLicense(licenseString, serverPrivKey, frontend.getFrontendPubKey());

        assertTrue("Retrieved license differed from Original", license.equals(retrievedLicense));
    }

    /**
     * Test of licenseRequest method, of class AbstractAnnotationEnabledFrontend.
     */
    @Test
    public void testLicenseRequest() throws Exception {
        TestLicense freshLicense = frontend.blankLicense();
        freshLicense.created = System.currentTimeMillis();
        freshLicense.hostname = "Test";
        freshLicense.id = UUID.randomUUID();
        TestLicense request = frontend.licenseRequest(freshLicense);
        assertTrue("Could not verify license", request.verifyLicense(frontend.getFrontendPubKey()));

    }

    /**
     * Test of loadLicenseFromDisk method, of class AbstractAnnotationEnabledFrontend.
     */
    @Test
    public void testLoadLicenseFromDisk() throws Exception {
        //Create license request.
        File licenseLocation = new File("test.license");
        TestLicense freshLicense = frontend.blankLicense();
        freshLicense.created = System.currentTimeMillis();
        freshLicense.hostname = "Test";
        freshLicense.id = UUID.randomUUID();
        TestLicense request = frontend.licenseRequest(freshLicense);
        request.signLicense(frontend.getFrontendPrivKey());
        frontend.licenseToDisk(licenseLocation, request);

        //Load request "server-side" and sign
        String serverLicenseString = "";
        try (FileInputStream stream = new FileInputStream(licenseLocation);
                InputStreamReader input = new InputStreamReader(stream, "UTF-8");
                BufferedReader reader = new BufferedReader(input)) {
            while (reader.ready()) {
                serverLicenseString = serverLicenseString + reader.readLine();
            }
        }
        TestFactory factory = new TestFactory();

        TestLicense serverSideLicense = factory.loadLicense(serverLicenseString, serverPrivKey,
                frontend.getFrontendPubKey());
        serverSideLicense.authorizations = new ArrayList<String>(
                Arrays.asList(new String[] { "Auth1", "Auth2", "Auth3", "Auth4", "Auth5" }));
        serverSideLicense.signed = System.currentTimeMillis();
        serverSideLicense.signLicense(serverPrivKey);
        String licenseString = serverSideLicense.getEncryptedLicense(frontend.getFrontendPubKey());
        try (FileWriter filewriter = new FileWriter(licenseLocation);
                BufferedWriter writer = new BufferedWriter(filewriter);) {
            writer.append(licenseString);
        }

        //Load the license in frontend
        frontend.loadLicenseFromDisk(licenseLocation);
        assertTrue("License in frontend was not the same as on the server",
                frontend.getCurrentLicense().equals(serverSideLicense));

    }

    /**
     * Test of checkLicenseAvailable method, of class AbstractAnnotationEnabledFrontend.
     */
    @Test
    public void testCheckLicenseAvailable1() throws Exception {
        assertFalse("License should not be available at start", frontend.checkLicenseAvailable());
        testLoadLicenseFromDisk();
        assertTrue("License should be available after load", frontend.checkLicenseAvailable());
    }

    @Test
    public void testCheckLicenseAvailable2() throws Exception {
        assertFalse("License should not be available at start", frontend.checkLicenseAvailable());
        testLoadLicenseFromDisk();
        frontend.getCurrentLicense().hostname = "ChangingHostnameWithoutResigning";
        assertFalse("License should be available. Hostname changed without new server signature",
                frontend.checkLicenseAvailable());
    }

    /**
     * Test of load method, of class AbstractAnnotationEnabledFrontend.
     */
    @Test
    public void testLoad() throws Exception {
        testLoadLicenseFromDisk();
        frontend = new AnnotationEnabledFrontend<>(new TestFactory(), new TestConnector(), new TestDecorator());
        assertTrue("Loading failed", frontend.load());
        assertTrue("Loading of license failed", frontend.checkLicenseAvailable());

    }

    /**
     * Test of blankLicense method, of class AbstractAnnotationEnabledFrontend.
     */
    @Test
    public void testBlankLicense() {
        TestFactory factory = new TestFactory();
        assertTrue("The licenses should be equal", factory.createEmptyLicense().equals(frontend.blankLicense()));
    }

    public static class TestLicense extends AbstractSerializationBasedLicense {

        @LicenseElement(name = "hostname")
        String hostname;
        @LicenseElement(name = "ID", mandatory = LicenseElement.Mandatory.BOTH)
        UUID id;
        @LicenseElement(name = "creator", mandatory = LicenseElement.Mandatory.REQUEST)
        String initiator;
        @LicenseElement(name = "authorizations")
        List<String> authorizations;
        @LicenseElement(name = "time_created", mandatory = LicenseElement.Mandatory.REQUEST)
        Long created;
        @LicenseElement(name = "time_signed", mandatory = LicenseElement.Mandatory.REQUEST)
        Long signed;

        public TestLicense() {
            super();
        }

        @Override
        protected String getFieldsAsString() {
            return (hostname != null ? hostname : "") + (id != null ? id.toString() : "")
                    + (initiator != null ? initiator : "") + (authorizations != null ? authorizations : "")
                    + (created != null ? created : "") + (signed != null ? signed : "");
        }

        @Override
        public boolean isRequestSignable() throws BadLicenseException {
            return hostname != null && initiator != null && created != null;
        }

        @Override
        public boolean isLicenseSignable() throws BadLicenseException {
            return authorizations != null;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final TestLicense other = (TestLicense) obj;
            if (!Objects.equals(this.hostname, other.hostname)) {
                return false;
            }
            if (!Objects.equals(this.id, other.id)) {
                return false;
            }
            if (!Objects.equals(this.initiator, other.initiator)) {
                return false;
            }
            if (!Objects.equals(this.authorizations, other.authorizations)) {
                return false;
            }
            if (!Objects.equals(this.created, other.created)) {
                return false;
            }
            if (!Objects.equals(this.signed, other.signed)) {
                return false;
            }
            return true;
        }

    }

    public static class TestFactory extends AbstractSerializationBasedLicenseFactory<TestLicense> {

        @Override
        protected TestLicense getDeserializedObject(byte[] objectAsBytes)
                throws IOException, ClassNotFoundException, SystemStateException {
            return (TestLicense) this.defaultGetDeserializedObject(objectAsBytes);
        }

        @Override
        public TestLicense createEmptyLicense() {
            return new TestLicense();
        }

    }

    public static class TestConnector implements FrontendSystemConnector<TestLicense> {
        private static final File licenseFile = new File("current.license");
        private static final File serverKeyFile = new File("server.key");
        private static final File frontendPubKeyFile = new File("pub.key");
        private static final File frontendPrivKeyFile = new File("priv.key");

        @Override
        public TestLicense loadLicense(PublicKey clientPublicKey, PrivateKey clientPrivateKey,
                PublicKey serverPublicKey) throws SystemStateException, OperationException, IOException {
            TestFactory factory = new TestFactory();
            try (FileInputStream stream = new FileInputStream(licenseFile);
                    InputStreamReader input = new InputStreamReader(stream, "UTF-8");
                    BufferedReader reader = new BufferedReader(input)) {
                StringBuilder builder = new StringBuilder();
                while (reader.ready()) {
                    builder.append(reader.readLine());
                }
                return factory.loadLicense(builder.toString(), clientPrivateKey, serverPublicKey);
            } catch (BadLicenseException ex) {
                throw new OperationException("Could not read license", ex);
            }
        }

        @Override
        public void saveLicense(TestLicense license, PublicKey clientPublicKey, PrivateKey clientPrivateKey,
                PublicKey serverPublicKey) throws SystemStateException, IOException, OperationException {
            try (FileOutputStream stream = new FileOutputStream(licenseFile);
                    OutputStreamWriter output = new OutputStreamWriter(stream, "UTF-8");
                    BufferedWriter writer = new BufferedWriter(output)) {
                writer.append(license.getEncryptedLicense(clientPublicKey));
            }
        }

        @Override
        public void saveServerKey(PublicKey serverPublicKey) throws IOException {
            this.byteArrayToFile(serverPublicKey.getEncoded(), serverKeyFile);
        }

        @Override
        public void saveClientPublicKey(PublicKey clientPublicKey) throws IOException {
            this.byteArrayToFile(clientPublicKey.getEncoded(), frontendPubKeyFile);
        }

        @Override
        public void saveClientPrivateKey(PrivateKey clientPrivateKey) throws IOException {
            this.byteArrayToFile(clientPrivateKey.getEncoded(), frontendPrivKeyFile);
        }

        @Override
        public PublicKey loadServerKey() throws SystemStateException, IOException {
            PublicKey publicKey;
            try {
                publicKey = KeyFactory.getInstance("RSA")
                        .generatePublic(new X509EncodedKeySpec(byteArrayFromFile(TestConnector.serverKeyFile)));
            } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
                throw new SystemStateException("Invalid keyspec", ex);
            }
            return publicKey;
        }

        @Override
        public PublicKey loadClientPublicKey() throws SystemStateException, IOException {
            PublicKey publicKey;
            try {
                publicKey = KeyFactory.getInstance("RSA").generatePublic(
                        new X509EncodedKeySpec(byteArrayFromFile(TestConnector.frontendPubKeyFile)));
            } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
                throw new SystemStateException("Invalid keyspec", ex);
            }
            return publicKey;
        }

        @Override
        public PrivateKey loadClientPrivateKey() throws SystemStateException, IOException {
            PrivateKey privkey;
            try {
                privkey = KeyFactory.getInstance("RSA").generatePrivate(
                        new PKCS8EncodedKeySpec(byteArrayFromFile(TestConnector.frontendPrivKeyFile)));
            } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
                throw new SystemStateException("Invalid keyspec", ex);
            }
            return privkey;
        }

        private void byteArrayToFile(byte[] arr, File target)
                throws FileNotFoundException, UnsupportedEncodingException, IOException {
            try (FileOutputStream stream = new FileOutputStream(target);
                    OutputStreamWriter output = new OutputStreamWriter(stream, "UTF-8");
                    BufferedWriter writer = new BufferedWriter(output)) {
                writer.append(Base64.encodeBase64String(arr));
            }
        }

        private byte[] byteArrayFromFile(File target)
                throws FileNotFoundException, UnsupportedEncodingException, IOException {
            byte[] arr;
            try (FileInputStream stream = new FileInputStream(target);
                    InputStreamReader input = new InputStreamReader(stream, "UTF-8");
                    BufferedReader reader = new BufferedReader(input)) {
                StringBuilder builder = new StringBuilder();
                while (reader.ready()) {
                    builder.append(reader.readLine());
                }
                arr = Base64.decodeBase64(builder.toString());
            }
            return arr;
        }

    }

    private static class TestDecorator implements LicenseDecorator<TestLicense> {

        @Override
        public HashMap<String, Object> getLicenseData(TestLicense licenseToDecorate) {
            HashMap<String, Object> decorations = new HashMap<>();
            decorations.put("time_signed", System.currentTimeMillis());
            return decorations;
        }

        @Override
        public void decorate(TestLicense license) {
            license.initiator = "BillyBonka";
        }

    }

}