From 8ffcc4f18ff5c402e2c9c5461944f65a01de0cfc Mon Sep 17 00:00:00 2001 From: Areek Zillur Date: Thu, 2 Oct 2014 01:57:47 -0400 Subject: [PATCH 1/2] maven fix for running license verification tests Original commit: elastic/x-pack-elasticsearch@650adfadc8319f801adcdaa9491ec2662acbd0b1 --- pom.xml | 2 ++ .../license/licensor/LicenseVerificationToolTests.java | 1 - .../elasticsearch/license/manager/LicenseVerificationTests.java | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a2418e3ec75..70de30e5f29 100644 --- a/pom.xml +++ b/pom.xml @@ -108,6 +108,8 @@ maven-surefire-plugin 2.16 + 1 + false **/*Tests.java diff --git a/src/test/java/org/elasticsearch/license/licensor/LicenseVerificationToolTests.java b/src/test/java/org/elasticsearch/license/licensor/LicenseVerificationToolTests.java index 4ae012be99f..ce2460e5182 100644 --- a/src/test/java/org/elasticsearch/license/licensor/LicenseVerificationToolTests.java +++ b/src/test/java/org/elasticsearch/license/licensor/LicenseVerificationToolTests.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; -@Ignore("Enable once maven is setup properly; now it throws invalid signature error for all the tests when the tests always pass in intellij") public class LicenseVerificationToolTests { private static String pubKeyPath = null; diff --git a/src/test/java/org/elasticsearch/license/manager/LicenseVerificationTests.java b/src/test/java/org/elasticsearch/license/manager/LicenseVerificationTests.java index 0807076d663..12f53e849f3 100644 --- a/src/test/java/org/elasticsearch/license/manager/LicenseVerificationTests.java +++ b/src/test/java/org/elasticsearch/license/manager/LicenseVerificationTests.java @@ -27,7 +27,6 @@ import static org.elasticsearch.license.core.ESLicenses.FeatureType; import static org.elasticsearch.license.core.LicenseUtils.readLicensesFromString; import static org.junit.Assert.*; -@Ignore("Enable once maven is setup properly; now it throws invalid signature error for all the tests when the tests always pass in intellij") public class LicenseVerificationTests { private static String pubKeyPath = null; From 1da4b89311b4c7782d11139f175a8a11e2377665 Mon Sep 17 00:00:00 2001 From: Areek Zillur Date: Tue, 7 Oct 2014 10:59:39 -0400 Subject: [PATCH 2/2] minor fixes and improvements; incorporated feedback Original commit: elastic/x-pack-elasticsearch@ed4bff2ce4c324a77363b2f9d98c204da392958d --- README.md | 46 ++++++++--- sample/gen_license.json | 13 ---- .../license/core/LicenseBuilders.java | 14 ++-- .../license/core/LicenseUtils.java | 15 ++-- .../license/licensor/ESLicenseSigner.java | 29 +++---- .../licensor/tools/KeyPairGeneratorTool.java | 22 ++---- .../licensor/tools/LicenseGeneratorTool.java | 15 +--- .../tools/LicenseVerificationTool.java | 77 ++++++++++--------- .../license/manager/ESLicenseManager.java | 21 +++-- .../elasticsearch/license/manager/Utils.java | 2 +- .../licensor/LicenseGenerationTests.java | 31 ++------ .../LicenseVerificationToolTests.java | 23 ++---- .../manager/LicenseVerificationTests.java | 30 +++----- 13 files changed, 144 insertions(+), 194 deletions(-) delete mode 100644 sample/gen_license.json diff --git a/README.md b/README.md index 9e198ca150c..f3ac2dadeda 100644 --- a/README.md +++ b/README.md @@ -13,38 +13,37 @@ Generates a 2048-bit RSA public/private key pair to be used for license generati **Note:** Errors if provided file paths for public/private already exists -**Output** - public/private key in the location provided with the provided key password +**Output** - public/private key in the location provided **Options:** `--publicKeyPath` - path to store the public key `--privateKeyPath` - path to store the private key -`--keyPass` - password for the key pair **Example Usage:** ```bash -$ bin/key-pair-generator --publicKeyPath ~/.es_temp_license/pub.key --privateKeyPath ~/.es_temp_license/pri.key --keyPass ab +$ bin/key-pair-generator --publicKeyPath ~/.es_temp_license/pub.key --privateKeyPath ~/.es_temp_license/pri.key ``` -Outputs the public key to `~/.es_temp_license/pub.key`, private key to `~/.es_temp_license/pri.key` securing the key pair with the provided `--keyPass` of `ab` +Outputs the public key to `~/.es_temp_license/pub.key`, private key to `~/.es_temp_license/pri.key` ### bin/license-generator Generates a signed license given a licensing spec and keyPair location **Note:** a `license spec` (see format below) can be provided in two ways, using `--license` allows for passing the spec as a string using `--licenseFile` allows passing in a file that has the license spec -**Output** - a signed license based on the provided `license spec`, private/public key location and password +**Output** - a signed license based on the provided `license spec`, private/public key location **Options:** `--license` - license spec as a string (optional when `--licenseFile` is provided) `--licenseFile` - path to a license spec file (optional when `--license` is provided) `--publicKeyPath` - path to retrieve the public key `--privateKeyPath` - path to retrieve the private key -`--keyPass` - password for the key pair provided **License Spec format:** ``` { "licenses": [ { + "uid": STRING (optional, if not provided a random UUID is generated) "type": STRING (“trial” | “internal” | “subscription”), "subscription_type": STRING (“none” | “gold” | “silver” | “platinum”), "issued_to": STRING, @@ -83,7 +82,7 @@ $ cat license_spec.json # generate a signed license according to license_spec.json using the private/public keypair -$ bin/license-generator --publicKeyPath ~/.es_temp_license/pub.key --privateKeyPath ~/.es_temp_license/pri.key --keyPass ab --licenseFile license_spec.json > gen_license.json +$ bin/license-generator --publicKeyPath ~/.es_temp_license/pub.key --privateKeyPath ~/.es_temp_license/pri.key --licenseFile license_spec.json > gen_license.json # generated license for license_spec.json @@ -117,14 +116,41 @@ One licenses that only retains effective sub-licenses for all the licenses provi **Options:** `--licensesFiles` - a set of **generated** licenses files separated by `:` +`--licenses` - a **generated** licenses as string (multiple licenses could be inputted by repeating the parameter) `--publicKeyPath` - path to retrieve the public key -`--keyPass` - password for the key pair provided **Example Usage:** -``` +```bash # the output will be the same as the content of gen_license.json (as all the licenses are valid and not expired) # in order to merge multiple licenses file use --licensesFiles file1.json:file2.json -$ bin/verify-license --publicKeyPath ~/.es_temp_license/pub.key --keyPass ab --licensesFiles gen_license.json +$ bin/verify-license --publicKeyPath ~/.es_temp_license/pub.key --licensesFiles gen_license.json + +# example using verify-license with multiple licenses json as string +$ bin/verify-license --publicKeyPath ~/.es_temp_license/pub.key --licenses `cat generated_license1.json` --licenses `cat generated_license2.json` ``` + +## Workflow + +A public/private key pair has to be generated before license generation +```bash + +# store public/private key pair to PUBLIC_KEY_FILE_PATH and PRIVATE_KEY_FILE_PATH respectively +$ bin/key-pair-generator --publicKeyPath PUBLIC_KEY_FILE_PATH --privateKeyPath PRIVATE_KEY_FILE_PATH + +``` +### License Generation +```bash + +# generate a license for a requested feature for a customer with a LICENSE_SPEC (format shown above) +$ bin/license-generator --publicKeyPath PUBLIC_KEY_FILE_PATH --privateKeyPath PRIVATE_KEY_FILE_PATH --license LICENSE_SPEC > GENERATED_LICENSE + +# check any existing valid licenses already issued to the customer from the data store; grab the last generated license file for the customer +# as EXISTING_LICENSE + +# use verify-license to generate en EFFECTIVE_LICENSE for the customer for distribution +$ bin/verify-license --publicKeyPath PUBLIC_KEY_FILE_PATH --privateKeyPath PRIVATE_KEY_FILE_PATH --licenses GENERATED_LICENSE_STRING --licenses EXISTING_LICENSE_STRING > EFFECTIVE_LICENSE + +``` + diff --git a/sample/gen_license.json b/sample/gen_license.json deleted file mode 100644 index 0e3058826bc..00000000000 --- a/sample/gen_license.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "licenses" : [ { - "uid" : "d8bcf9e8-bcb0-4f72-81ca-8a7537a436c5", - "type" : "internal", - "subscription_type" : "none", - "issued_to" : "issuedTo", - "issue_date" : "2014-09-29", - "expiry_date" : "2015-08-29", - "feature" : "shield", - "max_nodes" : 1, - "signature" : "naPgicfKM2+IJ0AoYgAAAG0AAAAAVGdIQ01qZUtCeEZNbS8wcTF4RU5mYUpiY01hdFlQNEVkdFJhYitoZndrSTI5eVZrY3ZRZ3lYU0s1QWdYb0Y5d1dBQmRUK01leE1aR0RUOHhoRVVhVUE9PaztAAVzcgAxbmV0Lm5pY2hvbGFzd2lsbGlhbXMuamF2YS5saWNlbnNpbmcuU2lnbmVkTGljZW5zZYqE/59+smqEAgACWwAObGljZW5zZUNvbnRlbnR0AAJbQlsAEHNpZ25hdHVyZUNvbnRlbnRxAH4AAXhwdXIAAltCrPMX+AYIVOACAAB4cAAAAMCsH5r77/8FtWY+JxKd9MiBTYQLcXgmXMm+Y83VaNwmlr1lASJ2yf7rWojiuHTWemtUNtOZcXeSrLfs/oKwBzXIfvEZV8X/vPCWnpi7VtU4Hp+OZUFO4c0NQ1PnVdDk1uns16Dqe99/ota3FSvdFrmlzkz2E+2bbx0fwWbKnGDXFXy6eE7OISRJdCqa8gljMo9PA1+RI7MFQ8bSzs9up0cEkSuPzgtafFW5zfyn2vpoPZTxDpJslTBk7S3mdchE0eJ1cQB+AAMAAAEAdikZHpJVMxWMxNsksYnNOD7F+15SK3MCtUWJnQdhYCuVHdKQUE3YxWv59QQuDmKuLbnvi0DsuPGlq3hEx0AXmbpaBOhkwTv3DKZH7V6C0YmXj7RLZobaDTtGY2pwV6Qf5+teq5dV493a1k6YGFiwUoERuWQxqmA36naLdVo2diCSh8QmZ4ihKnhqxwswh2TlnCVuaNN3E7HuGeE0wYgFEfgISJOFlEOnLOItRlrQOTzCq+mhASKbANxx/Z42eMGrgs+GJsxYQZfnBh8K3NQFQk2SjWR1sEgqUPXC+0Z7ungzkkwoSBbrdJfRPKbqXFDthWI1DY9SSZnTbwpUC2XA6Q==" - } ] -} \ No newline at end of file diff --git a/src/main/java/org/elasticsearch/license/core/LicenseBuilders.java b/src/main/java/org/elasticsearch/license/core/LicenseBuilders.java index 1799e8e883e..091169b4046 100644 --- a/src/main/java/org/elasticsearch/license/core/LicenseBuilders.java +++ b/src/main/java/org/elasticsearch/license/core/LicenseBuilders.java @@ -50,7 +50,7 @@ public class LicenseBuilders { } public static class LicensesBuilder { - private Map licenseMap; + private Map licenseMap = new HashMap<>(); public LicensesBuilder() { } @@ -60,11 +60,15 @@ public class LicenseBuilders { } public LicensesBuilder license(ESLicense license) { - initLicenses(); putIfAppropriate(license); return this; } + public LicensesBuilder licenseAsIs(ESLicense license) { + licenseMap.put(license.feature(), license); + return this; + } + public LicensesBuilder licenses(Collection licenses) { for (ESLicense esLicense : licenses) { license(esLicense); @@ -100,12 +104,6 @@ public class LicenseBuilders { }; } - private void initLicenses() { - if (licenseMap == null) { - licenseMap = new HashMap<>(); - } - } - /** * Add a {@link org.elasticsearch.license.core.ESLicenses.ESLicense} to * {@link org.elasticsearch.license.core.ESLicenses} only if diff --git a/src/main/java/org/elasticsearch/license/core/LicenseUtils.java b/src/main/java/org/elasticsearch/license/core/LicenseUtils.java index c535a8943c7..a644bc39240 100644 --- a/src/main/java/org/elasticsearch/license/core/LicenseUtils.java +++ b/src/main/java/org/elasticsearch/license/core/LicenseUtils.java @@ -10,10 +10,7 @@ import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; import java.text.ParseException; import java.util.HashSet; import java.util.Set; @@ -22,7 +19,7 @@ public class LicenseUtils { public static void dumpLicenseAsJson(ESLicenses esLicenses, OutputStream out) throws IOException { JsonGenerator generator = new JsonFactory().createJsonGenerator(out); - generator.useDefaultPrettyPrinter(); + //generator.useDefaultPrettyPrinter(); generator.writeStartObject(); { @@ -78,11 +75,15 @@ public class LicenseUtils { public static ESLicenses readLicenseFile(File licenseFile) throws IOException { try (FileInputStream fileInputStream = new FileInputStream(licenseFile)) { - JsonNode jsonNode = new ObjectMapper().readTree(fileInputStream); - return extractLicenseFromJson(jsonNode); + return readLicenseFromInputStream(fileInputStream); } } + public static ESLicenses readLicenseFromInputStream(InputStream inputStream) throws IOException { + JsonNode jsonNode = new ObjectMapper().readTree(inputStream); + return extractLicenseFromJson(jsonNode); + } + public static ESLicenses readLicensesFromString(String licensesString) throws IOException { JsonNode jsonNode = new ObjectMapper().readTree(licensesString); return extractLicenseFromJson(jsonNode); diff --git a/src/main/java/org/elasticsearch/license/licensor/ESLicenseSigner.java b/src/main/java/org/elasticsearch/license/licensor/ESLicenseSigner.java index 8d9e5fa7815..31f730a72d9 100644 --- a/src/main/java/org/elasticsearch/license/licensor/ESLicenseSigner.java +++ b/src/main/java/org/elasticsearch/license/licensor/ESLicenseSigner.java @@ -28,34 +28,28 @@ import static org.elasticsearch.license.core.ESLicenses.ESLicense; public class ESLicenseSigner { + public static String DEFAULT_PASS_PHRASE = "elasticsearch-license"; + private final static int VERSION_START = 0; private final static int VERSION = VERSION_START; private final static int MAGIC_LENGTH = 13; private final LicenseCreator licenseCreator; - private final SignerOptions options; - public static class SignerOptions { - final String privateKeyPath; - final String publicKeyPath; - final String password; + private final Path publicKeyPath; - public SignerOptions(String privateKeyPath, String publicKeyPath, String password) { - this.privateKeyPath = privateKeyPath; - this.publicKeyPath = publicKeyPath; - this.password = password; - } + public ESLicenseSigner(final String privateKeyPath, final String publicKeyPath) { + this(Paths.get(privateKeyPath), Paths.get(publicKeyPath)); } - public ESLicenseSigner(final SignerOptions options) { + public ESLicenseSigner(final Path privateKeyPath, final Path publicKeyPath) { LicenseCreatorProperties.setPrivateKeyDataProvider(new PrivateKeyDataProvider() { @Override public byte[] getEncryptedPrivateKeyData() throws KeyNotFoundException { - Path privateKeyFile = Paths.get(options.privateKeyPath); - assert privateKeyFile.toFile().exists(); + assert privateKeyPath.toFile().exists(); try { - return Files.readAllBytes(privateKeyFile); + return Files.readAllBytes(privateKeyPath); } catch (IOException e) { e.printStackTrace(); throw new IllegalStateException(e); @@ -64,13 +58,14 @@ public class ESLicenseSigner { } }); LicenseCreatorProperties.setPrivateKeyPasswordProvider(new PasswordProvider() { + @Override public char[] getPassword() { - return options.password.toCharArray(); + return Hasher.hash(DEFAULT_PASS_PHRASE).toCharArray(); } }); this.licenseCreator = LicenseCreator.getInstance(); - this.options = options; + this.publicKeyPath = publicKeyPath; } public ESLicenses sign(ESLicenses esLicenses) throws IOException { @@ -108,7 +103,7 @@ public class ESLicenseSigner { random.nextBytes(magic); final byte[] licenseSignature = licenseCreator.signAndSerializeLicense(license); final byte[] hash = Hasher.hash(Base64.encodeBase64String( - Files.readAllBytes(Paths.get(options.publicKeyPath))) + Files.readAllBytes(publicKeyPath)) ).getBytes(Charset.forName("UTF-8")); int headerLength = MAGIC_LENGTH + hash.length + 4 + 4; byte[] bytes = new byte[headerLength + licenseSignature.length]; diff --git a/src/main/java/org/elasticsearch/license/licensor/tools/KeyPairGeneratorTool.java b/src/main/java/org/elasticsearch/license/licensor/tools/KeyPairGeneratorTool.java index 5cd441eaef7..f1810b900de 100644 --- a/src/main/java/org/elasticsearch/license/licensor/tools/KeyPairGeneratorTool.java +++ b/src/main/java/org/elasticsearch/license/licensor/tools/KeyPairGeneratorTool.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.license.licensor.tools; +import net.nicholaswilliams.java.licensing.encryption.Hasher; import net.nicholaswilliams.java.licensing.encryption.RSAKeyPairGenerator; import net.nicholaswilliams.java.licensing.exception.AlgorithmNotSupportedException; import net.nicholaswilliams.java.licensing.exception.InappropriateKeyException; @@ -16,22 +17,21 @@ import java.security.KeyPair; public class KeyPairGeneratorTool { + public static String DEFAULT_PASS_PHRASE = "elasticsearch-license"; + static class Options { private final String publicKeyFilePath; private final String privateKeyFilePath; - private final String keyPass; - Options(String publicKeyFilePath, String privateKeyFilePath, String keyPass) { + Options(String publicKeyFilePath, String privateKeyFilePath) { this.publicKeyFilePath = publicKeyFilePath; this.privateKeyFilePath = privateKeyFilePath; - this.keyPass = keyPass; } } private static Options parse(String[] args) { String privateKeyPath = null; String publicKeyPath = null; - String keyPass = null; for (int i = 0; i < args.length; i++) { String command = args[i]; @@ -42,9 +42,6 @@ public class KeyPairGeneratorTool { case "--privateKeyPath": privateKeyPath = args[++i]; break; - case "--keyPass": - keyPass = args[++i]; - break; } } @@ -54,11 +51,8 @@ public class KeyPairGeneratorTool { if (privateKeyPath == null) { throw new IllegalArgumentException("mandatory option '--privateKeyPath' is missing"); } - if (keyPass == null) { - throw new IllegalArgumentException("mandatory option '--keyPass' is missing"); - } - return new Options(publicKeyPath, privateKeyPath, keyPass); + return new Options(publicKeyPath, privateKeyPath); } public static void main(String[] args) throws IOException { @@ -76,7 +70,7 @@ public class KeyPairGeneratorTool { throw new IllegalArgumentException("public key already exists in " + options.publicKeyFilePath); } - KeyPair keyPair = generateKeyPair(options.privateKeyFilePath, options.publicKeyFilePath, options.keyPass); + KeyPair keyPair = generateKeyPair(options.privateKeyFilePath, options.publicKeyFilePath); if (keyPair != null) { printStream.println("Successfully generated new keyPair [publicKey: " + options.publicKeyFilePath + ", privateKey: " + options.privateKeyFilePath + "]"); printStream.flush(); @@ -88,7 +82,7 @@ public class KeyPairGeneratorTool { } - private static KeyPair generateKeyPair(String privateKeyFileName, String publicKeyFileName, String password) { + private static KeyPair generateKeyPair(String privateKeyFileName, String publicKeyFileName) { RSAKeyPairGenerator generator = new RSAKeyPairGenerator(); KeyPair keyPair; @@ -99,7 +93,7 @@ public class KeyPairGeneratorTool { } try { - generator.saveKeyPairToFiles(keyPair, privateKeyFileName, publicKeyFileName, password.toCharArray()); + generator.saveKeyPairToFiles(keyPair, privateKeyFileName, publicKeyFileName, Hasher.hash(DEFAULT_PASS_PHRASE).toCharArray()); } catch (IOException | AlgorithmNotSupportedException | InappropriateKeyException | InappropriateKeySpecificationException e) { throw new IllegalStateException(e); } diff --git a/src/main/java/org/elasticsearch/license/licensor/tools/LicenseGeneratorTool.java b/src/main/java/org/elasticsearch/license/licensor/tools/LicenseGeneratorTool.java index 57d72587e6a..4c49c00e4dc 100644 --- a/src/main/java/org/elasticsearch/license/licensor/tools/LicenseGeneratorTool.java +++ b/src/main/java/org/elasticsearch/license/licensor/tools/LicenseGeneratorTool.java @@ -21,13 +21,11 @@ public class LicenseGeneratorTool { private final String licensesInput; private final String publicKeyFilePath; private final String privateKeyFilePath; - private final String keyPass; - Options(String licensesInput, String publicKeyFilePath, String privateKeyFilePath, String keyPass) { + Options(String licensesInput, String publicKeyFilePath, String privateKeyFilePath) { this.licensesInput = licensesInput; this.publicKeyFilePath = publicKeyFilePath; this.privateKeyFilePath = privateKeyFilePath; - this.keyPass = keyPass; } } @@ -36,7 +34,6 @@ public class LicenseGeneratorTool { String licenseFilePath = null; String privateKeyPath = null; String publicKeyPath = null; - String keyPass = null; for (int i = 0; i < args.length; i++) { String command = args[i].trim(); @@ -53,9 +50,6 @@ public class LicenseGeneratorTool { case "--privateKeyPath": privateKeyPath = args[++i]; break; - case "--keyPass": - keyPass = args[++i]; - break; } } @@ -75,11 +69,8 @@ public class LicenseGeneratorTool { if (privateKeyPath == null) { throw new IllegalArgumentException("mandatory option '--privateKeyPath' is missing"); } - if (keyPass == null) { - throw new IllegalArgumentException("mandatory option '--keyPass' is missing"); - } - return new Options(licenseInput, publicKeyPath, privateKeyPath, keyPass); + return new Options(licenseInput, publicKeyPath, privateKeyPath); } public static void main(String[] args) throws IOException { @@ -91,7 +82,7 @@ public class LicenseGeneratorTool { ESLicenses esLicenses = LicenseUtils.readLicensesFromString(options.licensesInput); - ESLicenseSigner signer = new ESLicenseSigner(new ESLicenseSigner.SignerOptions(options.privateKeyFilePath, options.publicKeyFilePath, options.keyPass)); + ESLicenseSigner signer = new ESLicenseSigner(options.privateKeyFilePath, options.publicKeyFilePath); ESLicenses signedLicences = signer.sign(esLicenses); LicenseUtils.dumpLicenseAsJson(signedLicences, out); diff --git a/src/main/java/org/elasticsearch/license/licensor/tools/LicenseVerificationTool.java b/src/main/java/org/elasticsearch/license/licensor/tools/LicenseVerificationTool.java index 0e982ed5d93..2dcb8c12fc6 100644 --- a/src/main/java/org/elasticsearch/license/licensor/tools/LicenseVerificationTool.java +++ b/src/main/java/org/elasticsearch/license/licensor/tools/LicenseVerificationTool.java @@ -19,35 +19,42 @@ import java.util.Set; public class LicenseVerificationTool { static class Options { - private final Set licensesFiles; + private final Set licenses; private final String publicKeyFilePath; - private final String keyPass; - Options(Set licensesFiles, String publicKeyFilePath, String keyPass) { - this.licensesFiles = licensesFiles; + Options(Set licenses, String publicKeyFilePath) { + this.licenses = licenses; this.publicKeyFilePath = publicKeyFilePath; - this.keyPass = keyPass; } - static Set asFiles(Set filePaths) { - Set files = new HashSet<>(filePaths.size()); - for (String filePath : filePaths) { - final File file = new File(filePath); - if (file.exists()) { - files.add(file); - } else { - throw new IllegalArgumentException(file.getAbsolutePath() + " does not exist!"); - } - } - return files; - } } - private static Options parse(String[] args) { + static Set asLicensesFromFiles(Set filePaths) throws IOException { + Set licenses = new HashSet<>(filePaths.size()); + for (String filePath : filePaths) { + final File file = new File(filePath); + if (file.exists()) { + licenses.add(LicenseUtils.readLicenseFile(file)); + } else { + throw new IllegalArgumentException(file.getAbsolutePath() + " does not exist!"); + } + } + return licenses; + } + + static Set asLicensesFromStrings(Set fileContents) throws IOException { + Set licenses = new HashSet<>(fileContents.size()); + for (String fileContent : fileContents) { + licenses.add(LicenseUtils.readLicensesFromString(fileContent)); + } + return licenses; + } + + private static Options parse(String[] args) throws IOException { Set licenseFilePaths = null; - Set licenseFiles = null; + Set licensesContents = new HashSet<>(); + Set licenses = null; String publicKeyPath = null; - String keyPass = null; for (int i = 0; i < args.length; i++) { String command = args[i]; @@ -56,29 +63,28 @@ public class LicenseVerificationTool { licenseFilePaths = new HashSet<>(); licenseFilePaths.addAll(Arrays.asList(args[++i].split(":"))); break; + case "--licenses": + licensesContents.add(args[++i]); + break; case "--publicKeyPath": publicKeyPath = args[++i]; break; - case "--keyPass": - keyPass = args[++i]; - break; } } - if (licenseFilePaths == null) { - throw new IllegalArgumentException("mandatory option '--licensesFiles' is missing"); + if (licenseFilePaths == null && licensesContents.size() == 0) { + throw new IllegalArgumentException("mandatory option '--licensesFiles' or '--licenses' is missing"); + } else if (licenseFilePaths != null) { + licenses = asLicensesFromFiles(licenseFilePaths); + } else if (licensesContents.size() > 0) { + licenses = asLicensesFromStrings(licensesContents); } else { - licenseFiles = Options.asFiles(licenseFilePaths); - if (licenseFiles.size() == 0) { - throw new IllegalArgumentException("no license file found for provided license files"); - } + throw new IllegalArgumentException("no licenses could be extracted"); } if (publicKeyPath == null) { throw new IllegalArgumentException("mandatory option '--publicKeyPath' is missing"); } - if (keyPass == null) { - throw new IllegalArgumentException("mandatory option '--keyPass' is missing"); - } - return new Options(licenseFiles, publicKeyPath, keyPass); + assert licenses != null; + return new Options(licenses, publicKeyPath); } public static void main(String[] args) throws IOException { @@ -88,11 +94,8 @@ public class LicenseVerificationTool { public static void run(String[] args, OutputStream out) throws IOException { Options options = parse(args); - // read licenses - Set esLicensesSet = LicenseUtils.readLicensesFromFiles(options.licensesFiles); - // verify licenses - ESLicenseManager licenseManager = new ESLicenseManager(esLicensesSet, options.publicKeyFilePath, options.keyPass); + ESLicenseManager licenseManager = new ESLicenseManager(options.licenses, options.publicKeyFilePath); licenseManager.verifyLicenses(); // dump effective licences diff --git a/src/main/java/org/elasticsearch/license/manager/ESLicenseManager.java b/src/main/java/org/elasticsearch/license/manager/ESLicenseManager.java index 266009ad199..2b54c0f3504 100644 --- a/src/main/java/org/elasticsearch/license/manager/ESLicenseManager.java +++ b/src/main/java/org/elasticsearch/license/manager/ESLicenseManager.java @@ -41,19 +41,19 @@ public class ESLicenseManager { private final ESLicenses esLicenses; private final FilePublicKeyDataProvider publicKeyDataProvider; - public ESLicenseManager(Set esLicensesSet, String publicKeyFile, String password) throws IOException { + public ESLicenseManager(Set esLicensesSet, String publicKeyFile) throws IOException { this.publicKeyDataProvider = new FilePublicKeyDataProvider(publicKeyFile); this.esLicenses = merge(esLicensesSet); LicenseManagerProperties.setLicenseProvider(new ESLicenseProvider()); LicenseManagerProperties.setPublicKeyDataProvider(publicKeyDataProvider); LicenseManagerProperties.setLicenseValidator(new DefaultLicenseValidator()); - LicenseManagerProperties.setPublicKeyPasswordProvider(new ESPublicKeyPasswordProvider(password)); + LicenseManagerProperties.setPublicKeyPasswordProvider(new ESPublicKeyPasswordProvider()); this.licenseManager = LicenseManager.getInstance(); } - public ESLicenseManager(ESLicenses esLicenses, String publicKeyFile, String password) throws IOException { - this(Collections.singleton(esLicenses), publicKeyFile, password); + public ESLicenseManager(ESLicenses esLicenses, String publicKeyFile) throws IOException { + this(Collections.singleton(esLicenses), publicKeyFile); } private static ESLicenses merge(Set esLicensesSet) { @@ -129,7 +129,7 @@ public class ESLicenseManager { && license.getHolder().equals(eslicense.issuedTo()) && license.getIssueDate() == eslicense.issueDate() && license.getGoodBeforeDate() == eslicense.expiryDate(); - assert license.getFeatures().size() == 4 : "one license should have only four feature"; + assert license.getFeatures().size() == 4 : "one license should have only four features"; String maxNodesPrefix = "maxNodes:"; String typePrefix = "type:"; String subscriptionTypePrefix = "subscription_type:"; @@ -137,6 +137,7 @@ public class ESLicenseManager { boolean featureValid = false; boolean typeValid = false; boolean subscriptionTypeValid = false; + for (License.Feature feature : license.getFeatures()) { String featureName = feature.getName(); if (featureName.startsWith(maxNodesPrefix)) { @@ -151,6 +152,7 @@ public class ESLicenseManager { } } if (!licenseValid || !featureValid || !maxNodesValid || !typeValid || !subscriptionTypeValid) { + //only for debugging String msg = "licenseValid: " + licenseValid + "\n" + "featureValid: " + featureValid + "\n" + "maxNodeValide: " + maxNodesValid + "\n" + @@ -255,16 +257,11 @@ public class ESLicenseManager { } private class ESPublicKeyPasswordProvider implements PasswordProvider { - - private final String pass; - - private ESPublicKeyPasswordProvider(String pass) { - this.pass = pass; - } + private final String DEFAULT_PASS_PHRASE = "elasticsearch-license"; @Override public char[] getPassword() { - return pass.toCharArray(); + return Hasher.hash(DEFAULT_PASS_PHRASE).toCharArray(); } } } diff --git a/src/main/java/org/elasticsearch/license/manager/Utils.java b/src/main/java/org/elasticsearch/license/manager/Utils.java index d62f734e29e..2b22c6b4b6d 100644 --- a/src/main/java/org/elasticsearch/license/manager/Utils.java +++ b/src/main/java/org/elasticsearch/license/manager/Utils.java @@ -23,7 +23,7 @@ public class Utils { private Utils() { } - static ESLicenses getESLicensesFromSignatures(final LicenseManager licenseManager, Set signatures) { + public static ESLicenses getESLicensesFromSignatures(final LicenseManager licenseManager, Set signatures) { final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder(); for (String signature : signatures) { licensesBuilder.license(getESLicenseFromSignature(licenseManager, signature)); diff --git a/src/test/java/org/elasticsearch/license/licensor/LicenseGenerationTests.java b/src/test/java/org/elasticsearch/license/licensor/LicenseGenerationTests.java index cf02a5f5644..290d26fd00a 100644 --- a/src/test/java/org/elasticsearch/license/licensor/LicenseGenerationTests.java +++ b/src/test/java/org/elasticsearch/license/licensor/LicenseGenerationTests.java @@ -26,7 +26,6 @@ public class LicenseGenerationTests { private static String pubKeyPath = null; private static String priKeyPath = null; - private static String keyPass = null; @BeforeClass public static void setup() throws IOException { @@ -38,17 +37,13 @@ public class LicenseGenerationTests { LicenseGenerationTests.priKeyPath = privateKeyFile.getAbsolutePath(); assert privateKeyFile.delete(); assert publicKeyFile.delete(); - String keyPass = "password"; - LicenseGenerationTests.keyPass = keyPass; // Generate keyPair - String[] args = new String[6]; + String[] args = new String[4]; args[0] = "--publicKeyPath"; args[1] = LicenseGenerationTests.pubKeyPath; args[2] = "--privateKeyPath"; args[3] = LicenseGenerationTests.priKeyPath; - args[4] = "--keyPass"; - args[5] = LicenseGenerationTests.keyPass; KeyPairGeneratorTool.main(args); } @@ -61,15 +56,13 @@ public class LicenseGenerationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; String licenseOutput = TestUtils.runLicenseGenerationTool(args); @@ -90,15 +83,13 @@ public class LicenseGenerationTests { map.put(FeatureType.MARVEL, marvelFeatureAttributes); String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; String licenseOutput = TestUtils.runLicenseGenerationTool(args); @@ -117,15 +108,13 @@ public class LicenseGenerationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--linse"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; try { String licenseOutput = TestUtils.runLicenseGenerationTool(args); @@ -145,15 +134,13 @@ public class LicenseGenerationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; try { String licenseOutput = TestUtils.runLicenseGenerationTool(args); @@ -172,15 +159,13 @@ public class LicenseGenerationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; try { String licenseOutput = TestUtils.runLicenseGenerationTool(args); @@ -200,15 +185,13 @@ public class LicenseGenerationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; try { String licenseOutput = TestUtils.runLicenseGenerationTool(args); diff --git a/src/test/java/org/elasticsearch/license/licensor/LicenseVerificationToolTests.java b/src/test/java/org/elasticsearch/license/licensor/LicenseVerificationToolTests.java index ce2460e5182..7a0dab92862 100644 --- a/src/test/java/org/elasticsearch/license/licensor/LicenseVerificationToolTests.java +++ b/src/test/java/org/elasticsearch/license/licensor/LicenseVerificationToolTests.java @@ -25,7 +25,6 @@ public class LicenseVerificationToolTests { private static String pubKeyPath = null; private static String priKeyPath = null; - private static String keyPass = null; @BeforeClass public static void setup() throws IOException { @@ -37,16 +36,13 @@ public class LicenseVerificationToolTests { LicenseVerificationToolTests.priKeyPath = privateKeyFile.getAbsolutePath(); assert privateKeyFile.delete(); assert publicKeyFile.delete(); - LicenseVerificationToolTests.keyPass = "password"; // Generate keyPair - String[] args = new String[6]; + String[] args = new String[4]; args[0] = "--publicKeyPath"; args[1] = LicenseVerificationToolTests.pubKeyPath; args[2] = "--privateKeyPath"; args[3] = LicenseVerificationToolTests.priKeyPath; - args[4] = "--keyPass"; - args[5] = LicenseVerificationToolTests.keyPass; KeyPairGeneratorTool.main(args); } @@ -67,13 +63,11 @@ public class LicenseVerificationToolTests { signedLicense = runLicenseGenerationTool(TestUtils.generateESLicenses(map)); String secondLicenseFile = getAsFilePath(signedLicense); - String[] args = new String[6]; + String[] args = new String[4]; args[0] = "--licensesFiles"; args[1] = firstLicenseFile + ":" + secondLicenseFile; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; - args[4] = "--keyPass"; - args[5] = keyPass; String effectiveLicenseStr = runLicenseVerificationTool(args); ESLicenses effectiveLicense = LicenseUtils.readLicensesFromString(effectiveLicenseStr); @@ -101,13 +95,11 @@ public class LicenseVerificationToolTests { signedLicense = runLicenseGenerationTool(TestUtils.generateESLicenses(map)); String secondLicenseFile = getAsFilePath(signedLicense); - String[] args = new String[6]; + String[] args = new String[4]; args[0] = "--licensesFiles"; args[1] = firstLicenseFile + ":" + secondLicenseFile; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; - args[4] = "--keyPass"; - args[5] = keyPass; String effectiveLicenseStr = runLicenseVerificationTool(args); ESLicenses effectiveLicense = LicenseUtils.readLicensesFromString(effectiveLicenseStr); @@ -142,13 +134,11 @@ public class LicenseVerificationToolTests { signedLicense = runLicenseGenerationTool(TestUtils.generateESLicenses(map)); String secondLicenseFile = getAsFilePath(signedLicense); - String[] args = new String[6]; + String[] args = new String[4]; args[0] = "--licensesFiles"; args[1] = firstLicenseFile + ":" + secondLicenseFile; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; - args[4] = "--keyPass"; - args[5] = keyPass; String effectiveLicenseStr = runLicenseVerificationTool(args); ESLicenses effectiveLicense = LicenseUtils.readLicensesFromString(effectiveLicenseStr); @@ -170,16 +160,13 @@ public class LicenseVerificationToolTests { } public static String runLicenseGenerationTool(String licenseInput) throws IOException { - String args[] = new String[8]; - + String args[] = new String[6]; args[0] = "--license"; args[1] = licenseInput; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; return TestUtils.runLicenseGenerationTool(args); } diff --git a/src/test/java/org/elasticsearch/license/manager/LicenseVerificationTests.java b/src/test/java/org/elasticsearch/license/manager/LicenseVerificationTests.java index 12f53e849f3..3ba5d4d133f 100644 --- a/src/test/java/org/elasticsearch/license/manager/LicenseVerificationTests.java +++ b/src/test/java/org/elasticsearch/license/manager/LicenseVerificationTests.java @@ -31,7 +31,6 @@ public class LicenseVerificationTests { private static String pubKeyPath = null; private static String priKeyPath = null; - private static String keyPass = null; @BeforeClass public static void setup() throws IOException { @@ -43,16 +42,13 @@ public class LicenseVerificationTests { LicenseVerificationTests.priKeyPath = privateKeyFile.getAbsolutePath(); assert privateKeyFile.delete(); assert publicKeyFile.delete(); - LicenseVerificationTests.keyPass = "password"; // Generate keyPair - String[] args = new String[6]; + String[] args = new String[4]; args[0] = "--publicKeyPath"; args[1] = LicenseVerificationTests.pubKeyPath; args[2] = "--privateKeyPath"; args[3] = LicenseVerificationTests.priKeyPath; - args[4] = "--keyPass"; - args[5] = LicenseVerificationTests.keyPass; KeyPairGeneratorTool.main(args); } @@ -68,21 +64,19 @@ public class LicenseVerificationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; String licenseOutput = TestUtils.runLicenseGenerationTool(args); ESLicenses esLicensesOutput = readLicensesFromString(licenseOutput); - ESLicenseManager esLicenseManager = new ESLicenseManager(esLicensesOutput, pubKeyPath, keyPass); + ESLicenseManager esLicenseManager = new ESLicenseManager(esLicensesOutput, pubKeyPath); esLicenseManager.verifyLicenses(); @@ -105,21 +99,19 @@ public class LicenseVerificationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; String licenseOutput = TestUtils.runLicenseGenerationTool(args); ESLicenses esLicensesOutput = readLicensesFromString(licenseOutput); - ESLicenseManager esLicenseManager = new ESLicenseManager(esLicensesOutput, pubKeyPath, keyPass); + ESLicenseManager esLicenseManager = new ESLicenseManager(esLicensesOutput, pubKeyPath); esLicenseManager.verifyLicenses(); @@ -145,21 +137,19 @@ public class LicenseVerificationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; String licenseOutput = TestUtils.runLicenseGenerationTool(args); ESLicenses esLicensesOutput = readLicensesFromString(licenseOutput); - ESLicenseManager esLicenseManager = new ESLicenseManager(esLicensesOutput, pubKeyPath, keyPass); + ESLicenseManager esLicenseManager = new ESLicenseManager(esLicensesOutput, pubKeyPath); // All validation for shield license should be normal as expected verifyLicenseManager(esLicenseManager, Collections.singletonMap(FeatureType.SHIELD, shildFeatureAttributes)); @@ -180,15 +170,13 @@ public class LicenseVerificationTests { String licenseString = TestUtils.generateESLicenses(map); - String[] args = new String[8]; + String[] args = new String[6]; args[0] = "--license"; args[1] = licenseString; args[2] = "--publicKeyPath"; args[3] = pubKeyPath; args[4] = "--privateKeyPath"; args[5] = priKeyPath; - args[6] = "--keyPass"; - args[7] = keyPass; String licenseOutput = TestUtils.runLicenseGenerationTool(args); @@ -208,7 +196,7 @@ public class LicenseVerificationTests { ESLicenseManager esLicenseManager = null; try { - esLicenseManager = new ESLicenseManager(tamperedLicenses, pubKeyPath, keyPass); + esLicenseManager = new ESLicenseManager(tamperedLicenses, pubKeyPath); assertTrue("License manager should always report the original (signed) expiry date", esLicenseManager.getExpiryDateForLicense(FeatureType.SHIELD) == originalExpiryDate); esLicenseManager.verifyLicenses(); fail();