Refactored licensing tools to use CliTool as base

- rewrote licensing tool tests

Original commit: elastic/x-pack-elasticsearch@e5e70a491a
This commit is contained in:
Areek Zillur 2014-11-05 19:29:00 -05:00
parent 3bf4d2659e
commit abd129fa7a
10 changed files with 638 additions and 360 deletions

View File

@ -11,95 +11,99 @@ import net.nicholaswilliams.java.licensing.exception.AlgorithmNotSupportedExcept
import net.nicholaswilliams.java.licensing.exception.InappropriateKeyException; import net.nicholaswilliams.java.licensing.exception.InappropriateKeyException;
import net.nicholaswilliams.java.licensing.exception.InappropriateKeySpecificationException; import net.nicholaswilliams.java.licensing.exception.InappropriateKeySpecificationException;
import net.nicholaswilliams.java.licensing.exception.RSA2048NotSupportedException; import net.nicholaswilliams.java.licensing.exception.RSA2048NotSupportedException;
import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.common.cli.CliToolConfig;
import org.elasticsearch.common.cli.Terminal;
import org.elasticsearch.common.cli.commons.CommandLine;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.security.KeyPair; import java.security.KeyPair;
public class KeyPairGeneratorTool { import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
import static org.elasticsearch.common.cli.CliToolConfig.Builder.option;
import static org.elasticsearch.common.cli.CliToolConfig.config;
public static String DEFAULT_PASS_PHRASE = "elasticsearch-license"; public class KeyPairGeneratorTool extends CliTool {
static class Options { private static final CliToolConfig CONFIG = config("key-pair-generator", KeyPairGeneratorTool.class)
private final String publicKeyFilePath; .cmds(KeyPairGenerator.CMD)
private final String privateKeyFilePath; .build();
Options(String publicKeyFilePath, String privateKeyFilePath) { public KeyPairGeneratorTool() {
this.publicKeyFilePath = publicKeyFilePath; super(CONFIG);
this.privateKeyFilePath = privateKeyFilePath;
}
} }
private static Options parse(String[] args) { @Override
String privateKeyPath = null; protected Command parse(String s, CommandLine commandLine) throws Exception {
String publicKeyPath = null; return KeyPairGenerator.parse(terminal, commandLine);
}
for (int i = 0; i < args.length; i++) { private static class KeyPairGenerator extends Command {
String command = args[i];
switch (command) { public static String DEFAULT_PASS_PHRASE = "elasticsearch-license";
case "--publicKeyPath": private static final String NAME = "key-pair-generator";
publicKeyPath = args[++i]; private static final CliToolConfig.Cmd CMD = cmd(NAME, KeyPairGenerator.class)
break; .options(
case "--privateKeyPath": option("pub", "publicKeyPath").required(true).hasArg(true),
privateKeyPath = args[++i]; option("pri", "privateKeyPath").required(true).hasArg(true)
break; ).build();
private final String publicKeyPath;
private final String privateKeyPath;
protected KeyPairGenerator(Terminal terminal, String publicKeyPath, String privateKeyPath) {
super(terminal);
this.privateKeyPath = privateKeyPath;
this.publicKeyPath = publicKeyPath;
}
public static Command parse(Terminal terminal, CommandLine commandLine) {
String publicKeyPath = commandLine.getOptionValue("publicKeyPath");
String privateKeyPath = commandLine.getOptionValue("privateKeyPath");
if (exists(privateKeyPath)) {
return exitCmd(ExitStatus.USAGE, terminal, privateKeyPath + " already exists");
} else if (exists(publicKeyPath)) {
return exitCmd(ExitStatus.USAGE, terminal, publicKeyPath + " already exists");
} }
return new KeyPairGenerator(terminal, publicKeyPath, privateKeyPath);
} }
if (publicKeyPath == null) { @Override
throw new IllegalArgumentException("mandatory option '--publicKeyPath' is missing"); public ExitStatus execute(Settings settings, Environment env) throws Exception {
} KeyPair keyPair = generateKeyPair(privateKeyPath, publicKeyPath);
if (privateKeyPath == null) { terminal.println(Terminal.Verbosity.VERBOSE, "generating key pair [public key: " + publicKeyPath + ", private key: " + privateKeyPath + "]");
throw new IllegalArgumentException("mandatory option '--privateKeyPath' is missing"); return (keyPair != null) ? ExitStatus.OK : ExitStatus.CANT_CREATE;
} }
return new Options(publicKeyPath, privateKeyPath); private static boolean exists(String filePath) {
} return new File(filePath).exists();
public static void main(String[] args) throws IOException {
run(args, System.out);
}
public static void run(String[] args, OutputStream out) throws IOException {
PrintStream printStream = new PrintStream(out);
Options options = parse(args);
if (exists(options.privateKeyFilePath)) {
throw new IllegalArgumentException("private key already exists in " + options.privateKeyFilePath);
} else if (exists(options.publicKeyFilePath)) {
throw new IllegalArgumentException("public key already exists in " + options.publicKeyFilePath);
} }
KeyPair keyPair = generateKeyPair(options.privateKeyFilePath, options.publicKeyFilePath); private static KeyPair generateKeyPair(String privateKeyFileName, String publicKeyFileName) {
if (keyPair != null) { RSAKeyPairGenerator generator = new RSAKeyPairGenerator();
printStream.println("Successfully generated new keyPair [publicKey: " + options.publicKeyFilePath + ", privateKey: " + options.privateKeyFilePath + "]");
printStream.flush(); KeyPair keyPair;
try {
keyPair = generator.generateKeyPair();
} catch (RSA2048NotSupportedException e) {
throw new IllegalStateException(e);
}
try {
generator.saveKeyPairToFiles(keyPair, privateKeyFileName, publicKeyFileName, Hasher.hash(DEFAULT_PASS_PHRASE).toCharArray());
} catch (IOException | AlgorithmNotSupportedException | InappropriateKeyException | InappropriateKeySpecificationException e) {
throw new IllegalStateException(e);
}
return keyPair;
} }
} }
private static boolean exists(String filePath) { public static void main(String[] args) throws Exception {
return new File(filePath).exists(); int status = new KeyPairGeneratorTool().execute(args);
} System.exit(status);
private static KeyPair generateKeyPair(String privateKeyFileName, String publicKeyFileName) {
RSAKeyPairGenerator generator = new RSAKeyPairGenerator();
KeyPair keyPair;
try {
keyPair = generator.generateKeyPair();
} catch (RSA2048NotSupportedException e) {
throw new IllegalStateException(e);
}
try {
generator.saveKeyPairToFiles(keyPair, privateKeyFileName, publicKeyFileName, Hasher.hash(DEFAULT_PASS_PHRASE).toCharArray());
} catch (IOException | AlgorithmNotSupportedException | InappropriateKeyException | InappropriateKeySpecificationException e) {
throw new IllegalStateException(e);
}
return keyPair;
} }
} }

View File

@ -5,101 +5,130 @@
*/ */
package org.elasticsearch.license.licensor.tools; package org.elasticsearch.license.licensor.tools;
import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.common.cli.CliToolConfig;
import org.elasticsearch.common.cli.Terminal;
import org.elasticsearch.common.cli.commons.CommandLine;
import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.collect.ImmutableSet;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.core.ESLicenses; import org.elasticsearch.license.core.ESLicenses;
import org.elasticsearch.license.licensor.ESLicenseSigner; import org.elasticsearch.license.licensor.ESLicenseSigner;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.text.ParseException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class LicenseGeneratorTool { import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
import static org.elasticsearch.common.cli.CliToolConfig.Builder.option;
import static org.elasticsearch.common.cli.CliToolConfig.config;
static class Options { public class LicenseGeneratorTool extends CliTool {
private final Set<ESLicense> licenseSpecs; public static final String NAME = "license-generator";
private final String publicKeyFilePath;
private final String privateKeyFilePath;
Options(Set<ESLicense> licenseSpecs, String publicKeyFilePath, String privateKeyFilePath) { private static final CliToolConfig CONFIG = config(NAME, LicenseGeneratorTool.class)
.cmds(LicenseGenerator.CMD)
.build();
public LicenseGeneratorTool() {
super(CONFIG);
}
@Override
protected Command parse(String s, CommandLine commandLine) throws Exception {
return LicenseGenerator.parse(terminal, commandLine);
}
public static class LicenseGenerator extends Command {
private static final CliToolConfig.Cmd CMD = cmd(NAME, LicenseGenerator.class)
.options(
option("pub", "publicKeyPath").required(true).hasArg(true),
option("pri", "privateKeyPath").required(true).hasArg(true),
option("l", "license").required(false).hasArg(true),
option("lf", "licenseFile").required(false).hasArg(true)
).build();
public final Set<ESLicense> licenseSpecs;
public final String publicKeyFilePath;
public final String privateKeyFilePath;
public LicenseGenerator(Terminal terminal, String publicKeyFilePath, String privateKeyFilePath, Set<ESLicense> licenseSpecs) {
super(terminal);
this.licenseSpecs = licenseSpecs; this.licenseSpecs = licenseSpecs;
this.publicKeyFilePath = publicKeyFilePath;
this.privateKeyFilePath = privateKeyFilePath; this.privateKeyFilePath = privateKeyFilePath;
this.publicKeyFilePath = publicKeyFilePath;
} }
}
private static Options parse(String[] args) throws IOException, ParseException { public static Command parse(Terminal terminal, CommandLine commandLine) throws IOException {
Set<ESLicense> licenseSpecs = new HashSet<>(); String publicKeyPath = commandLine.getOptionValue("publicKeyPath");
String privateKeyPath = null; String privateKeyPath = commandLine.getOptionValue("privateKeyPath");
String publicKeyPath = null; String[] licenseSpecSources = commandLine.getOptionValues("license");
String[] licenseSpecSourceFiles = commandLine.getOptionValues("licenseFile");
for (int i = 0; i < args.length; i++) { if (!exists(privateKeyPath)) {
String command = args[i].trim(); return exitCmd(ExitStatus.USAGE, terminal, privateKeyPath + " does not exist");
switch (command) { } else if (!exists(publicKeyPath)) {
case "--license": return exitCmd(ExitStatus.USAGE, terminal, publicKeyPath + " does not exist");
String licenseInput = args[++i];
licenseSpecs.addAll(ESLicenses.fromSource(licenseInput.getBytes(StandardCharsets.UTF_8), false));
break;
case "--licenseFile":
File licenseFile = new File(args[++i]);
if (licenseFile.exists()) {
final byte[] bytes = Files.readAllBytes(Paths.get(licenseFile.getAbsolutePath()));
licenseSpecs.addAll(ESLicenses.fromSource(bytes, false));
} else {
throw new IllegalArgumentException(licenseFile.getAbsolutePath() + " does not exist!");
}
break;
case "--publicKeyPath":
publicKeyPath = args[++i];
break;
case "--privateKeyPath":
privateKeyPath = args[++i];
break;
} }
Set<ESLicense> licenseSpecs = new HashSet<>();
if (licenseSpecSources != null) {
for (String licenseSpec : licenseSpecSources) {
licenseSpecs.addAll(ESLicenses.fromSource(licenseSpec.getBytes(StandardCharsets.UTF_8), false));
}
}
if (licenseSpecSourceFiles != null) {
for (String licenseSpecFilePath : licenseSpecSourceFiles) {
Path licenseSpecPath = Paths.get(licenseSpecFilePath);
if (!exists(licenseSpecFilePath)) {
return exitCmd(ExitStatus.USAGE, terminal, licenseSpecFilePath + " does not exist");
}
licenseSpecs.addAll(ESLicenses.fromSource(Files.readAllBytes(licenseSpecPath), false));
}
}
if (licenseSpecs.size() == 0) {
return exitCmd(ExitStatus.USAGE, terminal, "no license spec provided");
}
return new LicenseGenerator(terminal, publicKeyPath, privateKeyPath, licenseSpecs);
} }
if (licenseSpecs.size() == 0) { @Override
throw new IllegalArgumentException("at least one of '--license' or '--licenseFile' has to be provided"); public ExitStatus execute(Settings settings, Environment env) throws Exception {
}
if (publicKeyPath == null) { // sign
throw new IllegalArgumentException("mandatory option '--publicKeyPath' is missing"); ESLicenseSigner signer = new ESLicenseSigner(privateKeyFilePath, publicKeyFilePath);
} else if (!Paths.get(publicKeyPath).toFile().exists()) { ImmutableSet<ESLicense> signedLicences = signer.sign(licenseSpecs);
throw new IllegalArgumentException("Public key file: " + publicKeyPath + " does not exist!");
} // dump
if (privateKeyPath == null) { XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
throw new IllegalArgumentException("mandatory option '--privateKeyPath' is missing"); ESLicenses.toXContent(signedLicences, builder, ToXContent.EMPTY_PARAMS);
} else if (!Paths.get(privateKeyPath).toFile().exists()) { builder.flush();
throw new IllegalArgumentException("Private key file: " + privateKeyPath + " does not exist!"); terminal.print(builder.string());
return ExitStatus.OK;
} }
return new Options(licenseSpecs, publicKeyPath, privateKeyPath);
private static boolean exists(String filePath) {
return new File(filePath).exists();
}
} }
public static void main(String[] args) throws IOException, ParseException { public static void main(String[] args) throws Exception {
run(args, System.out); int status = new LicenseGeneratorTool().execute(args);
System.exit(status);
} }
public static void run(String[] args, OutputStream out) throws IOException, ParseException {
Options options = parse(args);
ESLicenseSigner signer = new ESLicenseSigner(options.privateKeyFilePath, options.publicKeyFilePath);
ImmutableSet<ESLicense> signedLicences = signer.sign(options.licenseSpecs);
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON, out);
ESLicenses.toXContent(signedLicences, builder, ToXContent.EMPTY_PARAMS);
builder.flush();
}
} }

View File

@ -5,68 +5,121 @@
*/ */
package org.elasticsearch.license.licensor.tools; package org.elasticsearch.license.licensor.tools;
import org.elasticsearch.common.collect.ImmutableMap; import net.nicholaswilliams.java.licensing.exception.InvalidLicenseException;
import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.common.cli.CliToolConfig;
import org.elasticsearch.common.cli.Terminal;
import org.elasticsearch.common.cli.commons.CommandLine;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.core.ESLicenses; import org.elasticsearch.license.core.ESLicenses;
import org.elasticsearch.license.manager.ESLicenseManager; import org.elasticsearch.license.manager.ESLicenseManager;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
public class LicenseVerificationTool { import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
import static org.elasticsearch.common.cli.CliToolConfig.Builder.option;
import static org.elasticsearch.common.cli.CliToolConfig.config;
private static Set<ESLicense> parse(String[] args) throws IOException { public class LicenseVerificationTool extends CliTool {
Set<ESLicense> licenses = new HashSet<>(); public static final String NAME = "verify-license";
for (int i = 0; i < args.length; i++) { private static final CliToolConfig CONFIG = config(NAME, LicenseVerificationTool.class)
String command = args[i]; .cmds(LicenseVerifier.CMD)
switch (command) { .build();
case "--licensesFiles":
for (String filePath : args[++i].split(":")) { public LicenseVerificationTool() {
File file = new File(filePath); super(CONFIG);
if (file.exists()) { }
licenses.addAll(ESLicenses.fromSource(Files.readAllBytes(Paths.get(file.getAbsolutePath()))));
} else { @Override
throw new IllegalArgumentException(file.getAbsolutePath() + " does not exist!"); protected Command parse(String s, CommandLine commandLine) throws Exception {
} return LicenseVerifier.parse(terminal, commandLine);
} }
break;
case "--licenses": public static class LicenseVerifier extends Command {
licenses.addAll(ESLicenses.fromSource(args[++i]));
break; private static final CliToolConfig.Cmd CMD = cmd(NAME, LicenseVerifier.class)
.options(
option("l", "license").required(false).hasArg(true),
option("lf", "licenseFile").required(false).hasArg(true)
).build();
public final Set<ESLicense> licenses;
public LicenseVerifier(Terminal terminal, Set<ESLicense> licenses) {
super(terminal);
this.licenses = licenses;
}
public static Command parse(Terminal terminal, CommandLine commandLine) throws IOException {
String[] licenseSources = commandLine.getOptionValues("license");
String[] licenseSourceFiles = commandLine.getOptionValues("licenseFile");
Set<ESLicense> esLicenses = new HashSet<>();
if (licenseSources != null) {
for (String licenseSpec : licenseSources) {
esLicenses.addAll(ESLicenses.fromSource(licenseSpec.getBytes(StandardCharsets.UTF_8)));
}
} }
if (licenseSourceFiles != null) {
for (String licenseFilePath : licenseSourceFiles) {
Path licensePath = Paths.get(licenseFilePath);
if (!exists(licenseFilePath)) {
return exitCmd(ExitStatus.USAGE, terminal, licenseFilePath + " does not exist");
}
esLicenses.addAll(ESLicenses.fromSource(Files.readAllBytes(licensePath)));
}
}
if (esLicenses.size() == 0) {
return exitCmd(ExitStatus.USAGE, terminal, "no license provided");
}
return new LicenseVerifier(terminal, esLicenses);
} }
if (licenses.size() == 0) {
throw new IllegalArgumentException("mandatory option '--licensesFiles' or '--licenses' is missing"); @Override
public ExitStatus execute(Settings settings, Environment env) throws Exception {
// verify
Map<String, ESLicense> effectiveLicenses = ESLicenses.reduceAndMap(licenses);
ESLicenseManager licenseManager = new ESLicenseManager();
try {
licenseManager.verifyLicenses(effectiveLicenses);
} catch (InvalidLicenseException e) {
return ExitStatus.DATA_ERROR;
}
// dump effective licences
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
ESLicenses.toXContent(effectiveLicenses.values(), builder, ToXContent.EMPTY_PARAMS);
builder.flush();
terminal.print(builder.string());
return ExitStatus.OK;
}
private static boolean exists(String filePath) {
return new File(filePath).exists();
} }
return licenses;
} }
public static void main(String[] args) throws IOException { public static void main(String[] args) throws Exception {
run(args, System.out); int status = new LicenseVerificationTool().execute(args);
System.exit(status);
} }
public static void run(String[] args, OutputStream out) throws IOException {
Set<ESLicense> licenses = parse(args);
// reduce & verify licenses
ImmutableMap<String, ESLicense> effectiveLicenses = ESLicenses.reduceAndMap(licenses);
ESLicenseManager licenseManager = new ESLicenseManager();
licenseManager.verifyLicenses(effectiveLicenses);
// dump effective licences
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON, out);
ESLicenses.toXContent(effectiveLicenses.values(), builder, ToXContent.EMPTY_PARAMS);
builder.flush();
}
} }

View File

@ -0,0 +1,22 @@
NAME
key-pair-generator - generates a key pair with RSA 2048-bit security
SYNOPSIS
key-pair-generator -pub publicKeyPath -pri privateKeyPath
DESCRIPTION
This tool generates and saves a key pair to the provided publicKeyPath
and privateKeyPath. The tool checks the existence of the provided key paths
and will not override if any existing keys are found.
OPTIONS
-h,--help Shows this message
-pub,--publicKeyPath <path> Save the generated public key to path
-pri,--privateKeyPath <path> Save the generated private key to path

View File

@ -0,0 +1,26 @@
NAME
license-generator - generates signed elasticsearch license(s) for a given license spec(s)
SYNOPSIS
license-generator -l licenseSpec -pub publicKeyPath -pri privateKeyPath
DESCRIPTION
This tool generate elasticsearch license(s) for the provided license spec(s). The tool
can take arbitrary number of `--license` and/or `--licenseFile` to generate corrosponding
signed license(s).
OPTIONS
-h,--help Shows this message
-l,--license <license spec> License spec to generate a signed license from
-lf,--licenseFile <path> Path to a license spec file
-pub,--publicKeyPath <path> Save the generated public key to path
-pri,--privateKeyPath <path> Save the generated private key to path

View File

@ -0,0 +1,20 @@
NAME
verify-license - verifies the integrity of elasticsearch signed license(s)
SYNOPSIS
verify-license -l signedLicense
DESCRIPTION
This tool assumes the configured public key to be the same as that of the production license plugin public key.
The tool can take arbitrary number of `--license` and/or `--licenseFile` for verifying signed license(s).
OPTIONS
-h,--help Shows this message
-l,--license <signed license> License spec to generate a signed license from
-lf,--licenseFile <path> Path to signed license(s) file

View File

@ -29,6 +29,8 @@ import static com.carrotsearch.randomizedtesting.RandomizedTest.randomIntBetween
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomRealisticUnicodeOfCodepointLengthBetween; import static com.carrotsearch.randomizedtesting.RandomizedTest.randomRealisticUnicodeOfCodepointLengthBetween;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.ElasticsearchTestCase.randomFrom; import static org.elasticsearch.test.ElasticsearchTestCase.randomFrom;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
@RunWith(value = com.carrotsearch.randomizedtesting.RandomizedRunner.class) @RunWith(value = com.carrotsearch.randomizedtesting.RandomizedRunner.class)
public class AbstractLicensingTestBase { public class AbstractLicensingTestBase {
@ -36,9 +38,9 @@ public class AbstractLicensingTestBase {
protected static String pubKeyPath = null; protected static String pubKeyPath = null;
protected static String priKeyPath = null; protected static String priKeyPath = null;
private final FormatDateTimeFormatter formatDateTimeFormatter = Joda.forPattern("yyyy-MM-dd"); private final static FormatDateTimeFormatter formatDateTimeFormatter = Joda.forPattern("yyyy-MM-dd");
private final org.elasticsearch.common.joda.time.format.DateTimeFormatter dateTimeFormatter = formatDateTimeFormatter.printer(); private final static org.elasticsearch.common.joda.time.format.DateTimeFormatter dateTimeFormatter = formatDateTimeFormatter.printer();
private final DateMathParser dateMathParser = new DateMathParser(formatDateTimeFormatter, TimeUnit.MILLISECONDS); private final static DateMathParser dateMathParser = new DateMathParser(formatDateTimeFormatter, TimeUnit.MILLISECONDS);
@BeforeClass @BeforeClass
public static void setup() throws Exception { public static void setup() throws Exception {
@ -46,11 +48,11 @@ public class AbstractLicensingTestBase {
priKeyPath = getResourcePath("/private.key"); priKeyPath = getResourcePath("/private.key");
} }
protected String dateMathString(String time, long now) { protected static String dateMathString(String time, long now) {
return dateTimeFormatter.print(dateMathParser.parse(time, now)); return dateTimeFormatter.print(dateMathParser.parse(time, now));
} }
protected long dateMath(String time, long now) { protected static long dateMath(String time, long now) {
return dateMathParser.parse(time, now); return dateMathParser.parse(time, now);
} }
@ -62,13 +64,13 @@ public class AbstractLicensingTestBase {
return getResourcePath("/public.key"); return getResourcePath("/public.key");
} }
private static String getResourcePath(String resource) throws Exception { public static String getResourcePath(String resource) throws Exception {
URL url = ESLicenseManager.class.getResource(resource); URL url = ESLicenseManager.class.getResource(resource);
return url.toURI().getPath(); return url.toURI().getPath();
} }
protected LicenseSpec generateRandomLicenseSpec() { public static LicenseSpec generateRandomLicenseSpec() {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
String issueDate = dateMathString("now", now); String issueDate = dateMathString("now", now);
String expiryDate = dateMathString("now+10d/d", now); String expiryDate = dateMathString("now+10d/d", now);
@ -175,4 +177,16 @@ public class AbstractLicensingTestBase {
this.maxNodes = maxNodes; this.maxNodes = maxNodes;
} }
} }
public static void assertLicenseSpec(LicenseSpec spec, ESLicense license) {
assertThat(license.uid(), equalTo(spec.uid));
assertThat(license.feature(), equalTo(spec.feature));
assertThat(license.issuedTo(), equalTo(spec.issuedTo));
assertThat(license.issuer(), equalTo(spec.issuer));
assertThat(license.type(), equalTo(spec.type));
assertThat(license.subscriptionType(), equalTo(spec.subscriptionType));
assertThat(license.maxNodes(), equalTo(spec.maxNodes));
assertThat(license.issueDate(), equalTo(DateUtils.beginningOfTheDay(spec.issueDate)));
assertThat(license.expiryDate(), equalTo(DateUtils.endOfTheDay(spec.expiryDate)));
}
} }

View File

@ -6,130 +6,200 @@
package org.elasticsearch.license.licensor; package org.elasticsearch.license.licensor;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.elasticsearch.license.AbstractLicensingTestBase; import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.license.TestUtils; import org.elasticsearch.common.cli.CliToolTestCase;
import org.elasticsearch.common.cli.commons.MissingOptionException;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.core.ESLicenses; import org.elasticsearch.license.core.ESLicenses;
import org.elasticsearch.license.licensor.tools.LicenseGeneratorTool; import org.elasticsearch.license.licensor.tools.LicenseGeneratorTool;
import org.junit.BeforeClass;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.*;
import java.util.List;
import java.util.Set;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiOfLength; import static org.elasticsearch.common.cli.CliTool.ExitStatus;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomBoolean; import static org.elasticsearch.license.AbstractLicensingTestBase.*;
import static org.elasticsearch.license.licensor.tools.LicenseGeneratorTool.Command;
import static org.elasticsearch.license.licensor.tools.LicenseGeneratorTool.LicenseGenerator;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
public class LicenseGenerationToolTests extends AbstractLicensingTestBase { public class LicenseGenerationToolTests extends CliToolTestCase {
protected static String pubKeyPath = null;
protected static String priKeyPath = null;
@Rule @Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder(); public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void testSimple() throws Exception {
LicenseSpec inputLicenseSpec = generateRandomLicenseSpec();
String[] args = new String[6];
args[0] = "--license";
args[1] = generateESLicenseSpecString(Arrays.asList(inputLicenseSpec));
args[2] = "--publicKeyPath";
args[3] = pubKeyPath;
args[4] = "--privateKeyPath";
args[5] = priKeyPath;
String licenseOutput = runLicenseGenerationTool(args); @BeforeClass
List<ESLicense> outputLicenses = ESLicenses.fromSource(licenseOutput); public static void setup() throws Exception {
assertThat(outputLicenses.size(), equalTo(1)); pubKeyPath = getResourcePath("/public.key");
assertThat(outputLicenses.get(0).signature(), notNullValue()); priKeyPath = getResourcePath("/private.key");
Set<ESLicense> expectedLicenses = generateSignedLicenses(Arrays.asList(inputLicenseSpec));
ESLicense expectedLicense = ESLicense.builder()
.fromLicenseSpec(expectedLicenses.iterator().next(), outputLicenses.get(0).signature())
.build();
TestUtils.isSame(expectedLicense, outputLicenses.get(0));
} }
@Test @Test
public void testWithLicenseFile() throws Exception { public void testParsingNonExistentKeyFile() throws Exception {
LicenseSpec inputLicenseSpec = generateRandomLicenseSpec(); LicenseSpec inputLicenseSpec = generateRandomLicenseSpec();
LicenseGeneratorTool licenseGeneratorTool = new LicenseGeneratorTool();
boolean invalidPubKeyPath = randomBoolean();
Command command = licenseGeneratorTool.parse(LicenseGeneratorTool.NAME,
args("--license " + generateESLicenseSpecString(Arrays.asList(inputLicenseSpec))
+ " --publicKeyPath " + ((invalidPubKeyPath) ? pubKeyPath.concat("invalid") : pubKeyPath)
+ " --privateKeyPath " + ((!invalidPubKeyPath) ? priKeyPath.concat("invalid") : priKeyPath)));
assertThat(command, instanceOf(Command.Exit.class));
Command.Exit exitCommand = (Command.Exit) command;
assertThat(exitCommand.status(), equalTo(ExitStatus.USAGE));
}
@Test
public void testParsingMissingLicenseSpec() throws Exception {
LicenseGeneratorTool licenseGeneratorTool = new LicenseGeneratorTool();
Command command = licenseGeneratorTool.parse(LicenseGeneratorTool.NAME,
args(" --publicKeyPath " + pubKeyPath
+ " --privateKeyPath " + priKeyPath));
assertThat(command, instanceOf(Command.Exit.class));
Command.Exit exitCommand = (Command.Exit) command;
assertThat(exitCommand.status(), equalTo(ExitStatus.USAGE));
}
@Test
public void testParsingMissingArgs() throws Exception {
LicenseSpec inputLicenseSpec = generateRandomLicenseSpec();
LicenseGeneratorTool licenseGeneratorTool = new LicenseGeneratorTool();
boolean pubKeyMissing = randomBoolean();
try {
licenseGeneratorTool.parse(LicenseGeneratorTool.NAME,
args("--license " + generateESLicenseSpecString(Arrays.asList(inputLicenseSpec))
+ ((!pubKeyMissing) ? " --publicKeyPath " + pubKeyPath : "")
+ ((pubKeyMissing) ? " --privateKeyPath " + priKeyPath : "")));
fail("missing argument: " + ((pubKeyMissing) ? "publicKeyPath" : "privateKeyPath") + " should throw an exception");
} catch (MissingOptionException e) {
assertThat(e.getMessage(), containsString((pubKeyMissing) ? "pub" : "pri"));
}
}
@Test
public void testParsingSimple() throws Exception {
LicenseSpec inputLicenseSpec = generateRandomLicenseSpec();
LicenseGeneratorTool licenseGeneratorTool = new LicenseGeneratorTool();
Command command = licenseGeneratorTool.parse(LicenseGeneratorTool.NAME,
args("--license " + generateESLicenseSpecString(Arrays.asList(inputLicenseSpec))
+ " --publicKeyPath " + pubKeyPath
+ " --privateKeyPath " + priKeyPath));
assertThat(command, instanceOf(LicenseGenerator.class));
LicenseGenerator licenseGenerator = (LicenseGenerator) command;
assertThat(licenseGenerator.publicKeyFilePath, equalTo(pubKeyPath));
assertThat(licenseGenerator.privateKeyFilePath, equalTo(priKeyPath));
assertThat(licenseGenerator.licenseSpecs.size(), equalTo(1));
ESLicense outputLicenseSpec = licenseGenerator.licenseSpecs.iterator().next();
assertLicenseSpec(inputLicenseSpec, outputLicenseSpec);
}
@Test
public void testParsingLicenseFile() throws Exception {
LicenseSpec inputLicenseSpec = generateRandomLicenseSpec();
File tempFile = temporaryFolder.newFile("license_spec.json"); File tempFile = temporaryFolder.newFile("license_spec.json");
FileUtils.write(tempFile, generateESLicenseSpecString(Arrays.asList(inputLicenseSpec))); FileUtils.write(tempFile, generateESLicenseSpecString(Arrays.asList(inputLicenseSpec)));
String[] args = new String[6]; LicenseGeneratorTool licenseGeneratorTool = new LicenseGeneratorTool();
args[0] = "--licenseFile"; Command command = licenseGeneratorTool.parse(LicenseGeneratorTool.NAME,
args[1] = tempFile.getAbsolutePath(); args("--licenseFile " + tempFile.getAbsolutePath()
args[2] = "--publicKeyPath"; + " --publicKeyPath " + pubKeyPath
args[3] = pubKeyPath; + " --privateKeyPath " + priKeyPath));
args[4] = "--privateKeyPath";
args[5] = priKeyPath;
String licenseOutput = runLicenseGenerationTool(args); assertThat(command, instanceOf(LicenseGenerator.class));
List<ESLicense> outputLicenses = ESLicenses.fromSource(licenseOutput); LicenseGenerator licenseGenerator = (LicenseGenerator) command;
assertThat(outputLicenses.size(), equalTo(1)); assertThat(licenseGenerator.publicKeyFilePath, equalTo(pubKeyPath));
assertThat(outputLicenses.get(0).signature(), notNullValue()); assertThat(licenseGenerator.privateKeyFilePath, equalTo(priKeyPath));
assertThat(licenseGenerator.licenseSpecs.size(), equalTo(1));
ESLicense outputLicenseSpec = licenseGenerator.licenseSpecs.iterator().next();
Set<ESLicense> expectedLicenses = generateSignedLicenses(Arrays.asList(inputLicenseSpec)); assertLicenseSpec(inputLicenseSpec, outputLicenseSpec);
ESLicense expectedLicense = ESLicense.builder()
.fromLicenseSpec(expectedLicenses.iterator().next(), outputLicenses.get(0).signature())
.build();
TestUtils.isSame(expectedLicense, outputLicenses.get(0));
} }
@Test @Test
public void testBadKeyPath() throws Exception { public void testParsingMultipleLicense() throws Exception {
boolean pubKey = randomBoolean(); int n = randomIntBetween(2, 5);
List<LicenseSpec> inputLicenseSpecs = new ArrayList<>();
String[] args = new String[6]; for (int i = 0; i < n; i++) {
args[0] = "--license"; inputLicenseSpecs.add(generateRandomLicenseSpec());
args[1] = generateESLicenseSpecString(Arrays.asList(generateRandomLicenseSpec()));
args[2] = "--publicKeyPath";
args[3] = (pubKey) ? pubKeyPath + randomAsciiOfLength(3) : pubKeyPath;
args[4] = "--privateKeyPath";
args[5] = (!pubKey) ? priKeyPath + randomAsciiOfLength(3) : priKeyPath;
try {
runLicenseGenerationTool(args);
fail("Should not accept non-existent key paths");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("does not exist"));
} }
LicenseGeneratorTool licenseGeneratorTool = new LicenseGeneratorTool();
Command command = licenseGeneratorTool.parse(LicenseGeneratorTool.NAME,
args("--license " + generateESLicenseSpecString(inputLicenseSpecs)
+ " --publicKeyPath " + pubKeyPath
+ " --privateKeyPath " + priKeyPath));
assertThat(command, instanceOf(LicenseGenerator.class));
LicenseGenerator licenseGenerator = (LicenseGenerator) command;
assertThat(licenseGenerator.publicKeyFilePath, equalTo(pubKeyPath));
assertThat(licenseGenerator.privateKeyFilePath, equalTo(priKeyPath));
assertThat(licenseGenerator.licenseSpecs.size(), equalTo(n));
for (LicenseSpec inputSpec : inputLicenseSpecs) {
boolean found = false;
for (ESLicense outputSpec : licenseGenerator.licenseSpecs) {
if (inputSpec.uid.equals(outputSpec.uid())) {
assertLicenseSpec(inputSpec, outputSpec);
found = true;
break;
}
}
assertThat(found, equalTo(true));
}
} }
@Test @Test
public void testMissingCLTArgs() throws Exception { public void testTool() throws Exception {
String[] args = new String[6]; int n = randomIntBetween(1, 5);
args[0] = "--linse"; List<LicenseSpec> inputLicenseSpecs = new ArrayList<>();
args[1] = generateESLicenseSpecString(Arrays.asList(generateRandomLicenseSpec())); for (int i = 0; i < n; i++) {
args[2] = "--publicKeyPath"; inputLicenseSpecs.add(generateRandomLicenseSpec());
args[3] = pubKeyPath; }
args[4] = "--privateKeyPath"; List<ESLicense> licenseSpecs = ESLicenses.fromSource(generateESLicenseSpecString(inputLicenseSpecs).getBytes(StandardCharsets.UTF_8), false);
args[5] = priKeyPath;
try { String output = runLicenseGenerationTool(pubKeyPath, priKeyPath, new HashSet<>(licenseSpecs), ExitStatus.OK);
runLicenseGenerationTool(args); List<ESLicense> outputLicenses = ESLicenses.fromSource(output.getBytes(StandardCharsets.UTF_8), true);
fail("should not accept arguments without --license"); assertThat(outputLicenses.size(), equalTo(n));
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("'--license'")); for (LicenseSpec inputSpec : inputLicenseSpecs) {
boolean found = false;
for (ESLicense license : outputLicenses) {
if (inputSpec.uid.equals(license.uid())) {
assertLicenseSpec(inputSpec, license);
found = true;
break;
}
}
assertThat(found, equalTo(true));
} }
} }
private String runLicenseGenerationTool(String[] args) throws Exception { private String runLicenseGenerationTool(String pubKeyPath, String priKeyPath, Set<ESLicense> licenseSpecs, ExitStatus expectedExitStatus) throws Exception {
File temp = temporaryFolder.newFile("license_generator.out"); CaptureOutputTerminal outputTerminal = new CaptureOutputTerminal();
try (FileOutputStream outputStream = new FileOutputStream(temp)) { LicenseGenerator licenseGenerator = new LicenseGenerator(outputTerminal, pubKeyPath, priKeyPath, licenseSpecs);
LicenseGeneratorTool.run(args, outputStream); assertThat(execute(licenseGenerator, ImmutableSettings.EMPTY), equalTo(expectedExitStatus));
} assertThat(outputTerminal.getTerminalOutput().size(), equalTo(1));
return FileUtils.readFileToString(temp); return outputTerminal.getTerminalOutput().get(0);
}
private ExitStatus execute(CliTool.Command cmd, Settings settings) throws Exception {
Environment env = new Environment(settings);
return cmd.execute(settings, env);
} }
} }

View File

@ -70,19 +70,7 @@ public class LicenseSerializationTests extends AbstractLicensingTestBase {
for (ESLicense license : esLicensesOutput) { for (ESLicense license : esLicensesOutput) {
LicenseSpec spec = licenseSpecs.get(license.feature()); LicenseSpec spec = licenseSpecs.get(license.feature());
assertThat(spec, notNullValue()); assertThat(spec, notNullValue());
assertLicenseSpec(spec, license);
assertThat(license.uid(), equalTo(spec.uid));
assertThat(license.feature(), equalTo(spec.feature));
assertThat(license.issuedTo(), equalTo(spec.issuedTo));
assertThat(license.issuer(), equalTo(spec.issuer));
assertThat(license.type(), equalTo(spec.type));
assertThat(license.subscriptionType(), equalTo(spec.subscriptionType));
assertThat(license.maxNodes(), equalTo(spec.maxNodes));
assertThat(license.issueDate(), equalTo(DateUtils.beginningOfTheDay(spec.issueDate)));
assertThat(license.expiryDate(), equalTo(DateUtils.endOfTheDay(spec.expiryDate)));
} }
} }
} }

View File

@ -6,12 +6,15 @@
package org.elasticsearch.license.licensor; package org.elasticsearch.license.licensor;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.elasticsearch.common.cli.CliToolTestCase;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.AbstractLicensingTestBase; import org.elasticsearch.env.Environment;
import org.elasticsearch.license.TestUtils; import org.elasticsearch.license.TestUtils;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.core.ESLicenses; import org.elasticsearch.license.core.ESLicenses;
@ -21,117 +24,166 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.nio.charset.StandardCharsets;
import java.io.IOException; import java.util.Collections;
import java.util.*; import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomIntBetween; import static org.elasticsearch.common.cli.CliTool.Command;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomRealisticUnicodeOfCodepointLengthBetween; import static org.elasticsearch.common.cli.CliTool.ExitStatus;
import static org.hamcrest.CoreMatchers.containsString; import static org.elasticsearch.license.AbstractLicensingTestBase.generateSignedLicense;
import static org.elasticsearch.license.licensor.tools.LicenseVerificationTool.LicenseVerifier;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
public class LicenseVerificationToolTests extends AbstractLicensingTestBase { public class LicenseVerificationToolTests extends CliToolTestCase {
@Rule @Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder(); public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test @Test
public void testMissingCLTArgs() throws Exception { public void testParsingMissingLicense() throws Exception {
ESLicense singedLicense = generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15), LicenseVerificationTool licenseVerificationTool = new LicenseVerificationTool();
TimeValue.timeValueHours(1)); Command command = licenseVerificationTool.parse(LicenseVerificationTool.NAME, args(""));
String[] args = new String[2]; assertThat(command, instanceOf(Command.Exit.class));
args[0] = "--licenssFiles"; Command.Exit exitCommand = (Command.Exit) command;
args[1] = dumpLicense(singedLicense); assertThat(exitCommand.status(), equalTo(ExitStatus.USAGE));
try {
runLicenseVerificationTool(args);
fail("mandatory param '--licensesFiles' should throw an exception");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("--licensesFiles"));
}
} }
@Test @Test
public void testSimple() throws Exception { public void testParsingSimple() throws Exception {
ESLicense singedLicense = generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15), ESLicense inputLicense = generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15),
TimeValue.timeValueHours(1)); TimeValue.timeValueHours(1));
LicenseVerificationTool licenseVerificationTool = new LicenseVerificationTool();
String[] args = new String[2]; Command command = licenseVerificationTool.parse(LicenseVerificationTool.NAME,
args[0] = "--licensesFiles"; args("--license " + dumpLicense(inputLicense)));
args[1] = dumpLicense(singedLicense); assertThat(command, instanceOf(LicenseVerifier.class));
LicenseVerifier licenseVerifier = (LicenseVerifier) command;
String licenseOutput = runLicenseVerificationTool(args); assertThat(licenseVerifier.licenses.size(), equalTo(1));
List<ESLicense> licensesOutput = ESLicenses.fromSource(licenseOutput); ESLicense outputLicense = licenseVerifier.licenses.iterator().next();
TestUtils.isSame(inputLicense, outputLicense);
assertThat(licensesOutput.size(), equalTo(1));
ESLicense expectedLicense = ESLicense.builder()
.fromLicenseSpec(singedLicense, licensesOutput.get(0).signature())
.build();
TestUtils.isSame(expectedLicense, licensesOutput.get(0));
} }
@Test @Test
public void testWithLicenseFiles() throws Exception { public void testParsingLicenseFile() throws Exception {
int n = randomIntBetween(3, 10); ESLicense inputLicense = generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15),
Set<ESLicense> signedLicenses = new HashSet<>(); TimeValue.timeValueHours(1));
LicenseVerificationTool licenseVerificationTool = new LicenseVerificationTool();
Command command = licenseVerificationTool.parse(LicenseVerificationTool.NAME,
args("--licenseFile " + dumpLicenseAsFile(inputLicense)));
assertThat(command, instanceOf(LicenseVerifier.class));
LicenseVerifier licenseVerifier = (LicenseVerifier) command;
assertThat(licenseVerifier.licenses.size(), equalTo(1));
ESLicense outputLicense = licenseVerifier.licenses.iterator().next();
TestUtils.isSame(inputLicense, outputLicense);
}
@Test
public void testParsingMultipleLicense() throws Exception {
int n = randomIntBetween(2, 5);
Set<ESLicense> inputLicenses = new HashSet<>();
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
signedLicenses.add(generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15), inputLicenses.add(generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15),
TimeValue.timeValueHours(1))); TimeValue.timeValueHours(1)));
} }
StringBuilder licenseFilePathString = new StringBuilder(); StringBuilder argsBuilder = new StringBuilder();
ESLicense[] esLicenses = signedLicenses.toArray(new ESLicense[n]); for (ESLicense inputLicense : inputLicenses) {
for (int i = 0; i < n; i++) { argsBuilder.append(" --license ")
licenseFilePathString.append(dumpLicense(esLicenses[i])); .append(dumpLicense(inputLicense));
if (i != esLicenses.length - 1) { }
licenseFilePathString.append(":"); LicenseVerificationTool licenseVerificationTool = new LicenseVerificationTool();
Command command = licenseVerificationTool.parse(LicenseVerificationTool.NAME, args(argsBuilder.toString()));
assertThat(command, instanceOf(LicenseVerifier.class));
LicenseVerifier licenseVerifier = (LicenseVerifier) command;
assertThat(licenseVerifier.licenses.size(), equalTo(n));
for (ESLicense inputLicense : inputLicenses) {
boolean found = false;
for (ESLicense outputLicense : licenseVerifier.licenses) {
if (inputLicense.uid().equals(outputLicense.uid())) {
TestUtils.isSame(inputLicense, outputLicense);
found = true;
break;
}
} }
assertThat(found, equalTo(true));
}
}
@Test
public void testToolSimple() throws Exception {
int n = randomIntBetween(2, 5);
Set<ESLicense> inputLicenses = new HashSet<>();
for (int i = 0; i < n; i++) {
inputLicenses.add(generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15),
TimeValue.timeValueHours(1)));
} }
String[] args = new String[2]; String output = runLicenseVerificationTool(inputLicenses, ExitStatus.OK);
args[0] = "--licensesFiles"; List<ESLicense> outputLicenses = ESLicenses.fromSource(output.getBytes(StandardCharsets.UTF_8), true);
args[1] = licenseFilePathString.toString(); assertThat(outputLicenses.size(), equalTo(n));
String licenseOutput = runLicenseVerificationTool(args); for (ESLicense inputLicense : inputLicenses) {
List<ESLicense> output = ESLicenses.fromSource(licenseOutput); boolean found = false;
for (ESLicense outputLicense : outputLicenses) {
assertThat(output.size(), equalTo(n)); if (inputLicense.uid().equals(outputLicense.uid())) {
TestUtils.isSame(inputLicense, outputLicense);
Set<ESLicense> licensesOutput = new HashSet<>(); found = true;
Map<String, ESLicense> expectedLicenses = ESLicenses.reduceAndMap(signedLicenses); break;
for (ESLicense license : output) { }
licensesOutput.add( }
ESLicense.builder() assertThat(found, equalTo(true));
.fromLicenseSpec(license, expectedLicenses.get(license.feature()).signature())
.build()
);
} }
}
TestUtils.isSame(signedLicenses, licensesOutput); @Test
public void testToolInvalidLicense() throws Exception {
ESLicense signedLicense = generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15)
, TimeValue.timeValueHours(1));
ESLicense tamperedLicense = ESLicense.builder()
.fromLicenseSpec(signedLicense, signedLicense.signature())
.expiryDate(signedLicense.expiryDate() + randomIntBetween(1, 1000)).build();
runLicenseVerificationTool(Collections.singleton(tamperedLicense), ExitStatus.DATA_ERROR);
}
private String dumpLicenseAsFile(ESLicense license) throws Exception {
File tempFile = temporaryFolder.newFile();
FileUtils.write(tempFile, dumpLicense(license));
return tempFile.getAbsolutePath();
} }
private String dumpLicense(ESLicense license) throws Exception { private String dumpLicense(ESLicense license) throws Exception {
File tempFile = temporaryFolder.newFile("licenses.json"); XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
try (FileOutputStream outputStream = new FileOutputStream(tempFile)) { ESLicenses.toXContent(Collections.singletonList(license), builder, ToXContent.EMPTY_PARAMS);
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON, outputStream); builder.flush();
ESLicenses.toXContent(Collections.singletonList(license), builder, ToXContent.EMPTY_PARAMS); return builder.string();
builder.flush();
}
return tempFile.getAbsolutePath();
} }
private String runLicenseVerificationTool(String[] args) throws IOException { private String runLicenseVerificationTool(Set<ESLicense> licenses, ExitStatus expectedExitStatus) throws Exception {
File tempFile = temporaryFolder.newFile("licence_verification.out"); CaptureOutputTerminal outputTerminal = new CaptureOutputTerminal();
try (FileOutputStream outputStream = new FileOutputStream(tempFile)) { LicenseVerifier licenseVerifier = new LicenseVerifier(outputTerminal, licenses);
LicenseVerificationTool.run(args, outputStream); assertThat(execute(licenseVerifier, ImmutableSettings.EMPTY), equalTo(expectedExitStatus));
if (expectedExitStatus == ExitStatus.OK) {
assertThat(outputTerminal.getTerminalOutput().size(), equalTo(1));
return outputTerminal.getTerminalOutput().get(0);
} else {
return null;
} }
return FileUtils.readFileToString(tempFile); }
private ExitStatus execute(Command cmd, Settings settings) throws Exception {
Environment env = new Environment(settings);
return cmd.execute(settings, env);
} }
} }