From 8cc95fdfbe8146af8d5d4bcac7f7b9e3e2eb95c6 Mon Sep 17 00:00:00 2001
From: Roberto Sánchez <roberto.sanchez@curisit.net>
Date: Fri, 21 Feb 2014 13:52:42 +0000
Subject: [PATCH] #0 feaure - Created main methods for License validation
---
src/main/java/net/curisit/securis/LicenseValidator.java | 0
src/main/resources/images/logo_customer.png | 0
src/main/java/net/curisit/securis/utils/LicUtils.java | 0
src/main/java/net/curisit/securis/HWInfo.java | 122 +++++
src/main/resources/securis-client.properties | 1
pom.xml | 16
src/main/java/net/curisit/securis/License.java | 7
src/main/java/net/curisit/securis/beans/LicenseBean.java | 64 ++
/dev/null | 11
src/main/java/net/curisit/securis/SeCurisException.java | 17
src/main/java/net/curisit/securis/utils/Params.java | 191 ++++++++
src/main/java/net/curisit/securis/CryptoHelper.java | 155 +++++++
src/main/java/net/curisit/securis/utils/JsonUtils.java | 205 +++++++++
src/main/java/net/curisit/securis/LicenseManager.java | 47 ++
doc/README.md | 16
src/main/java/net/curisit/securis/SignatureHelper.java | 144 ++++++
src/main/java/net/curisit/securis/ReqGenerator.java | 59 ++
src/main/java/net/curisit/securis/beans/RequestBean.java | 97 ++++
src/main/resources/log4j.xml | 26 +
src/patch/java/net/curisit/securis/LicenseGenerator.java | 106 ++++
20 files changed, 1,271 insertions(+), 13 deletions(-)
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 0000000..252a4de
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,16 @@
+### Private and Public keys generation
+
+DSA
+
+ openssl dsaparam -out dsaparam.pem 2048
+ openssl gendsa -pkcs8 -out privkey.pem dsaparam.pem
+
+ openssl dsa -in privkey.pem -pubout > mykey.pub
+ openssl pkcs8 -topk8 -inform PEM -in privkey.pem -out privkey.pkcs8 -nocrypt
+
+RSA
+
+ openssl genrsa -des3 -out privkey.pem 2048
+ openssl rsa -in privkey.pem -pubout > mykey.pub
+ openssl pkcs8 -topk8 -inform PEM -in privkey.pem -out privkey.pkcs8 -nocrypt
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 27659dc..23a9cdd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,6 @@
<artifactId>securis-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
- <sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
@@ -37,5 +36,20 @@
<artifactId>commons-cli</artifactId>
<version>1.2</version>
</dependency>
+ <dependency>
+ <groupId>commons-net</groupId>
+ <artifactId>commons-net</artifactId>
+ <version>3.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>1.9.13</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ <version>2.0-rc1</version>
+ </dependency>
</dependencies>
</project>
\ No newline at end of file
diff --git a/src/main/java/net/curisit/securis/CryptoHelper.java b/src/main/java/net/curisit/securis/CryptoHelper.java
new file mode 100644
index 0000000..dd55a09
--- /dev/null
+++ b/src/main/java/net/curisit/securis/CryptoHelper.java
@@ -0,0 +1,155 @@
+package net.curisit.securis;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.net.util.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+//import net.curisit.common.ui.Dialogs;
+
+public class CryptoHelper {
+
+ private static final Logger log = LoggerFactory.getLogger(SignatureHelper.class);
+
+ private static final String KEY_FACTORY = "PBEWITHHMACSHA1";
+ private static final String PPROVIDER = "BC";
+ private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
+
+ private static CryptoHelper singleton = new CryptoHelper();
+
+ private String passPhrase = null;
+
+ private CryptoHelper() {
+ }
+
+ public static CryptoHelper getInstance() {
+ return singleton;
+ }
+
+ /**
+ * Encrypts a given text with AES algorithm
+ *
+ * @param plainText
+ * @return The encrypted text in Base64
+ */
+ public String encrypt(String plainText) throws SeCurisException {
+ return encrypt(plainText, this.passPhrase);
+ }
+
+ public String encrypt(String plainText, String pass) throws SeCurisException {
+ Cipher aes;
+ try {
+ aes = Cipher.getInstance(CIPHER_ALGORITHM);
+ byte[] salt = getSalt();
+ aes.init(Cipher.ENCRYPT_MODE, getSecretKey(salt, pass));
+ byte[] ciphertext = aes.doFinal(plainText.getBytes("utf-8"));
+
+ return Base64.encodeBase64String(salt) + "\n" + Base64.encodeBase64String(ciphertext);
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (NoSuchPaddingException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (InvalidKeyException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (IllegalBlockSizeException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (BadPaddingException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (UnsupportedEncodingException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ }
+ }
+
+ /**
+ * Encrypts a given text with AES algorithm
+ *
+ * @param plainText
+ * in Base64
+ * @return
+ */
+ public String decript(String ciphertext) throws SeCurisException {
+ return decript(ciphertext, this.passPhrase);
+ }
+
+ public String decript(String ciphertext, String pass) throws SeCurisException {
+ Cipher aes;
+ try {
+ aes = Cipher.getInstance(CIPHER_ALGORITHM);
+ int sep = ciphertext.indexOf('\n');
+ if (sep == -1)
+ throw new SeCurisException("Unknown format ciphered text");
+ byte[] salt = Base64.decodeBase64(ciphertext.substring(0, sep));
+ aes.init(Cipher.DECRYPT_MODE, getSecretKey(salt, pass));
+ byte[] encryptedBytes = Base64.decodeBase64(ciphertext.substring(sep + 1));
+ String cleartext = new String(aes.doFinal(encryptedBytes));
+ return cleartext;
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (NoSuchPaddingException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (InvalidKeyException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (IllegalBlockSizeException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ } catch (BadPaddingException e) {
+ log.error("Error decrypting text", e);
+ throw new SeCurisException("Error decrypting text", e);
+ }
+ }
+
+ private byte[] getSalt() throws SeCurisException {
+ byte[] salt = new byte[20];
+ new SecureRandom().nextBytes(salt);
+ return salt;
+ }
+
+ private SecretKeySpec getSecretKey(byte[] salt, String pass) throws SeCurisException {
+ String passPhrase = pass.replace('a', 'ä');
+
+ try {
+ int iterations = 10000;
+
+ SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_FACTORY, PPROVIDER);
+ SecretKey tmp = factory.generateSecret(new PBEKeySpec(passPhrase.toCharArray(), salt, iterations, 128));
+ byte[] key = Arrays.copyOf(tmp.getEncoded(), 16);
+ SecretKeySpec spec = new SecretKeySpec(key, "AES");
+ return spec;
+
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Error generation secret key", e);
+ throw new SeCurisException("Error generation secret key", e);
+ } catch (InvalidKeySpecException e) {
+ log.error("Error generation secret key", e);
+ throw new SeCurisException("Error generation secret key", e);
+ } catch (NoSuchProviderException e) {
+ log.error("Error generation secret key", e);
+ throw new SeCurisException("Error generation secret key", e);
+ }
+ }
+}
diff --git a/src/main/java/net/curisit/securis/HWInfo.java b/src/main/java/net/curisit/securis/HWInfo.java
new file mode 100644
index 0000000..a0f9e65
--- /dev/null
+++ b/src/main/java/net/curisit/securis/HWInfo.java
@@ -0,0 +1,122 @@
+package net.curisit.securis;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Retrieve HW info
+ *
+ * @author cesarcalvo
+ *
+ */
+public class HWInfo {
+
+ private static final Logger log = LoggerFactory.getLogger(HWInfo.class);
+
+ public static String getOsName() {
+ return System.getProperty("os.name");
+ }
+
+ public static String getArch() {
+ return System.getProperty("os.arch");
+ }
+
+ public static int getNumCpus() {
+ return Runtime.getRuntime().availableProcessors();
+ }
+
+ /**
+ * Get MAC address
+ *
+ * @return
+ */
+ public static List<String> getMACAddress() throws SeCurisException {
+ List<byte[]> macs = new ArrayList<byte[]>();
+ try {
+ // Get MAC for ethX interface, where X is the lower number with MAC address != null
+ for (NetworkInterface network : Collections.list(NetworkInterface.getNetworkInterfaces())) {
+ if (!network.isLoopback() && !network.isVirtual() && !network.isPointToPoint() && network.getHardwareAddress() != null) {
+ macs.add(network.getHardwareAddress());
+ log.debug("Interface added {}, MAC: {}", network.getName(), network.getHardwareAddress());
+ logInterface(network);
+ }
+ }
+
+ // If not found interface ethX
+ if (macs.isEmpty()) {
+ NetworkInterface network = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
+ if (network.getHardwareAddress() != null)
+ macs.add(network.getHardwareAddress());
+ log.debug("Selected interface (Inet Address rule)");
+ logInterface(network);
+ }
+
+ // If not found interface, last attempt, we get any mac
+ if (macs.isEmpty()) {
+ for (NetworkInterface network : Collections.list(NetworkInterface.getNetworkInterfaces())) {
+ if (!network.isLoopback() && !network.isVirtual() && !network.isPointToPoint() && network.getHardwareAddress() != null) {
+ if (network.getHardwareAddress() != null)
+ macs.add(network.getHardwareAddress());
+ log.debug("Selected interface (Any with MAC rule)");
+ logInterface(network);
+ break;
+ }
+ }
+ }
+
+ if (macs.isEmpty())
+ throw new SeCurisException("Unable to get MAC address");
+
+ List<String> macAddresses = new ArrayList<String>();
+ for (byte[] mac : macs) {
+ macAddresses.add(printMacAddress(mac));
+ }
+ log.info("MAC Addresses: {}", macAddresses);
+ return macAddresses;
+
+ } catch (UnknownHostException e) {
+ throw new SeCurisException("Unable to get MAC address", e);
+ } catch (SocketException e) {
+ throw new SeCurisException("Unable to get MAC address", e);
+ } catch (Exception e) {
+ throw new SeCurisException("Unable to get MAC address", e);
+ }
+ }
+
+ /**
+ * Get microprocessor name
+ *
+ * @return
+ */
+ public static String getCPUName() throws SeCurisException {
+ return System.getenv("PROCESSOR_IDENTIFIER");
+ }
+
+ private static void logInterface(NetworkInterface network) {
+ log.debug("Interface name: {}", network.getName());
+ log.debug("Interface display name: {}", network.getDisplayName());
+ try {
+ log.debug("Interface mac: {}", printMacAddress(network.getHardwareAddress()));
+ } catch (SocketException e) {
+ // Silent
+ }
+ }
+
+ private static String printMacAddress(byte[] mac) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < mac.length; i++) {
+ sb.append(String.format("%s%02X", (i > 0) ? "-" : "", mac[i]));
+ }
+ return sb.toString();
+
+ }
+
+}
diff --git a/src/net/curisit/securis/License.java b/src/main/java/net/curisit/securis/License.java
similarity index 82%
rename from src/net/curisit/securis/License.java
rename to src/main/java/net/curisit/securis/License.java
index 94ad8dd..5b6e1e3 100644
--- a/src/net/curisit/securis/License.java
+++ b/src/main/java/net/curisit/securis/License.java
@@ -7,8 +7,12 @@
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class License {
+
+ private static final Logger log = LoggerFactory.getLogger(License.class);
public static void main(String[] args) {
CommandLine cmd = getCommandLine(args);
@@ -47,11 +51,12 @@
options.addOption("h", "help", false, "Show help.");
options.addOption(OptionBuilder.withArgName("req_file").withLongOpt("rfile").withDescription("Set request file for its generation or for license requesting.").hasArg(true).create('r'));
options.addOption(OptionBuilder.withArgName("url_license_server").withLongOpt("server").withDescription("License server url.").hasArg(true).create('s'));
- options.addOption(OptionBuilder.withArgName("lic_file").withLongOpt("license").withDescription("Validate lic file.").hasArg(true).create('l'));
+ options.addOption(OptionBuilder.withArgName("lic_file").withLongOpt("validate").withDescription("Validate lic file.").hasArg(true).create('l'));
options.addOption("g", "gen_request", false, "Generate request file. If --rfile parameter is missing then It is generated in current directory.");
options.addOption("c", "create", false, "Request a license file from server. --rfile and --server parameters are mandatory.");
options.addOption("t", "test_lc", false, "Test if License Server (LC) is available. --server parameter is mandatory.");
+ options.addOption(OptionBuilder.withArgName("lic_file").withLongOpt("sync").withDescription("Synchronize/renew the current license file. --server parameter is mandatory.").hasArg(true).create('y'));
return options;
}
diff --git a/src/main/java/net/curisit/securis/LicenseManager.java b/src/main/java/net/curisit/securis/LicenseManager.java
new file mode 100644
index 0000000..6d74838
--- /dev/null
+++ b/src/main/java/net/curisit/securis/LicenseManager.java
@@ -0,0 +1,47 @@
+package net.curisit.securis;
+
+import java.io.File;
+import java.io.IOException;
+
+import net.curisit.securis.beans.LicenseBean;
+import net.curisit.securis.beans.RequestBean;
+import net.curisit.securis.utils.JsonUtils;
+
+import org.apache.commons.io.FileUtils;
+
+/**
+ * Manage all licenses tasks, just like, validation, sync, requesting, ...
+ *
+ * @author roberto <roberto.sanchez@curisit.net>
+ */
+public class LicenseManager {
+
+ private static LicenseManager singleton = new LicenseManager();
+
+ private LicenseManager() {
+ }
+
+ public static LicenseManager getInstance() {
+ return singleton;
+ }
+
+ public LicenseBean validateLicense(File licFile, String appCode, String customerCode) throws SeCurisException {
+ LicenseBean licBean;
+ try {
+ licBean = JsonUtils.json2object(FileUtils.readFileToString(licFile), LicenseBean.class);
+ } catch (IOException e) {
+ throw new SeCurisException("Error validating license", e);
+ }
+ SignatureHelper.getInstance().validateSignature(licBean);
+ validateHW(licBean, appCode, customerCode);
+
+ return licBean;
+ }
+
+ private void validateHW(RequestBean reqBean, String appCode, String customerCode) throws SeCurisException {
+ RequestBean currentHW = ReqGenerator.getInstance().createRequest(appCode, customerCode);
+ if (!currentHW.match(reqBean))
+ throw new SeCurisException("Current System info mismatch the License System info: " + JsonUtils.toJSON(reqBean));
+ }
+
+}
diff --git a/src/net/curisit/securis/LicenseValidator.java b/src/main/java/net/curisit/securis/LicenseValidator.java
similarity index 100%
rename from src/net/curisit/securis/LicenseValidator.java
rename to src/main/java/net/curisit/securis/LicenseValidator.java
diff --git a/src/main/java/net/curisit/securis/ReqGenerator.java b/src/main/java/net/curisit/securis/ReqGenerator.java
new file mode 100644
index 0000000..665b54a
--- /dev/null
+++ b/src/main/java/net/curisit/securis/ReqGenerator.java
@@ -0,0 +1,59 @@
+package net.curisit.securis;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import net.curisit.securis.beans.RequestBean;
+import net.curisit.securis.utils.LicUtils;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ReqGenerator {
+
+ @SuppressWarnings("unused")
+ private static final Logger log = LoggerFactory.getLogger(ReqGenerator.class);
+
+ private static ReqGenerator singleton = new ReqGenerator();
+
+ private byte[] LOGO_SECRET;
+
+ private ReqGenerator() {
+ try {
+ LOGO_SECRET = "Logo ipsum s3cr3t test áíóú".getBytes("utf-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static ReqGenerator getInstance() {
+ return singleton;
+ }
+
+ public RequestBean createRequest(String appCode, String customerCode) throws SeCurisException {
+ RequestBean req = new RequestBean();
+
+ req.setAppCode(appCode);
+ req.setCustomerCode(customerCode);
+ req.setArch(HWInfo.getArch());
+ req.setCrcLogo(getCrcLogo());
+ req.setMacAddresses(HWInfo.getMACAddress());
+ req.setOsName(HWInfo.getOsName());
+
+ return req;
+ }
+
+ private String getCrcLogo() {
+ String logResource = "images/logo_customer.png";
+ InputStream is = getClass().getClassLoader().getResourceAsStream(logResource);
+ try {
+ String shaLogo = LicUtils.sha256(IOUtils.toByteArray(is), LOGO_SECRET);
+ return shaLogo;
+ } catch (IOException e) {
+ log.error("Customer logo was not found in classpath in " + logResource, e);
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/net/curisit/securis/SeCurisException.java b/src/main/java/net/curisit/securis/SeCurisException.java
new file mode 100644
index 0000000..5c99e68
--- /dev/null
+++ b/src/main/java/net/curisit/securis/SeCurisException.java
@@ -0,0 +1,17 @@
+package net.curisit.securis;
+
+public class SeCurisException extends Exception {
+
+ private static final long serialVersionUID = 5702956178417661458L;
+
+ public SeCurisException() {
+ }
+
+ public SeCurisException(String msg, Exception e) {
+ super(msg, e);
+ }
+
+ public SeCurisException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/main/java/net/curisit/securis/SignatureHelper.java b/src/main/java/net/curisit/securis/SignatureHelper.java
new file mode 100644
index 0000000..0d14483
--- /dev/null
+++ b/src/main/java/net/curisit/securis/SignatureHelper.java
@@ -0,0 +1,144 @@
+package net.curisit.securis;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+
+import net.curisit.securis.beans.LicenseBean;
+import net.curisit.securis.beans.RequestBean;
+import net.curisit.securis.utils.JsonUtils;
+import net.curisit.securis.utils.Params;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.net.util.Base64;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+//import net.curisit.common.ui.Dialogs;
+
+/**
+ * digital Signature utilities
+ *
+ * @author roberto <roberto.sanchez@curisit.net>
+ */
+public class SignatureHelper {
+
+ private static final Logger log = LoggerFactory.getLogger(SignatureHelper.class);
+ private static String AUX = "hEDhryRjs2QRE";
+
+ private static SignatureHelper singleton = new SignatureHelper();
+
+ private static final String DEFAULT_ALGORITHM = "RSA";
+ protected static final String SIGNATURE_GENERATION_ALGORITHM = "SHA256withRSA";
+
+ private SignatureHelper() {
+ }
+
+ public static SignatureHelper getInstance() {
+ return singleton;
+ }
+
+ protected void prepareSignature(Signature signature, LicenseBean licBean) throws SeCurisException {
+ try {
+ log.info("JSON: {}", JsonUtils.toJSON(licBean));
+ signature.update(JsonUtils.toJSON(licBean).getBytes("utf-8"));
+ signature.update(AUX.getBytes("utf-8"));
+ } catch (SignatureException | UnsupportedEncodingException e) {
+ throw new SeCurisException("Error generating or validating signature", e);
+ }
+ }
+
+ public void validateSignature(LicenseBean licBean) throws SeCurisException {
+ Signature signature;
+ try {
+ signature = Signature.getInstance(SIGNATURE_GENERATION_ALGORITHM);
+ signature.initVerify(generatePublicKey());
+
+ prepareSignature(signature, licBean);
+
+ if (signature.verify(Base64.decodeBase64(licBean.getSignature())))
+ return;
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Error validating license for " + licBean, e);
+ } catch (InvalidKeyException e) {
+ log.error("Error validating license for " + licBean, e);
+ } catch (InvalidKeySpecException e) {
+ log.error("Error validating license for " + licBean, e);
+ } catch (IOException e) {
+ log.error("Error validating license for " + licBean, e);
+ } catch (SignatureException e) {
+ log.error("Error validating license for " + licBean, e);
+ }
+ throw new SeCurisException("License could not be validated");
+
+ }
+
+ private PublicKey generatePublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
+ return generatePublicKey(new File(Params.get(Params.KEYS.PUBLIC_KEY_FILE, System.getenv("SECURIS_PUBLIC_KEY_FILE"))));
+ }
+
+ private PublicKey generatePublicKey(File publicKeyFile) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
+ String pubKeyBase64 = FileUtils.readFileToString(publicKeyFile);
+ int from = pubKeyBase64.indexOf('\n');
+ int to = pubKeyBase64.indexOf("-----END", from);
+ pubKeyBase64 = pubKeyBase64.substring(from, to);
+
+ KeyFactory keyFactory = KeyFactory.getInstance(DEFAULT_ALGORITHM);
+ X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(pubKeyBase64));
+ PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
+ log.info("Public key read sucessfully from file: {}", publicKeyFile.getAbsolutePath());
+ return publicKey;
+ }
+
+ protected PrivateKey generatePrivateKey(File privateKeyFile) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
+ String privKeyBase64 = FileUtils.readFileToString(privateKeyFile);
+ int from = privKeyBase64.indexOf('\n');
+ int to = privKeyBase64.indexOf("-----END", from);
+ privKeyBase64 = privKeyBase64.substring(from, to);
+
+ KeyFactory keyFactory = KeyFactory.getInstance(DEFAULT_ALGORITHM);
+ PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privKeyBase64));
+ PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
+
+ return privateKey;
+ }
+
+ private KeyPair generateKeyPair(File privateKeyFile, File publicKeyFile) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
+
+ PublicKey publicKey = generatePublicKey(publicKeyFile);
+ PrivateKey privateKey = generatePrivateKey(privateKeyFile);
+
+ KeyPair kp = new KeyPair(publicKey, privateKey);
+ return kp;
+ }
+
+ public static void main(String[] args) throws SeCurisException {
+ // org.apache.log4j.Logger.getRootLogger().addAppender(new Appender);
+ DOMConfigurator.configure("/Users/cproberto/Documents/wsCurisIT/SeCurisClient/src/main/resources/log4j.xml");
+ RequestBean req = ReqGenerator.getInstance().createRequest("CI", "Roberto");
+
+ LicenseGenerator lg = LicenseGenerator.getInstance();
+ LicenseBean lic = lg.generateLicense(req, 12, new Date(new Date().getTime() + 24 * 3600 * 1000 * 10));
+ System.out.println(JsonUtils.toJSON(lic, true));
+ System.out.println(JsonUtils.toJSON(lic));
+ }
+
+ static {
+ byte[] s = new byte[]
+ { 64, -31, -81, 36, 99, -77, 100, 17, 16, -119, 31, 72, 123, -88, -32, 51, 39, -96, -35, 116, -65, 8, 41, -119, -108, -34, 41, 19, 26, -102, -16, -120, -96, 1, -5, -26, -13, 61, -121, 94, 59, 54, 110, 110, -55, 127, -106 };
+ AUX = Base64.encodeBase64String(s);
+ }
+}
diff --git a/src/main/java/net/curisit/securis/beans/LicenseBean.java b/src/main/java/net/curisit/securis/beans/LicenseBean.java
new file mode 100644
index 0000000..691241d
--- /dev/null
+++ b/src/main/java/net/curisit/securis/beans/LicenseBean.java
@@ -0,0 +1,64 @@
+package net.curisit.securis.beans;
+
+import java.util.Date;
+
+import org.codehaus.jackson.annotate.JsonPropertyOrder;
+
+@JsonPropertyOrder(
+ { "maxUsers", "expirationDate", "appCode", "arch", "osName", "customerCode", "macAddresses", "crclogo" })
+public class LicenseBean extends RequestBean {
+ private int maxUsers;
+ private Date expirationDate;
+ /**
+ * Signature is stored in Base64 code
+ */
+ private String signature;
+
+ public LicenseBean() {
+ }
+
+ public LicenseBean(RequestBean req) {
+ super.setAppCode(req.getAppCode());
+ super.setArch(req.getArch());
+ super.setCrcLogo(req.getCrcLogo());
+ super.setCustomerCode(req.getCustomerCode());
+ super.setMacAddresses(req.getMacAddresses());
+ super.setOsName(req.getOsName());
+ }
+
+ public String getSignature() {
+ return signature;
+ }
+
+ public void setSignature(String signature) {
+ this.signature = signature;
+ }
+
+ public Date getExpirationDate() {
+ return expirationDate;
+ }
+
+ public void setExpirationDate(Date expirationDate) {
+ this.expirationDate = expirationDate;
+ }
+
+ public int getMaxUsers() {
+ return maxUsers;
+ }
+
+ public void setMaxUsers(int maxUsers) {
+ this.maxUsers = maxUsers;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof LicenseBean))
+ return false;
+ LicenseBean rb = (LicenseBean) obj;
+ boolean result = (maxUsers == rb.maxUsers);
+ result = result && ((expirationDate == null && rb.expirationDate == null) || (expirationDate != null && expirationDate.equals(rb.expirationDate)));
+ result = result && ((signature == null && rb.signature == null) || (signature != null && signature.equals(rb.signature)));
+
+ return result && super.equals(obj);
+ }
+}
diff --git a/src/main/java/net/curisit/securis/beans/RequestBean.java b/src/main/java/net/curisit/securis/beans/RequestBean.java
new file mode 100644
index 0000000..cfb20f0
--- /dev/null
+++ b/src/main/java/net/curisit/securis/beans/RequestBean.java
@@ -0,0 +1,97 @@
+package net.curisit.securis.beans;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+
+@JsonAutoDetect
+public class RequestBean {
+ private String customerCode;
+ private String crcLogo;
+ private String appCode;
+ private List<String> macAddresses;
+ private String osName;
+ private String arch;
+
+ public String getCustomerCode() {
+ return customerCode;
+ }
+
+ public void setCustomerCode(String customerCode) {
+ this.customerCode = customerCode;
+ }
+
+ public String getCrcLogo() {
+ return crcLogo;
+ }
+
+ public void setCrcLogo(String crcLogo) {
+ this.crcLogo = crcLogo;
+ }
+
+ public String getAppCode() {
+ return appCode;
+ }
+
+ public void setAppCode(String appCode) {
+ this.appCode = appCode;
+ }
+
+ public List<String> getMacAddresses() {
+ return macAddresses;
+ }
+
+ public void setMacAddresses(List<String> macAddresses) {
+ this.macAddresses = macAddresses;
+ }
+
+ public String getOsName() {
+ return osName;
+ }
+
+ public void setOsName(String osName) {
+ this.osName = osName;
+ }
+
+ public String getArch() {
+ return arch;
+ }
+
+ public void setArch(String arch) {
+ this.arch = arch;
+ }
+
+ public boolean match(RequestBean rb) {
+
+ boolean result = appCode != null && appCode.equals(rb.appCode);
+ result = result && (arch != null && arch.equals(rb.arch));
+ result = result && (crcLogo != null && crcLogo.equals(rb.crcLogo));
+ result = result && (customerCode != null && customerCode.equals(rb.customerCode));
+ result = result && (osName != null && osName.equals(rb.osName));
+ result = result && (macAddresses != null && rb.macAddresses != null) && anyMacIsIncluded(rb.getMacAddresses());
+
+ return result;
+ }
+
+ private boolean anyMacIsIncluded(List<String> macList) {
+ for (String mac : macList) {
+ if (macAddresses.contains(mac))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof RequestBean))
+ return false;
+ RequestBean rb = (RequestBean) obj;
+ boolean result = (rb.appCode == null && appCode == null) || (appCode != null && appCode.equals(rb.appCode));
+ result = result && ((rb.arch == null && arch == null) || (arch != null && arch.equals(rb.arch)));
+ result = result && ((rb.crcLogo == null && crcLogo == null) || (crcLogo != null && crcLogo.equals(rb.crcLogo)));
+ result = result && ((rb.customerCode == null && customerCode == null) || (customerCode != null && customerCode.equals(rb.customerCode)));
+ result = result && ((rb.osName == null && osName == null) || (osName != null && osName.equals(rb.osName)));
+ result = result && ((rb.macAddresses == null && macAddresses == null) || (macAddresses != null && macAddresses.equals(rb.macAddresses)));
+ return result;
+ }
+}
diff --git a/src/main/java/net/curisit/securis/utils/JsonUtils.java b/src/main/java/net/curisit/securis/utils/JsonUtils.java
new file mode 100644
index 0000000..397a0e0
--- /dev/null
+++ b/src/main/java/net/curisit/securis/utils/JsonUtils.java
@@ -0,0 +1,205 @@
+package net.curisit.securis.utils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import net.curisit.securis.SeCurisException;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.codehaus.jackson.type.TypeReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper method to perform JSON tasks
+ *
+ * @author cproberto
+ */
+public class JsonUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(JsonUtils.class);
+
+ final private static ObjectMapper MAPPER = new ObjectMapper();
+
+ static {
+ MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
+ MAPPER.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
+ MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+ MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+ MAPPER.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
+ MAPPER.configure(SerializationConfig.Feature.INDENT_OUTPUT, false);
+ MAPPER.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, true);
+ MAPPER.configure(SerializationConfig.Feature.WRITE_ENUMS_USING_TO_STRING, true);
+
+ }
+
+ /**
+ * Convert an object in the type pass as parameter, avoiding to use casting in code.
+ *
+ * @param value
+ * @param type
+ * @return
+ */
+ public static <T> T value(Object value, Class<T> type) {
+
+ return (T) value;
+ }
+
+ public static <T> T parseJSON(String json, Class<T> type) throws SeCurisException {
+ try {
+ if (json == null)
+ return null;
+ return MAPPER.readValue(json, type);
+ } catch (JsonParseException e) {
+ log.error("Error parsing JSON string to obejct: {}", json, e);
+ if (json.length() > 60)
+ json = json.substring(0, 50) + "...";
+ throw new SeCurisException("Error parsing JSON string to object: " + json, e);
+ } catch (IOException e) {
+ log.error("Error parsing JSON string to object: {}", json, e);
+ if (json.length() > 60)
+ json = json.substring(0, 50) + "...";
+ throw new SeCurisException("Error parsing JSON string to object: " + json, e);
+ }
+ }
+
+ /**
+ * Create a JSON string from a object compatible or annotated with Jackson, i.e: <code>
+ * {"f1":2345,"f2":"Test de valor"}
+ *
+ * @param obj
+ * @return JSON string representation from object
+ */
+ public static String toJSON(Object obj) throws SeCurisException {
+ // and could also do other configuration...
+ try {
+ if (obj == null)
+ return null;
+ return MAPPER.writeValueAsString(obj);
+ } catch (JsonProcessingException e) {
+ log.error("Error formating JSON from object: {}", obj, e);
+ throw new SeCurisException("Error formating JSON from object: " + obj, e);
+ } catch (IOException e) {
+ log.error("Error formating JSON from object: {}", obj, e);
+ throw new SeCurisException("Error formating JSON from object: " + obj, e);
+ }
+ }
+
+ /**
+ * Create a JSON string from a object compatible or annotated with Jackson, i.e: <code>
+ * {"f1":2345,"f2":"Test de valor"}
+ *
+ * @param obj
+ * @return JSON string representation from object
+ */
+ public static String toJSON(Object obj, boolean pretty) throws SeCurisException {
+ // and could also do other configuration...
+ try {
+ if (obj == null)
+ return null;
+ MAPPER.enable(SerializationConfig.Feature.INDENT_OUTPUT);
+ String json = MAPPER.writeValueAsString(obj);
+ MAPPER.disable(SerializationConfig.Feature.INDENT_OUTPUT);
+ return json;
+ } catch (JsonProcessingException e) {
+ log.error("Error formating JSON from object: {}", obj, e);
+ throw new SeCurisException("Error formating JSON from object: " + obj, e);
+ } catch (IOException e) {
+ log.error("Error formating JSON from object: {}", obj, e);
+ throw new SeCurisException("Error formating JSON from object: " + obj, e);
+ }
+ }
+
+ /**
+ * Create a Map from a json string, i.e: <code>
+ * {"f1":2345,"f2":"Test de valor"}
+ * </code>
+ *
+ * @param json
+ * String with json format
+ * @return
+ */
+ public static Map<String, Object> json2map(String json) throws JsonParseException {
+
+ try {
+ if (json == null)
+ return null;
+ return MAPPER.readValue(json, Map.class);
+ } catch (JsonParseException e) {
+ log.error("Error parsing JSON string to map: {}", json, e);
+ throw e;
+ } catch (IOException e) {
+ log.error("Error parsing JSON string to map: {}", json, e);
+ }
+ return null;
+ }
+
+ /**
+ * Create a JSON strin from a Map object, i.e: <code>
+ * {"f1":2345,"f2":"Test de valor"}
+ *
+ * @param map
+ * @return
+ */
+ public static String map2json(Map<String, Object> map) {
+ // and could also do other configuration...
+ try {
+ if (map == null)
+ return null;
+ return MAPPER.writeValueAsString(map);
+ } catch (JsonProcessingException e) {
+ log.error("Error formating JSON from map: {}", map, e);
+ } catch (IOException e) {
+ log.error("Error formating JSON from map: {}", map, e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a Map from a json string, i.e: <code>
+ * [{"f1":2345}, {"f2":"Test de valor"}]
+ * </code>
+ *
+ * @param json
+ * String with json format
+ * @return
+ */
+ public static List<Object> json2list(String json) {
+ try {
+ return MAPPER.readValue(json, List.class);
+ } catch (JsonParseException e) {
+ log.error("Error converting JSON string to object {}", json, e);
+ } catch (IOException e) {
+ log.error("Error converting JSON string to object {}", json, e);
+ }
+ return null;
+ }
+
+ public static <T> T json2object(String json, Class<T> classObject) throws SeCurisException {
+ try {
+ return MAPPER.readValue(json, classObject);
+ } catch (JsonParseException e) {
+ throw new SeCurisException("Error converting JSON to object", e);
+ } catch (IOException e) {
+ throw new SeCurisException("Error converting JSON to object", e);
+ }
+ }
+
+ public static <T> T json2object(String json, TypeReference<T> typeReference) throws SeCurisException {
+ try {
+ return MAPPER.readValue(json, typeReference);
+ } catch (JsonParseException e) {
+ throw new SeCurisException("Error converting JSON to object", e);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new SeCurisException("Error converting JSON to object", e);
+ }
+ }
+
+}
diff --git a/src/net/curisit/securis/utils/LicUtils.java b/src/main/java/net/curisit/securis/utils/LicUtils.java
similarity index 100%
rename from src/net/curisit/securis/utils/LicUtils.java
rename to src/main/java/net/curisit/securis/utils/LicUtils.java
diff --git a/src/main/java/net/curisit/securis/utils/Params.java b/src/main/java/net/curisit/securis/utils/Params.java
new file mode 100644
index 0000000..56260c3
--- /dev/null
+++ b/src/main/java/net/curisit/securis/utils/Params.java
@@ -0,0 +1,191 @@
+package net.curisit.securis.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class that loads and serves global config parameters.
+ *
+ * @author rsanchez
+ */
+public class Params {
+
+ private static Logger log = LoggerFactory.getLogger(Params.class);
+
+ /**
+ * Key used to store config file resource location. In a web application, can be set as initial parameter in a servlet loaded on startup
+ */
+ public static final String KEY_CONFIG_FILE = "/securis-client.properties";
+
+ private static Properties params = null;
+
+ static {
+ try {
+ loadParameters(KEY_CONFIG_FILE);
+ } catch (IOException e) {
+ log.error("Config file {} was not found in classpath", KEY_CONFIG_FILE);
+ }
+ }
+
+ /**
+ * Loads application global parameters from a classpath resource
+ *
+ * @param resource
+ * : Resource location in classpath, i.e: "/resource/cp-securis.conf"
+ * @throws IOException
+ */
+ public static void loadParameters(String resource) throws IOException {
+
+ log.info("Loading params from " + resource);
+ InputStream fileis = Params.class.getResourceAsStream(resource);
+
+ params = new Properties();
+ try {
+
+ params.load(fileis);
+ log.info("Params loaded OK");
+ } catch (IOException e) {
+ log.error("Error loading config file: " + e);
+ params = null;
+ throw e;
+ }
+
+ }
+
+ public static String getByDomain(String domain, String paramname) {
+ return getByDomain(domain, paramname, null);
+ }
+
+ public static String getByPrefix(String prefix, String paramname) {
+ return get(prefix + "." + paramname, get(paramname));
+ }
+
+ public static String getByPrefix(String prefix, String paramname, String defaultVal) {
+ return get(prefix + "." + paramname, get(paramname, defaultVal));
+ }
+
+ public static String getByDomain(String domain, String paramname, String defaultval) {
+ return get(paramname + "." + domain, defaultval);
+ }
+
+ public static int getIntByDomain(String domain, String paramname) {
+ return getInt(paramname + "." + domain, getInt(paramname));
+ }
+
+ public static int getIntByDomain(String domain, String paramname, int defaultval) {
+ return getInt(paramname + "." + domain, defaultval);
+ }
+
+ /**
+ * Gets a List with all values of properties that begins with <code>prefix</code> It reads sequentially. For example:
+ *
+ * <pre>
+ * securis.sort.comparator.0: net.cp.securis.comparators.ComparePttidVsPtn
+ * securis.sort.comparator.1: net.cp.securis.comparators.CompareFrequency
+ * securis.sort.comparator.2: net.cp.securis.comparators.CompareOutgoingVsIncomming
+ * securis.sort.comparator.3: net.cp.securis.comparators.CompareDuration
+ * securis.sort.comparator.4: net.cp.securis.comparators.CompareCallVsSms
+ * </pre>
+ *
+ * That config (for prefix: "securis.sort.comparator" ) will return a List<String> with values:
+ *
+ * <pre>
+ * "net.cp.securis.comparators.ComparePttidVsPtn",
+ * "net.cp.securis.comparators.CompareFrequency",
+ * "net.cp.securis.comparators.CompareOutgoingVsIncomming",
+ * "net.cp.securis.comparators.CompareDuration",
+ * "net.cp.securis.comparators.CompareCallVsSms"
+ * </pre>
+ *
+ * Note: If there is a gap between suffixes process will stop, that is, only will be returned properties found before gap.
+ *
+ * @param prefix
+ * @return
+ */
+ public static List<String> getListByPrefix(String prefix) {
+ List<String> list = new ArrayList<String>();
+
+ String tpl = prefix + ".{0}";
+
+ int i = 0;
+ String value = get(MessageFormat.format(tpl, i++));
+ while (value != null) {
+ list.add(value);
+ value = get(MessageFormat.format(tpl, i++));
+ }
+
+ return list;
+ }
+
+ /**
+ * Gets param value in config file or environment variables
+ *
+ * @param paramname
+ * Global parameter's name
+ * @return Value of paramname or null if paramname is not found neither in config file nor in environment variables
+ */
+ public static String get(String paramname) {
+
+ assert (params != null) : "Parameters have not been loaded. Call method loadParameters(resource) before use Params.";
+
+ String value = params.getProperty(paramname);
+ if (value == null)
+ value = System.getenv(paramname);
+ return value;
+ }
+
+ /**
+ * Gets param value from config file or environment variables
+ *
+ * @param paramname
+ * Global parameter's name
+ * @param defaultval
+ * @return Value of paramname or defaultval if paramname is not found
+ */
+ public static String get(String paramname, String defaultval) {
+ String value = get(paramname);
+ return (value == null ? defaultval : value);
+ }
+
+ /**
+ * Gets param value in config file or environment variables
+ *
+ * @param paramname
+ * Global parameter's name
+ * @return Integer value of paramname or -1 if paramname is not found neither in config file nor in environment variables
+ */
+ public static int getInt(String paramname) {
+ String value = get(paramname);
+ return (value == null ? -1 : Integer.parseInt(value));
+ }
+
+ /**
+ * Gets param value from config file or environment variables
+ *
+ * @param paramname
+ * Global parameter's name
+ * @param defaultval
+ * @return Integer value of paramname or defaultval if paramname is not found
+ */
+ public static int getInt(String paramname, int defaultval) {
+ String value = get(paramname);
+ return (value == null ? defaultval : Integer.parseInt(value));
+ }
+
+ public static class KEYS {
+
+ /**
+ * Public key file, Usually in "PEM" format
+ */
+ public static final String PUBLIC_KEY_FILE = "public.key.file";
+
+ }
+
+}
diff --git a/src/main/resources/images/logo_customer.png b/src/main/resources/images/logo_customer.png
new file mode 100644
index 0000000..470bd7d
--- /dev/null
+++ b/src/main/resources/images/logo_customer.png
Binary files differ
diff --git a/src/main/resources/log4j.xml b/src/main/resources/log4j.xml
new file mode 100644
index 0000000..6298f36
--- /dev/null
+++ b/src/main/resources/log4j.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+ <appender name="console" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
+ </layout>
+ </appender>
+
+ <logger name="net.curisit">
+ <level value="INFO"/>
+ </logger>
+
+ <logger name="sandbox">
+ <level value="DEBUG"/>
+ </logger>
+
+ <root>
+ <priority value ="INFO" />
+ <appender-ref ref="console" />
+ </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/src/main/resources/securis-client.properties b/src/main/resources/securis-client.properties
new file mode 100644
index 0000000..a6a2ed3
--- /dev/null
+++ b/src/main/resources/securis-client.properties
@@ -0,0 +1 @@
+public.key.file = /Users/cproberto/Documents/wsPython/doky/tests/mykey.pub
\ No newline at end of file
diff --git a/src/net/curisit/securis/ReqGenerator.java b/src/net/curisit/securis/ReqGenerator.java
deleted file mode 100644
index 9a97b60..0000000
--- a/src/net/curisit/securis/ReqGenerator.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.curisit.securis;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ReqGenerator {
-
- @SuppressWarnings("unused")
- private static final Logger log = LoggerFactory.getLogger(ReqGenerator.class);
-
-}
diff --git a/src/patch/java/net/curisit/securis/LicenseGenerator.java b/src/patch/java/net/curisit/securis/LicenseGenerator.java
new file mode 100644
index 0000000..5977944
--- /dev/null
+++ b/src/patch/java/net/curisit/securis/LicenseGenerator.java
@@ -0,0 +1,106 @@
+package net.curisit.securis;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.text.MessageFormat;
+import java.util.Date;
+
+import net.curisit.securis.beans.LicenseBean;
+import net.curisit.securis.beans.RequestBean;
+
+import org.apache.commons.net.util.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * License generator and signer
+ *
+ * @author roberto <roberto.sanchez@curisit.net>
+ */
+public class LicenseGenerator {
+
+ @SuppressWarnings("unused")
+ private static final Logger log = LoggerFactory.getLogger(LicenseGenerator.class);
+
+ private static LicenseGenerator singleton = new LicenseGenerator();
+
+ private LicenseGenerator() {
+ }
+
+ public static LicenseGenerator getInstance() {
+ return singleton;
+ }
+
+ /**
+ * Generate a license bean with the specified data
+ *
+ * @param hw
+ * @param customerCode
+ * - e.g: "BP"
+ * @param maxInstances
+ * @param maxUsers
+ * @param maxTimeThreshold
+ * Max time between synchronizations expressed in days
+ * @return
+ * @throws SeCurisException
+ */
+ public LicenseBean generateLicense(RequestBean req, int maxUsers, Date expirationDate) throws SeCurisException {
+ log.info(MessageFormat.format("Generating license: MAC: {0}, Customer code: {1}, AppCode: {2}", req.getMacAddresses(), req.getCustomerCode(), req.getAppCode()));
+ LicenseBean license = new LicenseBean(req);
+ license.setExpirationDate(expirationDate);
+ license.setMaxUsers(maxUsers);
+ sign(license);
+
+ return license;
+ }
+
+ /**
+ * TODO: This method should be removed from client code.
+ *
+ * @param licBean
+ * @return
+ * @throws NoSuchAlgorithmException
+ * @throws IOException
+ * @throws InvalidKeySpecException
+ * @throws InvalidKeyException
+ * @throws SignatureException
+ */
+ public String sign(LicenseBean licBean) throws SeCurisException {
+ SignatureHelper sh = SignatureHelper.getInstance();
+
+ Signature signature;
+ try {
+ signature = Signature.getInstance(SignatureHelper.SIGNATURE_GENERATION_ALGORITHM);
+ signature.initSign(sh.generatePrivateKey(new File("/Users/cproberto/Documents/wsPython/doky/tests/privkey.pkcs8")));
+
+ sh.prepareSignature(signature, licBean);
+
+ byte[] signatureData = signature.sign();
+ licBean.setSignature(Base64.encodeBase64String(signatureData));
+ return licBean.getSignature();
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Error signing license for " + licBean, e);
+ } catch (InvalidKeyException e) {
+ log.error("Error signing license for " + licBean, e);
+ } catch (InvalidKeySpecException e) {
+ log.error("Error signing license for " + licBean, e);
+ } catch (IOException e) {
+ log.error("Error signing license for " + licBean, e);
+ } catch (SignatureException e) {
+ log.error("Error signing license for " + licBean, e);
+ }
+ throw new SeCurisException("License could not be generated");
+ }
+
+ public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, InvalidKeyException, SignatureException {
+
+ System.out.print("os.arch: " + System.getProperty("os.arch") + " " + System.getProperty("os.name"));
+
+ }
+}
--
Gitblit v1.3.2