Integration with license plugin
- Added a `LicenseService` to handle license feature enable/disable events - LicenseEventNotifier is responsible for notifying the license events to whatever registered listeners that are interested in them - In Shield, when a license is disabled for `shield` feature, we block all read operations (done in the `ShieldActionFilter`) - Added initial documentation around licensing Closes elastic/elasticsearch#347 Original commit: elastic/x-pack-elasticsearch@6ba7a10cd4
This commit is contained in:
parent
070dbebb7a
commit
e646fd5edc
23
pom.xml
23
pom.xml
|
@ -17,8 +17,19 @@
|
|||
<!-- needed for some test features for now, remove with 1.3 release -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>oss.sonatype.org-snapshot</id>
|
||||
<url>http://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
<id>es-releases</id>
|
||||
<url>http://maven.elasticsearch.org/libs-release-local</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>daily</updatePolicy>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>es-snapshots</id>
|
||||
<url>http://maven.elasticsearch.org/libs-snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
|
@ -33,6 +44,7 @@
|
|||
<lucene.version>4.10.2</lucene.version>
|
||||
<lucene.maven.version>4.10.2</lucene.maven.version>
|
||||
<elasticsearch.version>1.4.0</elasticsearch.version>
|
||||
<license.plugin.version>1.0.0-beta1</license.plugin.version>
|
||||
|
||||
<tests.jvms>auto</tests.jvms>
|
||||
<tests.shuffle>true</tests.shuffle>
|
||||
|
@ -150,6 +162,13 @@
|
|||
<version>1.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>elasticsearch-license-plugin</artifactId>
|
||||
<version>${license.plugin.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.elasticsearch.shield.authc.AuthenticationModule;
|
|||
import org.elasticsearch.shield.authz.AuthorizationModule;
|
||||
import org.elasticsearch.shield.signature.SignatureModule;
|
||||
import org.elasticsearch.shield.rest.ShieldRestModule;
|
||||
import org.elasticsearch.shield.license.LicenseModule;
|
||||
import org.elasticsearch.shield.ssl.SSLModule;
|
||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
||||
import org.elasticsearch.shield.transport.SecuredTransportModule;
|
||||
|
@ -23,20 +24,13 @@ import org.elasticsearch.shield.transport.SecuredTransportModule;
|
|||
*/
|
||||
public class ShieldModule extends AbstractShieldModule.Spawn {
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
public ShieldModule(Settings settings) {
|
||||
super(settings);
|
||||
this.enabled = settings.getAsBoolean("shield.enabled", true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterable<? extends Module> spawnModules(boolean clientMode) {
|
||||
// don't spawn modules if shield is explicitly disabled
|
||||
if (!enabled) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
// spawn needed parts in client mode
|
||||
if (clientMode) {
|
||||
return ImmutableList.<Module>of(
|
||||
|
@ -45,6 +39,7 @@ public class ShieldModule extends AbstractShieldModule.Spawn {
|
|||
}
|
||||
|
||||
return ImmutableList.<Module>of(
|
||||
new LicenseModule(settings),
|
||||
new AuthenticationModule(settings),
|
||||
new AuthorizationModule(settings),
|
||||
new AuditTrailModule(settings),
|
||||
|
|
|
@ -5,17 +5,18 @@
|
|||
*/
|
||||
package org.elasticsearch.shield;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.support.Headers;
|
||||
import org.elasticsearch.common.collect.ImmutableList;
|
||||
import org.elasticsearch.common.component.LifecycleComponent;
|
||||
import org.elasticsearch.common.inject.Module;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.plugins.AbstractPlugin;
|
||||
import org.elasticsearch.shield.ShieldModule;
|
||||
import org.elasticsearch.shield.ShieldSettingsException;
|
||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.shield.license.LicenseService;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
@ -29,9 +30,13 @@ public class ShieldPlugin extends AbstractPlugin {
|
|||
public static final String NAME = "shield";
|
||||
|
||||
private final Settings settings;
|
||||
private final boolean enabled;
|
||||
private final boolean clientMode;
|
||||
|
||||
public ShieldPlugin(Settings settings) {
|
||||
this.settings = settings;
|
||||
this.enabled = settings.getAsBoolean("shield.enabled", true);
|
||||
this.clientMode = clientMode(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,8 +54,18 @@ public class ShieldPlugin extends AbstractPlugin {
|
|||
return ImmutableList.<Class<? extends Module>>of(ShieldModule.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends LifecycleComponent>> services() {
|
||||
return enabled && !clientMode ?
|
||||
ImmutableList.<Class<? extends LifecycleComponent>>of(LicenseService.class) :
|
||||
ImmutableList.<Class<? extends LifecycleComponent>>of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings additionalSettings() {
|
||||
if (!enabled) {
|
||||
return ImmutableSettings.EMPTY;
|
||||
}
|
||||
String setting = Headers.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER;
|
||||
if (settings.get(setting) != null) {
|
||||
return ImmutableSettings.EMPTY;
|
||||
|
@ -77,4 +92,7 @@ public class ShieldPlugin extends AbstractPlugin {
|
|||
return configDir(env).resolve(name);
|
||||
}
|
||||
|
||||
public static boolean clientMode(Settings settings) {
|
||||
return !"node".equals(settings.get(Client.CLIENT_TYPE_SETTING));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.Nullable;
|
|||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.license.plugin.LicenseVersion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
@ -24,7 +25,7 @@ public class ShieldVersion implements Serializable {
|
|||
// the (internal) format of the id is there so we can easily do after/before checks on the id
|
||||
|
||||
public static final int V_1_0_0_ID = /*00*/1000099;
|
||||
public static final ShieldVersion V_1_0_0 = new ShieldVersion(V_1_0_0_ID, true, Version.V_1_4_0);
|
||||
public static final ShieldVersion V_1_0_0 = new ShieldVersion(V_1_0_0_ID, true, Version.V_1_4_0, LicenseVersion.V_1_0_0);
|
||||
|
||||
public static final ShieldVersion CURRENT = V_1_0_0;
|
||||
|
||||
|
@ -38,7 +39,7 @@ public class ShieldVersion implements Serializable {
|
|||
return V_1_0_0;
|
||||
|
||||
default:
|
||||
return new ShieldVersion(id, null, Version.CURRENT);
|
||||
return new ShieldVersion(id, null, Version.CURRENT, LicenseVersion.CURRENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,8 +98,9 @@ public class ShieldVersion implements Serializable {
|
|||
public final byte build;
|
||||
public final Boolean snapshot;
|
||||
public final Version minEsCompatibilityVersion;
|
||||
public final LicenseVersion minLicenseCompatibilityVersion;
|
||||
|
||||
ShieldVersion(int id, @Nullable Boolean snapshot, Version minEsCompatibilityVersion) {
|
||||
ShieldVersion(int id, @Nullable Boolean snapshot, Version minEsCompatibilityVersion, LicenseVersion minLicenseCompatibilityVersion) {
|
||||
this.id = id;
|
||||
this.major = (byte) ((id / 1000000) % 100);
|
||||
this.minor = (byte) ((id / 10000) % 100);
|
||||
|
@ -106,6 +108,7 @@ public class ShieldVersion implements Serializable {
|
|||
this.build = (byte) (id % 100);
|
||||
this.snapshot = snapshot;
|
||||
this.minEsCompatibilityVersion = minEsCompatibilityVersion;
|
||||
this.minLicenseCompatibilityVersion = minLicenseCompatibilityVersion;
|
||||
}
|
||||
|
||||
public boolean snapshot() {
|
||||
|
@ -154,6 +157,13 @@ public class ShieldVersion implements Serializable {
|
|||
return minEsCompatibilityVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The minimum license plugin version this shield version is compatible with.
|
||||
*/
|
||||
public LicenseVersion minimumLicenseCompatibilityVersion() {
|
||||
return minLicenseCompatibilityVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just the version number (without -SNAPSHOT if snapshot).
|
||||
*/
|
||||
|
|
|
@ -13,14 +13,20 @@ import org.elasticsearch.action.search.SearchResponse;
|
|||
import org.elasticsearch.action.search.SearchScrollRequest;
|
||||
import org.elasticsearch.action.support.ActionFilter;
|
||||
import org.elasticsearch.action.support.ActionFilterChain;
|
||||
import org.elasticsearch.common.base.Predicate;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.license.plugin.core.LicenseExpiredException;
|
||||
import org.elasticsearch.license.plugin.core.LicensesClientService;
|
||||
import org.elasticsearch.shield.User;
|
||||
import org.elasticsearch.shield.audit.AuditTrail;
|
||||
import org.elasticsearch.shield.authc.AuthenticationService;
|
||||
import org.elasticsearch.shield.authz.AuthorizationException;
|
||||
import org.elasticsearch.shield.authz.AuthorizationService;
|
||||
import org.elasticsearch.shield.signature.SignatureService;
|
||||
import org.elasticsearch.shield.authz.Privilege;
|
||||
import org.elasticsearch.shield.license.LicenseEventsNotifier;
|
||||
import org.elasticsearch.shield.license.LicenseService;
|
||||
import org.elasticsearch.shield.signature.SignatureException;
|
||||
import org.elasticsearch.shield.signature.SignatureService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -30,21 +36,45 @@ import java.util.List;
|
|||
*/
|
||||
public class ShieldActionFilter implements ActionFilter {
|
||||
|
||||
private static final Predicate<String> READ_ACTION_MATCHER = Privilege.Index.READ.predicate();
|
||||
|
||||
private final AuthenticationService authcService;
|
||||
private final AuthorizationService authzService;
|
||||
private final SignatureService signatureService;
|
||||
private final AuditTrail auditTrail;
|
||||
|
||||
private volatile boolean licenseEnabled;
|
||||
|
||||
@Inject
|
||||
public ShieldActionFilter(AuthenticationService authcService, AuthorizationService authzService, SignatureService signatureService, AuditTrail auditTrail) {
|
||||
public ShieldActionFilter(AuthenticationService authcService, AuthorizationService authzService, SignatureService signatureService, AuditTrail auditTrail, LicenseEventsNotifier licenseEventsNotifier) {
|
||||
this.authcService = authcService;
|
||||
this.authzService = authzService;
|
||||
this.signatureService = signatureService;
|
||||
this.auditTrail = auditTrail;
|
||||
licenseEventsNotifier.register(new LicensesClientService.Listener() {
|
||||
@Override
|
||||
public void onEnabled() {
|
||||
licenseEnabled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisabled() {
|
||||
licenseEnabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(String action, ActionRequest request, ActionListener listener, ActionFilterChain chain) {
|
||||
|
||||
/**
|
||||
A functional requirement - when the license of shield is disabled (invalid/expires), shield will continue
|
||||
to operate normally, except all read operations will be blocked.
|
||||
*/
|
||||
if (!licenseEnabled && READ_ACTION_MATCHER.apply(action)) {
|
||||
throw new LicenseExpiredException(LicenseService.FEATURE_NAME);
|
||||
}
|
||||
|
||||
try {
|
||||
/**
|
||||
here we fallback on the system user. Internal system requests are requests that are triggered by
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.shield.license;
|
||||
|
||||
import org.elasticsearch.license.plugin.core.LicensesClientService;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Serves as a registry of license event listeners and enables notifying them about the
|
||||
* different events.
|
||||
*
|
||||
* This class is required to serves as a bridge between the license service and any other
|
||||
* service that needs to recieve license events. The reason for that is that some services
|
||||
* that require such notifications also serves as a dependency for the licensing service
|
||||
* which introdues a circular dependency in guice (e.g. TransportService). This class then
|
||||
* serves as a bridge between the different services to eliminate such circular dependencies.
|
||||
*/
|
||||
public class LicenseEventsNotifier {
|
||||
|
||||
private final Set<LicensesClientService.Listener> listeners = new HashSet<>();
|
||||
|
||||
public void register(LicensesClientService.Listener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
protected void notifyEnabled() {
|
||||
for (LicensesClientService.Listener listener : listeners) {
|
||||
listener.onEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyDisabled() {
|
||||
for (LicensesClientService.Listener listener : listeners) {
|
||||
listener.onDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.shield.license;
|
||||
|
||||
import org.elasticsearch.ElasticsearchIllegalStateException;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.license.plugin.LicenseVersion;
|
||||
import org.elasticsearch.shield.ShieldVersion;
|
||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LicenseModule extends AbstractShieldModule.Node {
|
||||
|
||||
public LicenseModule(Settings settings) {
|
||||
super(settings);
|
||||
verifyLicensePlugin();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureNode() {
|
||||
bind(LicenseService.class).asEagerSingleton();
|
||||
bind(LicenseEventsNotifier.class).asEagerSingleton();
|
||||
}
|
||||
|
||||
private void verifyLicensePlugin() {
|
||||
try {
|
||||
getClass().getClassLoader().loadClass("org.elasticsearch.license.plugin.LicensePlugin");
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
throw new ElasticsearchIllegalStateException("Shield plugin requires the elasticsearch-license plugin to be installed");
|
||||
}
|
||||
|
||||
if (LicenseVersion.CURRENT.before(ShieldVersion.CURRENT.minLicenseCompatibilityVersion)) {
|
||||
throw new ElasticsearchIllegalStateException("Shield [" + ShieldVersion.CURRENT +
|
||||
"] requires minumum License plugin version [" + ShieldVersion.CURRENT.minLicenseCompatibilityVersion +
|
||||
"], but installed License plugin version is [" + LicenseVersion.CURRENT + "]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.shield.license;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.component.AbstractLifecycleComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.license.plugin.core.LicensesClientService;
|
||||
import org.elasticsearch.license.plugin.core.LicensesService;
|
||||
import org.elasticsearch.shield.ShieldPlugin;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LicenseService extends AbstractLifecycleComponent<LicenseService> {
|
||||
|
||||
public static final String FEATURE_NAME = ShieldPlugin.NAME;
|
||||
|
||||
private static final LicensesService.TrialLicenseOptions TRIAL_LICENSE_OPTIONS =
|
||||
new LicensesService.TrialLicenseOptions(TimeValue.timeValueHours(30 * 24), 1000);
|
||||
|
||||
private final LicensesClientService licensesClientService;
|
||||
private final LicenseEventsNotifier notifier;
|
||||
|
||||
private boolean enabled = false;
|
||||
|
||||
@Inject
|
||||
public LicenseService(Settings settings, LicensesClientService licensesClientService, LicenseEventsNotifier notifier) {
|
||||
super(settings);
|
||||
this.licensesClientService = licensesClientService;
|
||||
this.notifier = notifier;
|
||||
}
|
||||
|
||||
public synchronized boolean enabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ElasticsearchException {
|
||||
licensesClientService.register(FEATURE_NAME, TRIAL_LICENSE_OPTIONS, new InternalListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ElasticsearchException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose() throws ElasticsearchException {
|
||||
}
|
||||
|
||||
class InternalListener implements LicensesClientService.Listener {
|
||||
|
||||
@Override
|
||||
public void onEnabled() {
|
||||
synchronized (LicenseService.this) {
|
||||
enabled = true;
|
||||
notifier.notifyEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisabled() {
|
||||
synchronized (LicenseService.this) {
|
||||
enabled = false;
|
||||
notifier.notifyDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* 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.integration;
|
||||
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.ClusterChangedEvent;
|
||||
import org.elasticsearch.cluster.ClusterService;
|
||||
import org.elasticsearch.cluster.ClusterStateListener;
|
||||
import org.elasticsearch.common.collect.ImmutableSet;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.AbstractModule;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.inject.Module;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.license.plugin.core.LicenseExpiredException;
|
||||
import org.elasticsearch.license.plugin.core.LicensesClientService;
|
||||
import org.elasticsearch.license.plugin.core.LicensesService;
|
||||
import org.elasticsearch.plugins.AbstractPlugin;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.shield.license.LicenseService;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import org.elasticsearch.test.ShieldIntegrationTest;
|
||||
import org.elasticsearch.test.ShieldSettingsSource;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.SUITE;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ClusterScope(scope = SUITE)
|
||||
public class LicensingTests extends ShieldIntegrationTest {
|
||||
|
||||
public static final String ROLES =
|
||||
ShieldSettingsSource.DEFAULT_ROLE + ":\n" +
|
||||
" cluster: all\n" +
|
||||
" indices:\n" +
|
||||
" '*': manage\n" +
|
||||
" '/.*/': write\n" +
|
||||
" 'test': read\n" +
|
||||
" 'test1': read\n" +
|
||||
"\n" +
|
||||
"role_a:\n" +
|
||||
" indices:\n" +
|
||||
" 'a': all\n" +
|
||||
"\n" +
|
||||
"role_b:\n" +
|
||||
" indices:\n" +
|
||||
" 'b': all\n";
|
||||
|
||||
public static final String USERS =
|
||||
ShieldSettingsSource.CONFIG_STANDARD_USER +
|
||||
"user_a:{plain}passwd\n" +
|
||||
"user_b:{plain}passwd\n";
|
||||
|
||||
public static final String USERS_ROLES =
|
||||
ShieldSettingsSource.CONFIG_STANDARD_USER_ROLES +
|
||||
"role_a:user_a,user_b\n" +
|
||||
"role_b:user_b\n";
|
||||
|
||||
@Override
|
||||
protected String configRoles() {
|
||||
return ROLES;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String configUsers() {
|
||||
return USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String configUsersRoles() {
|
||||
return USERS_ROLES;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends Plugin> licensePluginClass() {
|
||||
return InternalLicensePlugin.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String licensePluginName() {
|
||||
return InternalLicensePlugin.NAME;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnableDisbleBehaviour() throws Exception {
|
||||
IndexResponse indexResponse = index("test", "type", jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "value")
|
||||
.endObject());
|
||||
assertThat(indexResponse.isCreated(), is(true));
|
||||
|
||||
|
||||
indexResponse = index("test1", "type", jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "value1")
|
||||
.endObject());
|
||||
assertThat(indexResponse.isCreated(), is(true));
|
||||
|
||||
refresh();
|
||||
|
||||
Client client = internalCluster().transportClient();
|
||||
|
||||
disableLicensing();
|
||||
try {
|
||||
client.prepareSearch().setQuery(matchAllQuery()).get();
|
||||
fail("expected an license expired exception when running a search with disabled license");
|
||||
} catch (LicenseExpiredException lee) {
|
||||
// expected
|
||||
assertThat(lee.feature(), equalTo(LicenseService.FEATURE_NAME));
|
||||
}
|
||||
|
||||
try {
|
||||
client.prepareGet("test1", "type", indexResponse.getId()).get();
|
||||
fail("expected an license expired exception when running a get with disabled license");
|
||||
} catch (LicenseExpiredException lee) {
|
||||
// expected
|
||||
assertThat(lee.feature(), equalTo(LicenseService.FEATURE_NAME));
|
||||
}
|
||||
|
||||
enableLicensing();
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch().setQuery(matchAllQuery()).get();
|
||||
assertNoFailures(searchResponse);
|
||||
assertHitCount(searchResponse, 2);
|
||||
|
||||
GetResponse getResponse = client.prepareGet("test1", "type", indexResponse.getId()).get();
|
||||
assertThat(getResponse.getId(), equalTo(indexResponse.getId()));
|
||||
|
||||
enableLicensing();
|
||||
indexResponse = index("test", "type", jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "value2")
|
||||
.endObject());
|
||||
assertThat(indexResponse.isCreated(), is(true));
|
||||
|
||||
disableLicensing();
|
||||
|
||||
indexResponse = index("test", "type", jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "value3")
|
||||
.endObject());
|
||||
assertThat(indexResponse.isCreated(), is(true));
|
||||
}
|
||||
|
||||
private void disableLicensing() {
|
||||
for (InternalLicensesClientService service : internalCluster().getInstances(InternalLicensesClientService.class)) {
|
||||
service.disable();
|
||||
}
|
||||
}
|
||||
|
||||
private void enableLicensing() {
|
||||
for (InternalLicensesClientService service : internalCluster().getInstances(InternalLicensesClientService.class)) {
|
||||
service.enable();
|
||||
}
|
||||
}
|
||||
|
||||
public static class InternalLicensePlugin extends AbstractPlugin {
|
||||
|
||||
static final String NAME = "internal-licensing";
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends Module>> modules() {
|
||||
return ImmutableSet.<Class<? extends Module>>of(InternalLicenseModule.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InternalLicenseModule extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(InternalLicensesClientService.class).asEagerSingleton();
|
||||
bind(LicensesClientService.class).to(InternalLicensesClientService.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InternalLicensesClientService extends AbstractComponent implements LicensesClientService {
|
||||
|
||||
private final List<Listener> listeners = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
public InternalLicensesClientService(Settings settings, ClusterService clusterService) {
|
||||
super(settings);
|
||||
clusterService.add(new ClusterStateListener() {
|
||||
@Override
|
||||
public void clusterChanged(ClusterChangedEvent event) {
|
||||
enable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String feature, LicensesService.TrialLicenseOptions trialLicenseOptions, Listener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
void enable() {
|
||||
for (Listener listener : listeners) {
|
||||
listener.onEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
void disable() {
|
||||
for (Listener listener : listeners) {
|
||||
listener.onDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,11 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
|||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
|
||||
import org.elasticsearch.common.base.Function;
|
||||
import org.elasticsearch.common.collect.Collections2;
|
||||
import org.elasticsearch.http.HttpServerTransport;
|
||||
import org.elasticsearch.license.plugin.LicensePlugin;
|
||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.test.ShieldIntegrationTest;
|
||||
|
@ -33,7 +37,13 @@ public class ShieldPluginTests extends ShieldIntegrationTest {
|
|||
NodesInfoResponse nodeInfos = internalCluster().transportClient().admin().cluster().prepareNodesInfo().get();
|
||||
logger.info("--> Checking nodes info that shield plugin is loaded");
|
||||
for (NodeInfo nodeInfo : nodeInfos.getNodes()) {
|
||||
assertThat(nodeInfo.getPlugins().getInfos(), hasSize(1));
|
||||
assertThat(nodeInfo.getPlugins().getInfos(), hasSize(2));
|
||||
assertThat(Collections2.transform(nodeInfo.getPlugins().getInfos(), new Function<PluginInfo, String>() {
|
||||
@Override
|
||||
public String apply(PluginInfo pluginInfo) {
|
||||
return pluginInfo.getName();
|
||||
}
|
||||
}), contains(ShieldPlugin.NAME, LicensePlugin.NAME));
|
||||
assertThat(nodeInfo.getPlugins().getInfos().get(0).getName(), is(ShieldPlugin.NAME));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,13 @@ import org.elasticsearch.action.ActionListener;
|
|||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.search.SearchScrollRequest;
|
||||
import org.elasticsearch.action.support.ActionFilterChain;
|
||||
import org.elasticsearch.license.plugin.core.LicensesClientService;
|
||||
import org.elasticsearch.shield.User;
|
||||
import org.elasticsearch.shield.audit.AuditTrail;
|
||||
import org.elasticsearch.shield.authc.AuthenticationService;
|
||||
import org.elasticsearch.shield.authz.AuthorizationException;
|
||||
import org.elasticsearch.shield.authz.AuthorizationService;
|
||||
import org.elasticsearch.shield.license.LicenseEventsNotifier;
|
||||
import org.elasticsearch.shield.signature.SignatureService;
|
||||
import org.elasticsearch.shield.signature.SignatureException;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
|
@ -34,6 +36,7 @@ public class ShieldActionFilterTests extends ElasticsearchTestCase {
|
|||
private AuthorizationService authzService;
|
||||
private SignatureService signatureService;
|
||||
private AuditTrail auditTrail;
|
||||
private LicenseEventsNotifier licenseEventsNotifier;
|
||||
private ShieldActionFilter filter;
|
||||
|
||||
@Before
|
||||
|
@ -42,7 +45,8 @@ public class ShieldActionFilterTests extends ElasticsearchTestCase {
|
|||
authzService = mock(AuthorizationService.class);
|
||||
signatureService = mock(SignatureService.class);
|
||||
auditTrail = mock(AuditTrail.class);
|
||||
filter = new ShieldActionFilter(authcService, authzService, signatureService, auditTrail);
|
||||
licenseEventsNotifier = new MockLicenseEventsNotifier();
|
||||
filter = new ShieldActionFilter(authcService, authzService, signatureService, auditTrail, licenseEventsNotifier);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -102,4 +106,11 @@ public class ShieldActionFilterTests extends ElasticsearchTestCase {
|
|||
verify(auditTrail).tamperedRequest(user, "_action", request);
|
||||
verifyNoMoreInteractions(chain);
|
||||
}
|
||||
|
||||
private class MockLicenseEventsNotifier extends LicenseEventsNotifier {
|
||||
@Override
|
||||
public void register(LicensesClientService.Listener listener) {
|
||||
listener.onEnabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,14 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
|||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.base.Function;
|
||||
import org.elasticsearch.common.collect.Collections2;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.license.plugin.LicensePlugin;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.shield.ShieldPlugin;
|
||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
import org.junit.Before;
|
||||
|
@ -25,8 +30,9 @@ import org.junit.rules.ExternalResource;
|
|||
import java.io.File;
|
||||
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
|
||||
/**
|
||||
* Base class to run tests against a cluster with shield installed.
|
||||
|
@ -120,8 +126,13 @@ public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest
|
|||
public void assertShieldIsInstalled() {
|
||||
NodesInfoResponse nodeInfos = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).get();
|
||||
for (NodeInfo nodeInfo : nodeInfos) {
|
||||
assertThat(ShieldPlugin.NAME + " should be the only installed plugin, found the following ones: " + nodeInfo.getPlugins().getInfos(), nodeInfo.getPlugins().getInfos().size(), equalTo(1));
|
||||
assertThat(ShieldPlugin.NAME + " should be the only installed plugin, found the following ones: " + nodeInfo.getPlugins().getInfos(), nodeInfo.getPlugins().getInfos().get(0).getName(), equalTo(ShieldPlugin.NAME));
|
||||
assertThat(nodeInfo.getPlugins().getInfos(), hasSize(2));
|
||||
assertThat(Collections2.transform(nodeInfo.getPlugins().getInfos(), new Function<PluginInfo, String>() {
|
||||
@Override
|
||||
public String apply(PluginInfo pluginInfo) {
|
||||
return pluginInfo.getName();
|
||||
}
|
||||
}), contains(ShieldPlugin.NAME, licensePluginName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,6 +214,14 @@ public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest
|
|||
return randomBoolean();
|
||||
}
|
||||
|
||||
protected Class<? extends Plugin> licensePluginClass() {
|
||||
return SHIELD_DEFAULT_SETTINGS.licensePluginClass();
|
||||
}
|
||||
|
||||
protected String licensePluginName() {
|
||||
return SHIELD_DEFAULT_SETTINGS.licensePluginName();
|
||||
}
|
||||
|
||||
private class CustomShieldSettingsSource extends ShieldSettingsSource {
|
||||
private CustomShieldSettingsSource(boolean sslTransportEnabled, File configDir, Scope scope) {
|
||||
super(maxNumberOfNodes(), sslTransportEnabled, configDir, scope);
|
||||
|
@ -243,6 +262,16 @@ public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest
|
|||
protected SecuredString transportClientPassword() {
|
||||
return ShieldIntegrationTest.this.transportClientPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends Plugin> licensePluginClass() {
|
||||
return ShieldIntegrationTest.this.licensePluginClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String licensePluginName() {
|
||||
return ShieldIntegrationTest.this.licensePluginName();
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertGreenClusterState(Client client) {
|
||||
|
|
|
@ -14,6 +14,8 @@ import org.elasticsearch.common.io.Streams;
|
|||
import org.elasticsearch.common.os.OsUtils;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.license.plugin.LicensePlugin;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.shield.ShieldPlugin;
|
||||
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
|
||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
|
@ -77,7 +79,6 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
public ShieldSettingsSource(int numOfNodes, boolean sslTransportEnabled, File parentFolder, ElasticsearchIntegrationTest.Scope scope) {
|
||||
super(numOfNodes, ImmutableSettings.builder()
|
||||
.put("node.mode", "network")
|
||||
.put("plugin.types", ShieldPlugin.class.getName())
|
||||
.put("plugins.load_classpath_plugins", false)
|
||||
.build(),
|
||||
scope);
|
||||
|
@ -91,6 +92,7 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
public Settings node(int nodeOrdinal) {
|
||||
File folder = createFolder(parentFolder, subfolderPrefix + "-" + nodeOrdinal);
|
||||
ImmutableSettings.Builder builder = ImmutableSettings.builder().put(super.node(nodeOrdinal))
|
||||
.put("plugin.types", ShieldPlugin.class.getName() + "," + licensePluginClass().getName())
|
||||
.put("shield.audit.enabled", RandomizedTest.randomBoolean())
|
||||
.put(InternalSignatureService.FILE_SETTING, writeFile(folder, "system_key", systemKey))
|
||||
.put("shield.authc.realms.esusers.type", ESUsersRealm.TYPE)
|
||||
|
@ -110,6 +112,16 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings transportClient() {
|
||||
ImmutableSettings.Builder builder = ImmutableSettings.builder().put(super.transportClient())
|
||||
.put("plugin.types", ShieldPlugin.class.getName())
|
||||
.put(getClientSSLSettings());
|
||||
setUser(builder, transportClientUsername(), transportClientPassword());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
protected String configUsers() {
|
||||
return CONFIG_STANDARD_USER;
|
||||
}
|
||||
|
@ -138,12 +150,12 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
return new SecuredString(DEFAULT_PASSWORD.toCharArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings transportClient() {
|
||||
ImmutableSettings.Builder builder = ImmutableSettings.builder().put(super.transportClient())
|
||||
.put(getClientSSLSettings());
|
||||
setUser(builder, transportClientUsername(), transportClientPassword());
|
||||
return builder.build();
|
||||
protected Class<? extends Plugin> licensePluginClass() {
|
||||
return LicensePlugin.class;
|
||||
}
|
||||
|
||||
protected String licensePluginName() {
|
||||
return LicensePlugin.NAME;
|
||||
}
|
||||
|
||||
private void setUser(ImmutableSettings.Builder builder, String username, SecuredString password) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.action.Action;
|
|||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.util.Callback;
|
||||
import org.elasticsearch.test.ShieldIntegrationTest;
|
||||
import org.elasticsearch.license.plugin.LicensePlugin;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -28,18 +29,18 @@ public class KnownActionsTests extends ShieldIntegrationTest {
|
|||
|
||||
private static ImmutableSet<String> knownActions;
|
||||
private static ImmutableSet<String> knownHandlers;
|
||||
private static ImmutableSet<String> coreActions;
|
||||
private static ImmutableSet<String> externalActions;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() throws Exception {
|
||||
knownActions = loadKnownActions();
|
||||
knownHandlers = loadKnownHandlers();
|
||||
coreActions = loadCoreActions();
|
||||
externalActions = loadExternalActions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllCoreTransportHandlersAreKnown() {
|
||||
TransportService transportService = internalCluster().getInstance(TransportService.class);
|
||||
public void testAllExternalTransportHandlersAreKnown() {
|
||||
TransportService transportService = internalCluster().getDataNodeInstance(TransportService.class);
|
||||
for (String handler : transportService.serverHandlers.keySet()) {
|
||||
if (!knownActions.contains(handler)) {
|
||||
assertThat("elasticsearch core transport handler [" + handler + "] is unknown to shield", knownHandlers, hasItem(handler));
|
||||
|
@ -48,8 +49,8 @@ public class KnownActionsTests extends ShieldIntegrationTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAllCoreActionsAreKnown() throws Exception {
|
||||
for (String action : coreActions) {
|
||||
public void testAllExternalActionsAreKnown() throws Exception {
|
||||
for (String action : externalActions) {
|
||||
assertThat("elasticsearch core action [" + action + "] is unknown to shield", knownActions, hasItem(action));
|
||||
}
|
||||
}
|
||||
|
@ -57,13 +58,13 @@ public class KnownActionsTests extends ShieldIntegrationTest {
|
|||
@Test
|
||||
public void testAllKnownActionsAreValid() {
|
||||
for (String knownAction : knownActions) {
|
||||
assertThat("shield known action [" + knownAction + "] is unknown to core", coreActions, hasItems(knownAction));
|
||||
assertThat("shield known action [" + knownAction + "] is unknown to core", externalActions, hasItems(knownAction));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllKnownTransportHandlersAreValid() {
|
||||
TransportService transportService = internalCluster().getInstance(TransportService.class);
|
||||
TransportService transportService = internalCluster().getDataNodeInstance(TransportService.class);
|
||||
for (String knownHandler : knownHandlers) {
|
||||
assertThat("shield known action [" + knownHandler + "] is unknown to core", transportService.serverHandlers.keySet(), hasItems(knownHandler));
|
||||
}
|
||||
|
@ -99,10 +100,22 @@ public class KnownActionsTests extends ShieldIntegrationTest {
|
|||
return knownHandlersBuilder.build();
|
||||
}
|
||||
|
||||
private static ImmutableSet<String> loadCoreActions() throws IOException, IllegalAccessException {
|
||||
ImmutableSet.Builder<String> coreActionsBuilder = ImmutableSet.builder();
|
||||
private static ImmutableSet<String> loadExternalActions() throws IOException, IllegalAccessException {
|
||||
ImmutableSet.Builder<String> actions = ImmutableSet.builder();
|
||||
|
||||
// loading es core actions
|
||||
ClassPath classPath = ClassPath.from(Action.class.getClassLoader());
|
||||
ImmutableSet<ClassPath.ClassInfo> infos = classPath.getTopLevelClassesRecursive(Action.class.getPackage().getName());
|
||||
loadActions(classPath, Action.class.getPackage().getName(), actions);
|
||||
|
||||
// also loading all actions from the licensing plugin
|
||||
classPath = ClassPath.from(LicensePlugin.class.getClassLoader());
|
||||
loadActions(classPath, LicensePlugin.class.getPackage().getName(), actions);
|
||||
|
||||
return actions.build();
|
||||
}
|
||||
|
||||
private static void loadActions(ClassPath classPath, String packageName, ImmutableSet.Builder<String> actions) throws IOException, IllegalAccessException {
|
||||
ImmutableSet<ClassPath.ClassInfo> infos = classPath.getTopLevelClassesRecursive(packageName);
|
||||
for (ClassPath.ClassInfo info : infos) {
|
||||
Class clazz = info.load();
|
||||
if (Action.class.isAssignableFrom(clazz)) {
|
||||
|
@ -115,10 +128,9 @@ public class KnownActionsTests extends ShieldIntegrationTest {
|
|||
}
|
||||
assertThat("every action should have a static field called INSTANCE, present but not static in " + clazz.getName(),
|
||||
Modifier.isStatic(field.getModifiers()), is(true));
|
||||
coreActionsBuilder.add(((Action) field.get(null)).name());
|
||||
actions.add(((Action) field.get(null)).name());
|
||||
}
|
||||
}
|
||||
}
|
||||
return coreActionsBuilder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,4 +73,7 @@ indices:data/write/delete/by_query
|
|||
indices:data/write/index
|
||||
indices:data/write/script/delete
|
||||
indices:data/write/script/put
|
||||
indices:data/write/update
|
||||
indices:data/write/update
|
||||
cluster:admin/plugin/license/get
|
||||
cluster:admin/plugin/license/delete
|
||||
cluster:admin/plugin/license/put
|
|
@ -83,3 +83,4 @@ internal:index/shard/recovery/start_recovery
|
|||
internal:index/shard/recovery/translog_ops
|
||||
internal:river/state/publish
|
||||
internal:admin/repository/verify
|
||||
internal:plugin/license/cluster/register_trial_license
|
||||
|
|
|
@ -35,6 +35,7 @@ grant {
|
|||
permission java.security.SecurityPermission "putProviderProperty.BC";
|
||||
permission java.security.SecurityPermission "insertProvider.BC";
|
||||
permission java.security.SecurityPermission "getProperty.ssl.KeyManagerFactory.algorithm";
|
||||
permission java.security.SecurityPermission "getProperty.ssl.TrustManagerFactory.algorithm";
|
||||
|
||||
//this shouldn't be in a production environment, just to run tests:
|
||||
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
|
||||
|
|
Loading…
Reference in New Issue