First round of refactoring
ESLicenceManager is no longer a static singleton Original commit: elastic/x-pack-elasticsearch@3e46f315a1
This commit is contained in:
parent
8367fc43d5
commit
9f84847681
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.license.licensor.tools;
|
||||||
|
|
||||||
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
|
import org.elasticsearch.license.core.LicenseBuilders;
|
||||||
|
import org.elasticsearch.license.manager.ESLicenseProvider;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class FileBasedESLicenseProvider implements ESLicenseProvider {
|
||||||
|
private ESLicenses esLicenses;
|
||||||
|
|
||||||
|
public FileBasedESLicenseProvider(ESLicenses esLicenses) {
|
||||||
|
this.esLicenses = esLicenses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileBasedESLicenseProvider(Set<ESLicenses> esLicensesSet) {
|
||||||
|
this(merge(esLicensesSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ESLicenses.ESLicense getESLicense(ESLicenses.FeatureType featureType) {
|
||||||
|
return esLicenses.get(featureType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ESLicenses getEffectiveLicenses() {
|
||||||
|
return esLicenses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing
|
||||||
|
public void setLicenses(ESLicenses esLicenses) {
|
||||||
|
this.esLicenses = esLicenses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ESLicenses merge(Set<ESLicenses> esLicensesSet) {
|
||||||
|
ESLicenses mergedLicenses = null;
|
||||||
|
for (ESLicenses licenses : esLicensesSet) {
|
||||||
|
mergedLicenses = LicenseBuilders.merge(mergedLicenses, licenses);
|
||||||
|
}
|
||||||
|
return mergedLicenses;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.license.licensor.tools;
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.core.LicenseUtils;
|
import org.elasticsearch.license.core.LicenseUtils;
|
||||||
import org.elasticsearch.license.manager.ESLicenseManager;
|
import org.elasticsearch.license.manager.ESLicenseManager;
|
||||||
|
import org.elasticsearch.license.manager.ESLicenseProvider;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -95,7 +96,8 @@ public class LicenseVerificationTool {
|
||||||
Options options = parse(args);
|
Options options = parse(args);
|
||||||
|
|
||||||
// verify licenses
|
// verify licenses
|
||||||
ESLicenseManager licenseManager = ESLicenseManager.createLocalBasedInstance(options.licenses, options.publicKeyFilePath);
|
ESLicenseProvider licenseProvider = new FileBasedESLicenseProvider(options.licenses);
|
||||||
|
ESLicenseManager licenseManager = new ESLicenseManager(licenseProvider);
|
||||||
licenseManager.verifyLicenses();
|
licenseManager.verifyLicenses();
|
||||||
|
|
||||||
// dump effective licences
|
// dump effective licences
|
||||||
|
|
|
@ -11,21 +11,16 @@ import net.nicholaswilliams.java.licensing.encryption.Hasher;
|
||||||
import net.nicholaswilliams.java.licensing.encryption.PasswordProvider;
|
import net.nicholaswilliams.java.licensing.encryption.PasswordProvider;
|
||||||
import net.nicholaswilliams.java.licensing.exception.ExpiredLicenseException;
|
import net.nicholaswilliams.java.licensing.exception.ExpiredLicenseException;
|
||||||
import net.nicholaswilliams.java.licensing.exception.InvalidLicenseException;
|
import net.nicholaswilliams.java.licensing.exception.InvalidLicenseException;
|
||||||
import org.elasticsearch.cluster.ClusterService;
|
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.core.LicenseBuilders;
|
import org.elasticsearch.license.core.LicenseBuilders;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.elasticsearch.license.core.ESLicenses.*;
|
import static org.elasticsearch.license.core.ESLicenses.*;
|
||||||
import static org.elasticsearch.license.manager.ESLicenseProvider.ClusterStateLicenseProvider;
|
import static org.elasticsearch.license.manager.Utils.extractSignedLicence;
|
||||||
import static org.elasticsearch.license.manager.ESLicenseProvider.FileBasedESLicenseProvider;
|
|
||||||
import static org.elasticsearch.license.manager.ESLicenseProvider.extractSignedLicence;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class responsible for reading signed licenses, maintaining an effective esLicenses instance, verification of licenses
|
* Class responsible for reading signed licenses, maintaining an effective esLicenses instance, verification of licenses
|
||||||
|
@ -36,65 +31,24 @@ import static org.elasticsearch.license.manager.ESLicenseProvider.extractSignedL
|
||||||
*/
|
*/
|
||||||
public class ESLicenseManager {
|
public class ESLicenseManager {
|
||||||
|
|
||||||
private static ESLicenseManager instance = null;
|
|
||||||
private static FilePublicKeyDataProvider publicKeyDataProvider;
|
|
||||||
private final ESLicenseProvider licenseProvider;
|
private final ESLicenseProvider licenseProvider;
|
||||||
|
|
||||||
private final LicenseManager licenseManager;
|
private final LicenseManager licenseManager;
|
||||||
|
|
||||||
public static ESLicenseManager getInstance() {
|
// Initialize LicenseManager
|
||||||
if (ESLicenseManager.instance == null) {
|
static {
|
||||||
throw new IllegalStateException("License manager has not been created!");
|
LicenseManagerProperties.setPublicKeyDataProvider(new FilePublicKeyDataProvider(getPublicKeyPath()));
|
||||||
}
|
LicenseManagerProperties.setPublicKeyPasswordProvider(new ESPublicKeyPasswordProvider());
|
||||||
return ESLicenseManager.instance;
|
LicenseManagerProperties.setLicenseProvider(new LicenseProvider() {
|
||||||
}
|
@Override
|
||||||
|
public SignedLicense getLicense(Object context) {
|
||||||
/**
|
throw new UnsupportedOperationException("This singelton license provider shouldn't be used");
|
||||||
* Creates a LicenseManager instance where the Licenses are queried from the cluster state
|
}
|
||||||
*
|
});
|
||||||
* @param clusterService used to query for appropriate license(s) for validation
|
|
||||||
* @param publicKeyPath used to decrypt the licenses
|
|
||||||
* @return {@link org.elasticsearch.license.manager.ESLicenseManager} instance backed by licenses residing
|
|
||||||
* in the cluster state
|
|
||||||
*/
|
|
||||||
public static ESLicenseManager createClusterStateBasedInstance(ClusterService clusterService, String publicKeyPath) {
|
|
||||||
if (ESLicenseManager.instance == null) {
|
|
||||||
ESLicenseManager.publicKeyDataProvider = new FilePublicKeyDataProvider(publicKeyPath);
|
|
||||||
instance = new ESLicenseManager(ESLicenseProvider.createClusterBasedLicenseProvider(clusterService, publicKeyPath));
|
|
||||||
return instance;
|
|
||||||
} else if (ESLicenseManager.instance.licenseProvider instanceof ClusterStateLicenseProvider) {
|
|
||||||
return ESLicenseManager.instance;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Manager already initiated with File based license provider");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ESLicenseManager createClusterStateBasedInstance(ClusterService clusterService) {
|
|
||||||
return createClusterStateBasedInstance(clusterService, getPublicKeyPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ESLicenseManager createLocalBasedInstance(ESLicenses esLicenses, String publicKeyPath) {
|
|
||||||
return createLocalBasedInstance(Collections.singleton(esLicenses), publicKeyPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a LicenseManager instance where the Licenses are queried from a set of pre-generated licenses
|
|
||||||
* @param esLicensesSet a set of pre-generated licenses stored in the license manager
|
|
||||||
* @param publicKeyPath used to decrypt the licenses
|
|
||||||
* @return {@link org.elasticsearch.license.manager.ESLicenseManager} instance backed by pre-generated licenses
|
|
||||||
*/
|
|
||||||
public static ESLicenseManager createLocalBasedInstance(Set<ESLicenses> esLicensesSet, String publicKeyPath) {
|
|
||||||
if (ESLicenseManager.instance == null) {
|
|
||||||
ESLicenseManager.publicKeyDataProvider = new FilePublicKeyDataProvider(publicKeyPath);
|
|
||||||
return new ESLicenseManager(ESLicenseProvider.createFileBasedLicenseProvider(merge(esLicensesSet), publicKeyPath));
|
|
||||||
} else if (ESLicenseManager.instance.licenseProvider instanceof FileBasedESLicenseProvider) {
|
|
||||||
return ESLicenseManager.instance;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Manager already initiated with Cluster state based license provider");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getPublicKeyPath() {
|
private static String getPublicKeyPath() {
|
||||||
|
//TODO: Imporove key management
|
||||||
URL resource = ESLicenseManager.class.getResource("public.key");
|
URL resource = ESLicenseManager.class.getResource("public.key");
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
//test REMOVE NOCOMMIT!!!!
|
//test REMOVE NOCOMMIT!!!!
|
||||||
|
@ -107,11 +61,7 @@ public class ESLicenseManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ESLicenseManager(ESLicenseProvider licenseProvider) {
|
public ESLicenseManager(ESLicenseProvider licenseProvider) {
|
||||||
LicenseManagerProperties.setLicenseProvider(licenseProvider);
|
|
||||||
LicenseManagerProperties.setPublicKeyDataProvider(publicKeyDataProvider);
|
|
||||||
LicenseManagerProperties.setLicenseValidator(new DefaultLicenseValidator());
|
|
||||||
LicenseManagerProperties.setPublicKeyPasswordProvider(new ESPublicKeyPasswordProvider());
|
|
||||||
this.licenseProvider = licenseProvider;
|
this.licenseProvider = licenseProvider;
|
||||||
this.licenseManager = LicenseManager.getInstance();
|
this.licenseManager = LicenseManager.getInstance();
|
||||||
}
|
}
|
||||||
|
@ -134,9 +84,7 @@ public class ESLicenseManager {
|
||||||
ESLicense esLicense = esLicenses.get(featureType);
|
ESLicense esLicense = esLicenses.get(featureType);
|
||||||
// verify signature
|
// verify signature
|
||||||
final License license = this.licenseManager.decryptAndVerifyLicense(
|
final License license = this.licenseManager.decryptAndVerifyLicense(
|
||||||
extractSignedLicence(
|
extractSignedLicence(esLicense.signature()));
|
||||||
esLicense.signature(),
|
|
||||||
publicKeyDataProvider.getPublicKeyFile().getAbsolutePath()));
|
|
||||||
// validate license
|
// validate license
|
||||||
this.licenseManager.validateLicense(license);
|
this.licenseManager.validateLicense(license);
|
||||||
|
|
||||||
|
@ -147,9 +95,6 @@ public class ESLicenseManager {
|
||||||
throw new InvalidLicenseException("Expired License");
|
throw new InvalidLicenseException("Expired License");
|
||||||
} catch (InvalidLicenseException e) {
|
} catch (InvalidLicenseException e) {
|
||||||
throw new InvalidLicenseException("Invalid License");
|
throw new InvalidLicenseException("Invalid License");
|
||||||
} catch (IOException e) {
|
|
||||||
// bogus
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +102,27 @@ public class ESLicenseManager {
|
||||||
verifyLicenses(getEffectiveLicenses());
|
verifyLicenses(getEffectiveLicenses());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ESLicenses fromSignaturesAsIs(final Set<String> signatures) {
|
||||||
|
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
|
||||||
|
for (String signature : signatures) {
|
||||||
|
licensesBuilder.licenseAsIs(getESLicenseFromSignature(signature));
|
||||||
|
}
|
||||||
|
return licensesBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ESLicense getESLicenseFromSignature(String signature) {
|
||||||
|
SignedLicense signedLicense = extractSignedLicence(signature);
|
||||||
|
return decryptAndVerifyESLicense(signedLicense, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ESLicenses fromSignatures(final Set<String> signatures) {
|
||||||
|
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
|
||||||
|
for (String signature : signatures) {
|
||||||
|
licensesBuilder.license(getESLicenseFromSignature(signature));
|
||||||
|
}
|
||||||
|
return licensesBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
private static void verifyLicenseFields(License license, ESLicense eslicense) {
|
private static void verifyLicenseFields(License license, ESLicense eslicense) {
|
||||||
boolean licenseValid = license.getProductKey().equals(eslicense.uid())
|
boolean licenseValid = license.getProductKey().equals(eslicense.uid())
|
||||||
&& license.getHolder().equals(eslicense.issuedTo())
|
&& license.getHolder().equals(eslicense.issuedTo())
|
||||||
|
@ -194,13 +160,22 @@ public class ESLicenseManager {
|
||||||
throw new InvalidLicenseException("Invalid License");
|
throw new InvalidLicenseException("Invalid License");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private License getLicense(FeatureType featureType) {
|
||||||
|
ESLicense esLicense = licenseProvider.getESLicense(featureType);
|
||||||
|
if (esLicense != null) {
|
||||||
|
String signature = esLicense.signature();
|
||||||
|
License license = this.licenseManager.decryptAndVerifyLicense(extractSignedLicence(signature));
|
||||||
|
this.licenseManager.validateLicense(license);
|
||||||
|
return license;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
//TODO wrap License validation methods so a plugin does not have to provide featureType param
|
//TODO wrap License validation methods so a plugin does not have to provide featureType param
|
||||||
|
|
||||||
public boolean hasLicenseForFeature(FeatureType featureType) {
|
public boolean hasLicenseForFeature(FeatureType featureType) {
|
||||||
try {
|
try {
|
||||||
final License license = licenseManager.getLicense(featureType);
|
final License license = getLicense(featureType);
|
||||||
if (license != null) {
|
if (license != null) {
|
||||||
return license.hasLicenseForFeature(featureType.string());
|
return license.hasLicenseForFeature(featureType.string());
|
||||||
}
|
}
|
||||||
|
@ -218,22 +193,22 @@ public class ESLicenseManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIssuerForLicense(FeatureType featureType) {
|
public String getIssuerForLicense(FeatureType featureType) {
|
||||||
final License license = licenseManager.getLicense(featureType);
|
final License license = getLicense(featureType);
|
||||||
return license.getIssuer();
|
return license.getIssuer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getIssueDateForLicense(FeatureType featureType) {
|
public long getIssueDateForLicense(FeatureType featureType) {
|
||||||
final License license = licenseManager.getLicense(featureType);
|
final License license = getLicense(featureType);
|
||||||
return license.getIssueDate();
|
return license.getIssueDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getExpiryDateForLicense(FeatureType featureType) {
|
public long getExpiryDateForLicense(FeatureType featureType) {
|
||||||
final License license = licenseManager.getLicense(featureType);
|
final License license = getLicense(featureType);
|
||||||
return license.getGoodBeforeDate();
|
return license.getGoodBeforeDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIssuedToForLicense(FeatureType featureType) {
|
public String getIssuedToForLicense(FeatureType featureType) {
|
||||||
final License license = licenseManager.getLicense(featureType);
|
final License license = getLicense(featureType);
|
||||||
return license.getHolder();
|
return license.getHolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +223,7 @@ public class ESLicenseManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
ESLicense getESLicense(FeatureType featureType) {
|
ESLicense getESLicense(FeatureType featureType) {
|
||||||
final License license = licenseManager.getLicense(featureType);
|
final License license = getLicense(featureType);
|
||||||
return convertToESLicense(license);
|
return convertToESLicense(license);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,14 +267,7 @@ public class ESLicenseManager {
|
||||||
return licenseBuilder.build();
|
return licenseBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Need a better password management
|
||||||
// only for testing
|
|
||||||
public void clearAndAddLicenses(ESLicenses licenses) {
|
|
||||||
this.licenseManager.clearLicenseCache();
|
|
||||||
assert this.licenseProvider instanceof FileBasedESLicenseProvider;
|
|
||||||
this.licenseProvider.addLicenses(licenses);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ESPublicKeyPasswordProvider implements PasswordProvider {
|
private static class ESPublicKeyPasswordProvider implements PasswordProvider {
|
||||||
private final String DEFAULT_PASS_PHRASE = "elasticsearch-license";
|
private final String DEFAULT_PASS_PHRASE = "elasticsearch-license";
|
||||||
|
|
||||||
|
|
|
@ -5,184 +5,14 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.license.manager;
|
package org.elasticsearch.license.manager;
|
||||||
|
|
||||||
import net.nicholaswilliams.java.licensing.LicenseProvider;
|
|
||||||
import net.nicholaswilliams.java.licensing.ObjectSerializer;
|
|
||||||
import net.nicholaswilliams.java.licensing.SignedLicense;
|
|
||||||
import net.nicholaswilliams.java.licensing.encryption.Hasher;
|
|
||||||
import net.nicholaswilliams.java.licensing.exception.InvalidLicenseException;
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
import org.elasticsearch.cluster.ClusterService;
|
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.core.LicenseBuilders;
|
|
||||||
import org.elasticsearch.license.plugin.core.LicensesMetaData;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static org.elasticsearch.license.core.ESLicenses.ESLicense;
|
import static org.elasticsearch.license.core.ESLicenses.ESLicense;
|
||||||
import static org.elasticsearch.license.core.ESLicenses.FeatureType;
|
import static org.elasticsearch.license.core.ESLicenses.FeatureType;
|
||||||
|
|
||||||
public abstract class ESLicenseProvider implements LicenseProvider {
|
public interface ESLicenseProvider {
|
||||||
|
|
||||||
/**
|
ESLicense getESLicense(FeatureType featureType);
|
||||||
* Factory for {@link org.elasticsearch.license.manager.ESLicenseProvider.ClusterStateLicenseProvider}
|
|
||||||
*/
|
|
||||||
public static ESLicenseProvider createClusterBasedLicenseProvider(ClusterService clusterService, String publicKeyPath) {
|
|
||||||
return new ClusterStateLicenseProvider(clusterService, publicKeyPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
ESLicenses getEffectiveLicenses();
|
||||||
* Factory for {@link org.elasticsearch.license.manager.ESLicenseProvider.FileBasedESLicenseProvider}
|
|
||||||
*/
|
|
||||||
public static ESLicenseProvider createFileBasedLicenseProvider(ESLicenses esLicenses, String publicKeyPath) {
|
|
||||||
return new FileBasedESLicenseProvider(esLicenses, publicKeyPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract ESLicense getESLicense(FeatureType featureType);
|
|
||||||
|
|
||||||
public abstract ESLicenses getEffectiveLicenses();
|
|
||||||
|
|
||||||
// only for testing
|
|
||||||
public abstract void addLicenses(ESLicenses esLicenses);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LicenseProvider backed by the current cluster state
|
|
||||||
* Uses the clusterService to query for the latest licenses
|
|
||||||
* for {@link org.elasticsearch.license.manager.ESLicenseManager}
|
|
||||||
* consumption
|
|
||||||
*/
|
|
||||||
public static class ClusterStateLicenseProvider extends ESLicenseProvider {
|
|
||||||
private final ClusterService clusterService;
|
|
||||||
private final String publicKeyPath;
|
|
||||||
|
|
||||||
private ClusterStateLicenseProvider(ClusterService clusterService, String publicKeyPath) {
|
|
||||||
this.clusterService = clusterService;
|
|
||||||
this.publicKeyPath = publicKeyPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ESLicenses getLicensesFromClusterState() {
|
|
||||||
final ClusterState state = clusterService.state();
|
|
||||||
LicensesMetaData metaData = state.metaData().custom(LicensesMetaData.TYPE);
|
|
||||||
if (metaData != null) {
|
|
||||||
return Utils.fromSignatures(metaData.getSignatures());
|
|
||||||
}
|
|
||||||
return LicenseBuilders.licensesBuilder().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ESLicenses getESLicenses() {
|
|
||||||
return getLicensesFromClusterState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SignedLicense getLicense(Object context) {
|
|
||||||
assert context instanceof FeatureType;
|
|
||||||
FeatureType featureType = (FeatureType) context;
|
|
||||||
final ESLicenses licenses = getLicensesFromClusterState();
|
|
||||||
final ESLicense esLicense = licenses.get(featureType);
|
|
||||||
if (esLicense == null) {
|
|
||||||
throw new InvalidLicenseException("Invalid License");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return extractSignedLicence(esLicense.signature(), publicKeyPath);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ESLicense getESLicense(FeatureType featureType) {
|
|
||||||
return getLicensesFromClusterState().get(featureType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ESLicenses getEffectiveLicenses() {
|
|
||||||
return getLicensesFromClusterState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addLicenses(ESLicenses esLicenses) {
|
|
||||||
throw new UnsupportedOperationException("Licenses can only be added by updating the cluster state");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract a signedLicense (SIGNED_LICENSE_CONTENT) from the signature.
|
|
||||||
* Validates the public key used to decrypt the license by comparing their hashes
|
|
||||||
* <p/>
|
|
||||||
* Signature structure:
|
|
||||||
* | MAGIC | HEADER_LENGTH | VERSION | PUB_KEY_DIGEST | SIGNED_LICENSE_CONTENT |
|
|
||||||
*
|
|
||||||
* @param signature of a single license
|
|
||||||
* @param publicKeyPath location of the public key used to decode the signature
|
|
||||||
* @return signed license content for the license
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
static SignedLicense extractSignedLicence(String signature, String publicKeyPath) throws IOException {
|
|
||||||
byte[] signatureBytes = Base64.decodeBase64(signature);
|
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(signatureBytes);
|
|
||||||
byteBuffer = (ByteBuffer) byteBuffer.position(13);
|
|
||||||
int start = byteBuffer.getInt();
|
|
||||||
int version = byteBuffer.getInt();
|
|
||||||
byte[] hash = new byte[start - 13 - 4 - 4];
|
|
||||||
byteBuffer.get(hash);
|
|
||||||
|
|
||||||
final byte[] computedHash = Hasher.hash(Base64.encodeBase64String(
|
|
||||||
Files.readAllBytes(Paths.get(publicKeyPath))
|
|
||||||
)).getBytes(Charset.forName("UTF-8"));
|
|
||||||
|
|
||||||
if (!Arrays.equals(hash, computedHash)) {
|
|
||||||
throw new InvalidLicenseException("Invalid License");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ObjectSerializer().readObject(SignedLicense.class, Arrays.copyOfRange(signatureBytes, start, signatureBytes.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not thread-safe (allows setting licenses); used only for testing and in command-line tools
|
|
||||||
*/
|
|
||||||
public static class FileBasedESLicenseProvider extends ESLicenseProvider {
|
|
||||||
private ESLicenses esLicenses;
|
|
||||||
private final String publicKeyPath;
|
|
||||||
|
|
||||||
private FileBasedESLicenseProvider(ESLicenses esLicenses, String publicKeyPath) {
|
|
||||||
this.esLicenses = esLicenses;
|
|
||||||
this.publicKeyPath = publicKeyPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SignedLicense getLicense(Object context) {
|
|
||||||
assert context instanceof FeatureType;
|
|
||||||
FeatureType featureType = (FeatureType) context;
|
|
||||||
ESLicense esLicense = esLicenses.get(featureType);
|
|
||||||
if (esLicense == null) {
|
|
||||||
throw new InvalidLicenseException("Invalid License");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return extractSignedLicence(esLicense.signature(), publicKeyPath);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ESLicense getESLicense(FeatureType featureType) {
|
|
||||||
return esLicenses.get(featureType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ESLicenses getEffectiveLicenses() {
|
|
||||||
return esLicenses;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addLicenses(ESLicenses esLicenses) {
|
|
||||||
this.esLicenses = esLicenses;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,66 +8,27 @@ package org.elasticsearch.license.manager;
|
||||||
import net.nicholaswilliams.java.licensing.ObjectSerializer;
|
import net.nicholaswilliams.java.licensing.ObjectSerializer;
|
||||||
import net.nicholaswilliams.java.licensing.SignedLicense;
|
import net.nicholaswilliams.java.licensing.SignedLicense;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.elasticsearch.common.collect.Sets;
|
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
|
||||||
import org.elasticsearch.license.core.LicenseBuilders;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.elasticsearch.license.core.ESLicenses.ESLicense;
|
public final class Utils {
|
||||||
|
/**
|
||||||
public class Utils {
|
* Extract a signedLicense (SIGNED_LICENSE_CONTENT) from the signature.
|
||||||
|
* Validates the public key used to decrypt the license by comparing their hashes
|
||||||
|
* <p/>
|
||||||
|
* Signature structure:
|
||||||
public static ESLicense getESLicenseFromSignature(String signature) {
|
* | MAGIC | HEADER_LENGTH | VERSION | PUB_KEY_DIGEST | SIGNED_LICENSE_CONTENT |
|
||||||
|
*
|
||||||
|
* @param signature of a single license
|
||||||
|
* @return signed license content for the license
|
||||||
|
*/
|
||||||
|
public static SignedLicense extractSignedLicence(String signature) {
|
||||||
byte[] signatureBytes = Base64.decodeBase64(signature);
|
byte[] signatureBytes = Base64.decodeBase64(signature);
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(signatureBytes);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(signatureBytes);
|
||||||
byteBuffer = (ByteBuffer) byteBuffer.position(13);
|
byteBuffer = (ByteBuffer) byteBuffer.position(13);
|
||||||
int start = byteBuffer.getInt();
|
int start = byteBuffer.getInt();
|
||||||
SignedLicense signedLicense = new ObjectSerializer()
|
int version = byteBuffer.getInt();
|
||||||
.readObject(SignedLicense.class, Arrays.copyOfRange(signatureBytes, start, signatureBytes.length));
|
return new ObjectSerializer().readObject(SignedLicense.class, Arrays.copyOfRange(signatureBytes, start, signatureBytes.length));
|
||||||
return ESLicenseManager.getInstance().decryptAndVerifyESLicense(signedLicense, signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isSame(ESLicenses firstLicenses, ESLicenses secondLicenses) {
|
|
||||||
|
|
||||||
// we do the build to make sure we weed out any expired licenses
|
|
||||||
final ESLicenses licenses1 = LicenseBuilders.licensesBuilder().licenses(firstLicenses).build();
|
|
||||||
final ESLicenses licenses2 = LicenseBuilders.licensesBuilder().licenses(secondLicenses).build();
|
|
||||||
|
|
||||||
// check if the effective licenses have the same feature set
|
|
||||||
if (!licenses1.features().equals(licenses2.features())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for every feature license, check if all the attributes are the same
|
|
||||||
for (ESLicenses.FeatureType featureType : licenses1.features()) {
|
|
||||||
ESLicense license1 = licenses1.get(featureType);
|
|
||||||
ESLicense license2 = licenses2.get(featureType);
|
|
||||||
|
|
||||||
if (!license1.uid().equals(license2.uid())
|
|
||||||
|| license1.feature() != license2.feature()
|
|
||||||
|| license1.subscriptionType() != license2.subscriptionType()
|
|
||||||
|| license1.type() != license2.type()
|
|
||||||
|| license1.expiryDate() != license2.expiryDate()
|
|
||||||
|| license1.issueDate() != license2.issueDate()
|
|
||||||
|| !license1.issuedTo().equals(license2.issuedTo())
|
|
||||||
|| license1.maxNodes() != license2.maxNodes()
|
|
||||||
|| license1.signature().equals(license2.signature())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ESLicenses fromSignatures(final Set<String> signatures) {
|
|
||||||
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
|
|
||||||
for (String signature : signatures) {
|
|
||||||
licensesBuilder.license(getESLicenseFromSignature(signature));
|
|
||||||
}
|
|
||||||
return licensesBuilder.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,17 @@
|
||||||
package org.elasticsearch.license.plugin.action;
|
package org.elasticsearch.license.plugin.action;
|
||||||
|
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.collect.Sets;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.core.LicenseBuilders;
|
import org.elasticsearch.license.core.LicenseBuilders;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.elasticsearch.license.core.ESLicenses.*;
|
import static org.elasticsearch.license.core.ESLicenses.*;
|
||||||
import static org.elasticsearch.license.manager.Utils.getESLicenseFromSignature;
|
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
|
@ -28,18 +28,6 @@ public class Utils {
|
||||||
return signatures.toArray(new String[signatures.size()]);
|
return signatures.toArray(new String[signatures.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ESLicenses fromSignatures(final String[] signatures) {
|
|
||||||
return org.elasticsearch.license.manager.Utils.fromSignatures(Sets.newHashSet(signatures));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ESLicenses fromSignaturesAsIs(final Set<String> signatures) {
|
|
||||||
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
|
|
||||||
for (String signature : signatures) {
|
|
||||||
licensesBuilder.licenseAsIs(getESLicenseFromSignature(signature));
|
|
||||||
}
|
|
||||||
return licensesBuilder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ESLicenses readGeneratedLicensesFrom(StreamInput in) throws IOException {
|
public static ESLicenses readGeneratedLicensesFrom(StreamInput in) throws IOException {
|
||||||
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
|
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
|
||||||
boolean exists = in.readBoolean();
|
boolean exists = in.readBoolean();
|
||||||
|
|
|
@ -17,8 +17,9 @@ import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.plugin.action.Utils;
|
import org.elasticsearch.license.manager.ESLicenseManager;
|
||||||
import org.elasticsearch.license.plugin.core.LicensesMetaData;
|
import org.elasticsearch.license.plugin.core.LicensesMetaData;
|
||||||
|
import org.elasticsearch.license.plugin.core.LicensesService;
|
||||||
import org.elasticsearch.license.plugin.core.trial.TrialLicenseUtils;
|
import org.elasticsearch.license.plugin.core.trial.TrialLicenseUtils;
|
||||||
import org.elasticsearch.license.plugin.core.trial.TrialLicenses;
|
import org.elasticsearch.license.plugin.core.trial.TrialLicenses;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
|
@ -26,10 +27,13 @@ import org.elasticsearch.transport.TransportService;
|
||||||
|
|
||||||
public class TransportGetLicenseAction extends TransportMasterNodeReadOperationAction<GetLicenseRequest, GetLicenseResponse> {
|
public class TransportGetLicenseAction extends TransportMasterNodeReadOperationAction<GetLicenseRequest, GetLicenseResponse> {
|
||||||
|
|
||||||
|
private final LicensesService licensesService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TransportGetLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
public TransportGetLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService, LicensesService licensesService,
|
||||||
ThreadPool threadPool, ActionFilters actionFilters) {
|
ThreadPool threadPool, ActionFilters actionFilters) {
|
||||||
super(settings, GetLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters);
|
super(settings, GetLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters);
|
||||||
|
this.licensesService = licensesService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,10 +59,12 @@ public class TransportGetLicenseAction extends TransportMasterNodeReadOperationA
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void masterOperation(final GetLicenseRequest request, ClusterState state, final ActionListener<GetLicenseResponse> listener) throws ElasticsearchException {
|
protected void masterOperation(final GetLicenseRequest request, ClusterState state, final ActionListener<GetLicenseResponse> listener) throws ElasticsearchException {
|
||||||
|
//TODO: Move this functionality to license service
|
||||||
MetaData metaData = state.metaData();
|
MetaData metaData = state.metaData();
|
||||||
LicensesMetaData licenses = metaData.custom(LicensesMetaData.TYPE);
|
LicensesMetaData licenses = metaData.custom(LicensesMetaData.TYPE);
|
||||||
if (licenses != null) {
|
if (licenses != null) {
|
||||||
ESLicenses esLicenses = Utils.fromSignaturesAsIs(licenses.getSignatures());
|
ESLicenseManager esLicenseManager = licensesService.getEsLicenseManager();
|
||||||
|
ESLicenses esLicenses = esLicenseManager.fromSignaturesAsIs(licenses.getSignatures());
|
||||||
TrialLicenses trialLicenses = TrialLicenseUtils.fromEncodedTrialLicenses(licenses.getEncodedTrialLicenses());
|
TrialLicenses trialLicenses = TrialLicenseUtils.fromEncodedTrialLicenses(licenses.getEncodedTrialLicenses());
|
||||||
listener.onResponse(new GetLicenseResponse(esLicenses, trialLicenses));
|
listener.onResponse(new GetLicenseResponse(esLicenses, trialLicenses));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.elasticsearch.gateway.GatewayService;
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.core.LicenseBuilders;
|
import org.elasticsearch.license.core.LicenseBuilders;
|
||||||
import org.elasticsearch.license.manager.ESLicenseManager;
|
import org.elasticsearch.license.manager.ESLicenseManager;
|
||||||
|
import org.elasticsearch.license.manager.ESLicenseProvider;
|
||||||
import org.elasticsearch.license.plugin.action.Utils;
|
import org.elasticsearch.license.plugin.action.Utils;
|
||||||
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest;
|
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest;
|
||||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
|
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
|
||||||
|
@ -54,7 +55,7 @@ import static org.elasticsearch.license.plugin.core.trial.TrialLicensesBuilder.t
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
public class LicensesService extends AbstractLifecycleComponent<LicensesService> implements ClusterStateListener, LicensesManagerService, LicensesClientService {
|
public class LicensesService extends AbstractLifecycleComponent<LicensesService> implements ESLicenseProvider, ClusterStateListener, LicensesManagerService, LicensesClientService {
|
||||||
|
|
||||||
private ESLicenseManager esLicenseManager;
|
private ESLicenseManager esLicenseManager;
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
||||||
public LicensesService(Settings settings, ClusterService clusterService, ThreadPool threadPool) {
|
public LicensesService(Settings settings, ClusterService clusterService, ThreadPool threadPool) {
|
||||||
super(settings);
|
super(settings);
|
||||||
this.clusterService = clusterService;
|
this.clusterService = clusterService;
|
||||||
this.esLicenseManager = ESLicenseManager.createClusterStateBasedInstance(clusterService);
|
this.esLicenseManager = new ESLicenseManager(this);
|
||||||
this.threadPool = threadPool;
|
this.threadPool = threadPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
||||||
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
|
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
|
||||||
LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
|
LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
|
||||||
final LicensesWrapper licensesWrapper = LicensesWrapper.wrap(currentLicenses);
|
final LicensesWrapper licensesWrapper = LicensesWrapper.wrap(currentLicenses);
|
||||||
licensesWrapper.addSignedLicenses(newLicenses);
|
licensesWrapper.addSignedLicenses(esLicenseManager, newLicenses);
|
||||||
mdBuilder.putCustom(LicensesMetaData.TYPE, licensesWrapper.createLicensesMetaData());
|
mdBuilder.putCustom(LicensesMetaData.TYPE, licensesWrapper.createLicensesMetaData());
|
||||||
return ClusterState.builder(currentState).metaData(mdBuilder).build();
|
return ClusterState.builder(currentState).metaData(mdBuilder).build();
|
||||||
}
|
}
|
||||||
|
@ -143,7 +144,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
||||||
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
|
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
|
||||||
LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
|
LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
|
||||||
final LicensesWrapper licensesWrapper = LicensesWrapper.wrap(currentLicenses);
|
final LicensesWrapper licensesWrapper = LicensesWrapper.wrap(currentLicenses);
|
||||||
licensesWrapper.removeFeatures(featuresToDelete);
|
licensesWrapper.removeFeatures(esLicenseManager, featuresToDelete);
|
||||||
mdBuilder.putCustom(LicensesMetaData.TYPE, licensesWrapper.createLicensesMetaData());
|
mdBuilder.putCustom(LicensesMetaData.TYPE, licensesWrapper.createLicensesMetaData());
|
||||||
return ClusterState.builder(currentState).metaData(mdBuilder).build();
|
return ClusterState.builder(currentState).metaData(mdBuilder).build();
|
||||||
}
|
}
|
||||||
|
@ -296,6 +297,22 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
||||||
return ThreadPool.Names.GENERIC;
|
return ThreadPool.Names.GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ESLicenses.ESLicense getESLicense(FeatureType featureType) {
|
||||||
|
return getEffectiveLicenses().get(featureType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ESLicenses getEffectiveLicenses() {
|
||||||
|
final ClusterState state = clusterService.state();
|
||||||
|
LicensesMetaData metaData = state.metaData().custom(LicensesMetaData.TYPE);
|
||||||
|
if (metaData != null) {
|
||||||
|
return esLicenseManager.fromSignatures(metaData.getSignatures());
|
||||||
|
}
|
||||||
|
return LicenseBuilders.licensesBuilder().build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public class SubmitReschedulingLicensingClientNotificationJob implements Runnable {
|
public class SubmitReschedulingLicensingClientNotificationJob implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -312,6 +329,10 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Shouldn't expose this
|
||||||
|
public ESLicenseManager getEsLicenseManager() {
|
||||||
|
return esLicenseManager;
|
||||||
|
}
|
||||||
|
|
||||||
public class LicensingClientNotificationJob implements Runnable {
|
public class LicensingClientNotificationJob implements Runnable {
|
||||||
|
|
||||||
|
@ -483,8 +504,8 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ESLicenses signedLicenses() {
|
public ESLicenses signedLicenses(ESLicenseManager licenseManage) {
|
||||||
return org.elasticsearch.license.manager.Utils.fromSignatures(signatures);
|
return licenseManage.fromSignatures(signatures);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrialLicenses trialLicenses() {
|
public TrialLicenses trialLicenses() {
|
||||||
|
@ -496,15 +517,15 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
||||||
Collections.singleton(TrialLicenseUtils.toEncodedTrialLicense(trialLicense))));
|
Collections.singleton(TrialLicenseUtils.toEncodedTrialLicense(trialLicense))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSignedLicenses(ESLicenses licenses) {
|
public void addSignedLicenses(ESLicenseManager licenseManage, ESLicenses licenses) {
|
||||||
ESLicenses currentSignedLicenses = signedLicenses();
|
ESLicenses currentSignedLicenses = signedLicenses(licenseManage);
|
||||||
final ESLicenses mergedLicenses = LicenseBuilders.merge(currentSignedLicenses, licenses);
|
final ESLicenses mergedLicenses = LicenseBuilders.merge(currentSignedLicenses, licenses);
|
||||||
Set<String> newSignatures = Sets.newHashSet(Utils.toSignatures(mergedLicenses));
|
Set<String> newSignatures = Sets.newHashSet(Utils.toSignatures(mergedLicenses));
|
||||||
this.signatures = ImmutableSet.copyOf(Sets.union(signatures, newSignatures));
|
this.signatures = ImmutableSet.copyOf(Sets.union(signatures, newSignatures));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeFeatures(Set<FeatureType> featuresToDelete) {
|
public void removeFeatures(ESLicenseManager licenseManage, Set<FeatureType> featuresToDelete) {
|
||||||
ESLicenses currentSignedLicenses = signedLicenses();
|
ESLicenses currentSignedLicenses = signedLicenses(licenseManage);
|
||||||
final ESLicenses reducedLicenses = LicenseBuilders.removeFeatures(currentSignedLicenses, featuresToDelete);
|
final ESLicenses reducedLicenses = LicenseBuilders.removeFeatures(currentSignedLicenses, featuresToDelete);
|
||||||
Set<String> reducedSignatures = Sets.newHashSet(Utils.toSignatures(reducedLicenses));
|
Set<String> reducedSignatures = Sets.newHashSet(Utils.toSignatures(reducedLicenses));
|
||||||
this.signatures = ImmutableSet.copyOf(Sets.intersection(signatures, reducedSignatures));
|
this.signatures = ImmutableSet.copyOf(Sets.intersection(signatures, reducedSignatures));
|
||||||
|
|
|
@ -6,11 +6,12 @@
|
||||||
package org.elasticsearch.license;
|
package org.elasticsearch.license;
|
||||||
|
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.licensor.tools.KeyPairGeneratorTool;
|
import org.elasticsearch.license.manager.ESLicenseManager;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class AbstractLicensingTestBase {
|
public class AbstractLicensingTestBase {
|
||||||
|
@ -19,23 +20,15 @@ public class AbstractLicensingTestBase {
|
||||||
protected static String priKeyPath = null;
|
protected static String priKeyPath = null;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setup() throws IOException {
|
public static void setup() throws Exception {
|
||||||
|
pubKeyPath = getResourcePath("test_pub.key");
|
||||||
|
priKeyPath = getResourcePath("test_pri.key");
|
||||||
|
|
||||||
// Generate temp KeyPair spec
|
}
|
||||||
File privateKeyFile = File.createTempFile("privateKey", ".key");
|
|
||||||
File publicKeyFile = File.createTempFile("publicKey", ".key");
|
|
||||||
AbstractLicensingTestBase.pubKeyPath = publicKeyFile.getAbsolutePath();
|
|
||||||
AbstractLicensingTestBase.priKeyPath = privateKeyFile.getAbsolutePath();
|
|
||||||
assert privateKeyFile.delete();
|
|
||||||
assert publicKeyFile.delete();
|
|
||||||
|
|
||||||
// Generate keyPair
|
private static String getResourcePath(String resource) throws Exception {
|
||||||
String[] args = new String[4];
|
URL url = ESLicenseManager.class.getResource("/org.elasticsearch.license.plugin/" + resource);
|
||||||
args[0] = "--publicKeyPath";
|
return url.toURI().getPath();
|
||||||
args[1] = AbstractLicensingTestBase.pubKeyPath;
|
|
||||||
args[2] = "--privateKeyPath";
|
|
||||||
args[3] = AbstractLicensingTestBase.priKeyPath;
|
|
||||||
KeyPairGeneratorTool.main(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateSignedLicenses(Map<ESLicenses.FeatureType, TestUtils.FeatureAttributes> map) throws IOException {
|
public String generateSignedLicenses(Map<ESLicenses.FeatureType, TestUtils.FeatureAttributes> map) throws IOException {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.elasticsearch.license.TestUtils;
|
||||||
import org.elasticsearch.license.core.DateUtils;
|
import org.elasticsearch.license.core.DateUtils;
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.core.LicenseBuilders;
|
import org.elasticsearch.license.core.LicenseBuilders;
|
||||||
|
import org.elasticsearch.license.licensor.tools.FileBasedESLicenseProvider;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -26,16 +27,20 @@ public class LicenseVerificationTests extends AbstractLicensingTestBase {
|
||||||
|
|
||||||
private static ESLicenseManager esLicenseManager;
|
private static ESLicenseManager esLicenseManager;
|
||||||
|
|
||||||
|
private static FileBasedESLicenseProvider esLicenseProvider;
|
||||||
|
|
||||||
private final static ESLicenses EMPTY_LICENSES = LicenseBuilders.licensesBuilder().build();
|
private final static ESLicenses EMPTY_LICENSES = LicenseBuilders.licensesBuilder().build();
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setupManager() {
|
public static void setupManager() {
|
||||||
esLicenseManager = ESLicenseManager.createLocalBasedInstance(LicenseBuilders.licensesBuilder().build(), pubKeyPath);
|
esLicenseProvider = new FileBasedESLicenseProvider(LicenseBuilders.licensesBuilder().build());
|
||||||
|
esLicenseManager = new ESLicenseManager(esLicenseProvider);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void clearManager() {
|
public void clearManager() {
|
||||||
esLicenseManager.clearAndAddLicenses(EMPTY_LICENSES);
|
esLicenseProvider.setLicenses(EMPTY_LICENSES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +56,7 @@ public class LicenseVerificationTests extends AbstractLicensingTestBase {
|
||||||
|
|
||||||
ESLicenses esLicensesOutput = readLicensesFromString(generateSignedLicenses(map));
|
ESLicenses esLicensesOutput = readLicensesFromString(generateSignedLicenses(map));
|
||||||
|
|
||||||
esLicenseManager.clearAndAddLicenses(esLicensesOutput);
|
esLicenseProvider.setLicenses(esLicensesOutput);
|
||||||
|
|
||||||
esLicenseManager.verifyLicenses();
|
esLicenseManager.verifyLicenses();
|
||||||
|
|
||||||
|
@ -75,7 +80,7 @@ public class LicenseVerificationTests extends AbstractLicensingTestBase {
|
||||||
|
|
||||||
ESLicenses esLicensesOutput = readLicensesFromString(generateSignedLicenses(map));
|
ESLicenses esLicensesOutput = readLicensesFromString(generateSignedLicenses(map));
|
||||||
|
|
||||||
esLicenseManager.clearAndAddLicenses(esLicensesOutput);
|
esLicenseProvider.setLicenses(esLicensesOutput);
|
||||||
|
|
||||||
//printLicense(esLicenseManager.getEffectiveLicenses());
|
//printLicense(esLicenseManager.getEffectiveLicenses());
|
||||||
|
|
||||||
|
@ -132,7 +137,7 @@ public class LicenseVerificationTests extends AbstractLicensingTestBase {
|
||||||
|
|
||||||
ESLicenses esLicensesOutput = readLicensesFromString(generateSignedLicenses(map));
|
ESLicenses esLicensesOutput = readLicensesFromString(generateSignedLicenses(map));
|
||||||
|
|
||||||
esLicenseManager.clearAndAddLicenses(esLicensesOutput);
|
esLicenseProvider.setLicenses(esLicensesOutput);
|
||||||
|
|
||||||
// All validation for shield license should be normal as expected
|
// All validation for shield license should be normal as expected
|
||||||
verifyLicenseManager(esLicenseManager, Collections.singletonMap(FeatureType.SHIELD, shildFeatureAttributes));
|
verifyLicenseManager(esLicenseManager, Collections.singletonMap(FeatureType.SHIELD, shildFeatureAttributes));
|
||||||
|
@ -166,7 +171,7 @@ public class LicenseVerificationTests extends AbstractLicensingTestBase {
|
||||||
ESLicenses tamperedLicenses = LicenseBuilders.licensesBuilder().license(tamperedLicense).build();
|
ESLicenses tamperedLicenses = LicenseBuilders.licensesBuilder().license(tamperedLicense).build();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
esLicenseManager.clearAndAddLicenses(tamperedLicenses);
|
esLicenseProvider.setLicenses(tamperedLicenses);
|
||||||
assertTrue("License manager should always report the original (signed) expiry date of: " + originalExpiryDate + " but got: " + esLicenseManager.getExpiryDateForLicense(FeatureType.SHIELD), esLicenseManager.getExpiryDateForLicense(FeatureType.SHIELD) == originalExpiryDate);
|
assertTrue("License manager should always report the original (signed) expiry date of: " + originalExpiryDate + " but got: " + esLicenseManager.getExpiryDateForLicense(FeatureType.SHIELD), esLicenseManager.getExpiryDateForLicense(FeatureType.SHIELD) == originalExpiryDate);
|
||||||
esLicenseManager.verifyLicenses();
|
esLicenseManager.verifyLicenses();
|
||||||
fail();
|
fail();
|
||||||
|
|
|
@ -18,7 +18,7 @@ import org.elasticsearch.license.TestUtils;
|
||||||
import org.elasticsearch.license.core.ESLicenses;
|
import org.elasticsearch.license.core.ESLicenses;
|
||||||
import org.elasticsearch.license.core.LicenseBuilders;
|
import org.elasticsearch.license.core.LicenseBuilders;
|
||||||
import org.elasticsearch.license.core.LicenseUtils;
|
import org.elasticsearch.license.core.LicenseUtils;
|
||||||
import org.elasticsearch.license.manager.Utils;
|
import org.elasticsearch.license.manager.ESLicenseManager;
|
||||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
|
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
|
||||||
import org.elasticsearch.license.plugin.core.*;
|
import org.elasticsearch.license.plugin.core.*;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
|
@ -134,6 +134,7 @@ public class LicensesServiceTests extends ElasticsearchIntegrationTest {
|
||||||
ESLicenses licenses = LicenseUtils.readLicensesFromString(licenseOutput);
|
ESLicenses licenses = LicenseUtils.readLicensesFromString(licenseOutput);
|
||||||
|
|
||||||
LicensesManagerService licensesManagerService = licensesManagerService();
|
LicensesManagerService licensesManagerService = licensesManagerService();
|
||||||
|
ESLicenseManager esLicenseManager = ((LicensesService)licensesManagerService).getEsLicenseManager();
|
||||||
final CountDownLatch latch1 = new CountDownLatch(1);
|
final CountDownLatch latch1 = new CountDownLatch(1);
|
||||||
licensesManagerService.registerLicenses(new LicensesService.PutLicenseRequestHolder(new PutLicenseRequest().license(licenses), "test"), new ActionListener<ClusterStateUpdateResponse>() {
|
licensesManagerService.registerLicenses(new LicensesService.PutLicenseRequestHolder(new PutLicenseRequest().license(licenses), "test"), new ActionListener<ClusterStateUpdateResponse>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -151,7 +152,7 @@ public class LicensesServiceTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
latch1.await();
|
latch1.await();
|
||||||
LicensesMetaData metaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
LicensesMetaData metaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
||||||
ESLicenses metaDataLicense = Utils.fromSignatures(metaData.getSignatures());
|
ESLicenses metaDataLicense = esLicenseManager.fromSignatures(metaData.getSignatures());
|
||||||
TestUtils.isSame(licenses, metaDataLicense);
|
TestUtils.isSame(licenses, metaDataLicense);
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,7 +179,7 @@ public class LicensesServiceTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
latch2.await();
|
latch2.await();
|
||||||
metaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
metaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
||||||
metaDataLicense = Utils.fromSignatures(metaData.getSignatures());
|
metaDataLicense = esLicenseManager.fromSignatures(metaData.getSignatures());
|
||||||
TestUtils.isSame(licenses2, metaDataLicense);
|
TestUtils.isSame(licenses2, metaDataLicense);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue