diff --git a/pom.xml b/pom.xml index 67186f0d63f..3affdfaaaaa 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 4.10.2 4.10.2 1.4.2 - 1.0.0-beta2 + 1.0.0-SNAPSHOT auto true diff --git a/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java b/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java index 027a35f581e..f0d92f94ddb 100644 --- a/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java +++ b/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java @@ -18,7 +18,6 @@ import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; 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; @@ -38,7 +37,7 @@ import java.util.List; */ public class ShieldActionFilter extends AbstractComponent implements ActionFilter { - private static final Predicate READ_ACTION_MATCHER = Privilege.Index.READ.predicate(); + private static final Predicate LICESE_EXPIRATION_ACTION_MATCHER = Privilege.HEALTH_AND_STATS.predicate(); private final AuthenticationService authcService; private final AuthorizationService authzService; @@ -57,14 +56,14 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte this.signatureService = signatureService; this.auditTrail = auditTrail; this.actionMapper = actionMapper; - licenseEventsNotifier.register(new LicensesClientService.Listener() { + licenseEventsNotifier.register(new LicenseEventsNotifier.Listener() { @Override - public void onEnabled() { + public void enabled() { licenseEnabled = true; } @Override - public void onDisabled() { + public void disabled() { licenseEnabled = false; } }); @@ -77,8 +76,10 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte 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)) { - logger.error("blocking read operation [{}] due to disabled license", action); + if (!licenseEnabled && LICESE_EXPIRATION_ACTION_MATCHER.apply(action)) { + logger.error("blocking [{}] operation due to expired license. Cluster health, cluster stats and indices stats \n" + + "operations are blocked on shield license expiration. All data operations (read and write) continue to work. \n" + + "If you have a new license, please update it. Otherwise, please reach out to your support contact.", action); throw new LicenseExpiredException(LicenseService.FEATURE_NAME); } diff --git a/src/main/java/org/elasticsearch/shield/authz/Privilege.java b/src/main/java/org/elasticsearch/shield/authz/Privilege.java index 5fac995903b..e221ff6573b 100644 --- a/src/main/java/org/elasticsearch/shield/authz/Privilege.java +++ b/src/main/java/org/elasticsearch/shield/authz/Privilege.java @@ -40,6 +40,7 @@ public abstract class Privilege

> { static final String SUB_ACTION_SUFFIX_PATTERN = "*"; public static final System SYSTEM = new System(); + public static final General HEALTH_AND_STATS = new General("health_and_stats", "cluster:monitor/health*", "cluster:monitor/stats*", "indices:monitor/stats*"); protected final Name name; @@ -106,6 +107,34 @@ public abstract class Privilege

> { } } + public static class General extends AutomatonPrivilege { + + private static final General NONE = new General(Name.NONE, Automata.makeEmpty()); + + public General(String name, String... patterns) { + super(name, patterns); + } + + public General(Name name, String... patterns) { + super(name, patterns); + } + + public General(Name name, Automaton automaton) { + super(name, automaton); + } + + @Override + protected General create(Name name, Automaton automaton) { + return new General(name, automaton); + } + + @Override + protected General none() { + return NONE; + } + } + + public static class Index extends AutomatonPrivilege { public static final Index NONE = new Index(Name.NONE, Automata.makeEmpty()); diff --git a/src/main/java/org/elasticsearch/shield/license/LicenseEventsNotifier.java b/src/main/java/org/elasticsearch/shield/license/LicenseEventsNotifier.java index bbcc18d55a1..5de13445386 100644 --- a/src/main/java/org/elasticsearch/shield/license/LicenseEventsNotifier.java +++ b/src/main/java/org/elasticsearch/shield/license/LicenseEventsNotifier.java @@ -5,8 +5,6 @@ */ package org.elasticsearch.shield.license; -import org.elasticsearch.license.plugin.core.LicensesClientService; - import java.util.HashSet; import java.util.Set; @@ -22,22 +20,28 @@ import java.util.Set; */ public class LicenseEventsNotifier { - private final Set listeners = new HashSet<>(); + private final Set listeners = new HashSet<>(); - public void register(LicensesClientService.Listener listener) { + public void register(Listener listener) { listeners.add(listener); } protected void notifyEnabled() { - for (LicensesClientService.Listener listener : listeners) { - listener.onEnabled(); + for (Listener listener : listeners) { + listener.enabled(); } } protected void notifyDisabled() { - for (LicensesClientService.Listener listener : listeners) { - listener.onDisabled(); + for (Listener listener : listeners) { + listener.disabled(); } } + public static interface Listener { + + void enabled(); + + void disabled(); + } } diff --git a/src/main/java/org/elasticsearch/shield/license/LicenseService.java b/src/main/java/org/elasticsearch/shield/license/LicenseService.java index d1b28bc59a4..c63999aefe9 100644 --- a/src/main/java/org/elasticsearch/shield/license/LicenseService.java +++ b/src/main/java/org/elasticsearch/shield/license/LicenseService.java @@ -6,14 +6,21 @@ package org.elasticsearch.shield.license; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.collect.ImmutableList; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.joda.FormatDateTimeFormatter; +import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.license.core.License; import org.elasticsearch.license.plugin.core.LicensesClientService; import org.elasticsearch.license.plugin.core.LicensesService; import org.elasticsearch.shield.ShieldPlugin; +import java.util.Collection; +import java.util.Locale; + /** * */ @@ -24,8 +31,11 @@ public class LicenseService extends AbstractLifecycleComponent { private static final LicensesService.TrialLicenseOptions TRIAL_LICENSE_OPTIONS = new LicensesService.TrialLicenseOptions(TimeValue.timeValueHours(30 * 24), 1000); + private static final FormatDateTimeFormatter DATE_FORMATTER = Joda.forPattern("EEEE, MMMMM dd, yyyy", Locale.ROOT); + private final LicensesClientService licensesClientService; private final LicenseEventsNotifier notifier; + private final Collection expirationLoggers; private boolean enabled = false; @@ -34,6 +44,41 @@ public class LicenseService extends AbstractLifecycleComponent { super(settings); this.licensesClientService = licensesClientService; this.notifier = notifier; + this.expirationLoggers = ImmutableList.of( + new LicensesService.ExpirationCallback.Pre(days(7), days(30), days(1)) { + @Override + public void on(License license, LicensesService.ExpirationStatus status) { + logger.error("\n" + + "#\n" + + "# Shield license will expire on [{}]. Cluster health, cluster stats and indices stats operations are\n" + + "# blocked on Shield license expiration. All data operations (read and write) continue to work. If you\n" + + "# have a new license, please update it. Otherwise, please reach out to your support contact.\n" + + "#", DATE_FORMATTER.printer().print(license.expiryDate())); + } + }, + new LicensesService.ExpirationCallback.Pre(days(0), days(7), minutes(10)) { + @Override + public void on(License license, LicensesService.ExpirationStatus status) { + logger.error("\n" + + "#\n" + + "# Shield license will expire on [{}]. Cluster health, cluster stats and indices stats operations are\n" + + "# blocked on Shield license expiration. All data operations (read and write) continue to work. If you\n" + + "# have a new license, please update it. Otherwise, please reach out to your support contact.\n" + + "#", DATE_FORMATTER.printer().print(license.expiryDate())); + } + }, + new LicensesService.ExpirationCallback.Post(days(0), null, minutes(10)) { + @Override + public void on(License license, LicensesService.ExpirationStatus status) { + logger.error("\n" + + "#\n" + + "# SHIELD LICENSE EXPIRED ON [{}]! CLUSTER HEALTH, CLUSTER STATS AND INDICES STATS OPERATIONS ARE\n" + + "# NOW BLOCKED. ALL DATA OPERATIONS (READ AND WRITE) CONTINUE TO WORK. IF YOU HAVE A NEW LICENSE, PLEASE\n" + + "# UPDATE IT. OTHERWISE, PLEASE REACH OUT TO YOUR SUPPORT CONTACT.\n" + + "#", DATE_FORMATTER.printer().print(license.expiryDate())); + } + } + ); } public synchronized boolean enabled() { @@ -43,10 +88,10 @@ public class LicenseService extends AbstractLifecycleComponent { @Override protected void doStart() throws ElasticsearchException { if (settings.getGroups("tribe", true).isEmpty()) { - licensesClientService.register(FEATURE_NAME, TRIAL_LICENSE_OPTIONS, new InternalListener()); + licensesClientService.register(FEATURE_NAME, TRIAL_LICENSE_OPTIONS, expirationLoggers, new InternalListener()); } else { //TODO currently we disable licensing on tribe node. remove this once es core supports merging cluster - new InternalListener().onEnabled(); + new InternalListener().onEnabled(null); } } @@ -58,22 +103,33 @@ public class LicenseService extends AbstractLifecycleComponent { protected void doClose() throws ElasticsearchException { } + static TimeValue days(int days) { + return TimeValue.timeValueHours(days * 24); + } + + static TimeValue minutes(int minutes) { + return TimeValue.timeValueMinutes(minutes); + } + class InternalListener implements LicensesClientService.Listener { @Override - public void onEnabled() { + public void onEnabled(License license) { synchronized (LicenseService.this) { + logger.info("enabling license for [{}]", FEATURE_NAME); enabled = true; notifier.notifyEnabled(); } } @Override - public void onDisabled() { + public void onDisabled(License license) { synchronized (LicenseService.this) { + logger.info("DISABLING LICENSE FOR [{}]", FEATURE_NAME); enabled = false; notifier.notifyDisabled(); } } } + } diff --git a/src/test/java/org/elasticsearch/integration/LicensingTests.java b/src/test/java/org/elasticsearch/integration/LicensingTests.java index 22ef9f8af89..59dc97b6ea8 100644 --- a/src/test/java/org/elasticsearch/integration/LicensingTests.java +++ b/src/test/java/org/elasticsearch/integration/LicensingTests.java @@ -5,9 +5,11 @@ */ package org.elasticsearch.integration; -import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; +import org.elasticsearch.action.admin.cluster.stats.ClusterStatsIndices; +import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse; +import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.index.IndexResponse; -import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.Client; import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.component.AbstractComponent; @@ -15,6 +17,7 @@ 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.core.License; import org.elasticsearch.license.plugin.core.LicenseExpiredException; import org.elasticsearch.license.plugin.core.LicensesClientService; import org.elasticsearch.license.plugin.core.LicensesService; @@ -31,12 +34,9 @@ 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; +import static org.hamcrest.Matchers.*; /** * @@ -44,6 +44,19 @@ import static org.hamcrest.Matchers.is; @ClusterScope(scope = SUITE) public class LicensingTests extends ShieldIntegrationTest { + static final License DUMMY_LICENSE = License.builder() + .feature(LicenseService.FEATURE_NAME) + .expiryDate(System.currentTimeMillis()) + .issueDate(System.currentTimeMillis()) + .issuedTo("LicensingTests") + .issuer("test") + .maxNodes(Integer.MAX_VALUE) + .signature("_signature") + .type("test_license_for_shield") + .subscriptionType("all_is_good") + .uid(String.valueOf(CHILD_JVM_ID) + System.identityHashCode(LicensingTests.class)) + .build(); + public static final String ROLES = ShieldSettingsSource.DEFAULT_ROLE + ":\n" + " cluster: all\n" + @@ -116,17 +129,26 @@ public class LicensingTests extends ShieldIntegrationTest { Client client = internalCluster().transportClient(); disableLicensing(); + try { - client.prepareSearch().setQuery(matchAllQuery()).get(); - fail("expected an license expired exception when running a search with disabled license"); + client.admin().indices().prepareStats().get(); + fail("expected an license expired exception when executing an index stats action"); } 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"); + client.admin().cluster().prepareClusterStats().get(); + fail("expected an license expired exception when executing cluster stats action"); + } catch (LicenseExpiredException lee) { + // expected + assertThat(lee.feature(), equalTo(LicenseService.FEATURE_NAME)); + } + + try { + client.admin().cluster().prepareHealth().get(); + fail("expected an license expired exception when executing cluster health action"); } catch (LicenseExpiredException lee) { // expected assertThat(lee.feature(), equalTo(LicenseService.FEATURE_NAME)); @@ -134,27 +156,17 @@ public class LicensingTests extends ShieldIntegrationTest { enableLicensing(); - SearchResponse searchResponse = client.prepareSearch().setQuery(matchAllQuery()).get(); - assertNoFailures(searchResponse); - assertHitCount(searchResponse, 2); + IndicesStatsResponse indicesStatsResponse = client.admin().indices().prepareStats().get(); + assertNoFailures(indicesStatsResponse); - GetResponse getResponse = client.prepareGet("test1", "type", indexResponse.getId()).get(); - assertThat(getResponse.getId(), equalTo(indexResponse.getId())); + ClusterStatsResponse clusterStatsNodeResponse = client.admin().cluster().prepareClusterStats().get(); + assertThat(clusterStatsNodeResponse, notNullValue()); + ClusterStatsIndices indices = clusterStatsNodeResponse.getIndicesStats(); + assertThat(indices, notNullValue()); + assertThat(indices.getIndexCount(), is(2)); - 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)); + ClusterHealthResponse clusterIndexHealth = client.admin().cluster().prepareHealth().get(); + assertThat(clusterIndexHealth, notNullValue()); } public static void disableLicensing() { @@ -208,20 +220,20 @@ public class LicensingTests extends ShieldIntegrationTest { } @Override - public void register(String feature, LicensesService.TrialLicenseOptions trialLicenseOptions, Listener listener) { + public void register(String s, LicensesService.TrialLicenseOptions trialLicenseOptions, Collection collection, Listener listener) { listeners.add(listener); enable(); } void enable() { for (Listener listener : listeners) { - listener.onEnabled(); + listener.onEnabled(DUMMY_LICENSE); } } void disable() { for (Listener listener : listeners) { - listener.onDisabled(); + listener.onDisabled(DUMMY_LICENSE); } } } diff --git a/src/test/java/org/elasticsearch/shield/ShieldPluginEnabledDisabledTests.java b/src/test/java/org/elasticsearch/shield/ShieldPluginEnabledDisabledTests.java index beafbd9e761..0593231f41c 100644 --- a/src/test/java/org/elasticsearch/shield/ShieldPluginEnabledDisabledTests.java +++ b/src/test/java/org/elasticsearch/shield/ShieldPluginEnabledDisabledTests.java @@ -26,6 +26,7 @@ import org.elasticsearch.test.rest.json.JsonPath; import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.TransportService; import org.hamcrest.Matcher; +import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; @@ -49,6 +50,15 @@ public class ShieldPluginEnabledDisabledTests extends ShieldIntegrationTest { enabled = randomBoolean(); } + @After + public void cleanup() throws Exception { + // now that on a disabled license we block cluster health/stats and indices stats, we need + // to make sure that after the tests (which disable the license for testing purposes) we + // reenabled the license, so the internal cluster will be cleaned appropriately. + logger.info("cleanup: enabling licensing..."); + LicensingTests.enableLicensing(); + } + @Override protected Settings nodeSettings(int nodeOrdinal) { logger.info("******* shield is " + (enabled ? "enabled" : "disabled")); diff --git a/src/test/java/org/elasticsearch/shield/action/ShieldActionFilterTests.java b/src/test/java/org/elasticsearch/shield/action/ShieldActionFilterTests.java index 3c2e40d2137..337325b3b4a 100644 --- a/src/test/java/org/elasticsearch/shield/action/ShieldActionFilterTests.java +++ b/src/test/java/org/elasticsearch/shield/action/ShieldActionFilterTests.java @@ -10,15 +10,14 @@ import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.support.ActionFilterChain; import org.elasticsearch.common.settings.ImmutableSettings; -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.shield.signature.SignatureService; import org.elasticsearch.test.ElasticsearchTestCase; import org.junit.Before; import org.junit.Test; @@ -110,8 +109,8 @@ public class ShieldActionFilterTests extends ElasticsearchTestCase { private class MockLicenseEventsNotifier extends LicenseEventsNotifier { @Override - public void register(LicensesClientService.Listener listener) { - listener.onEnabled(); + public void register(MockLicenseEventsNotifier.Listener listener) { + listener.enabled(); } } } diff --git a/src/test/java/org/elasticsearch/shield/test/ShieldTestUtils.java b/src/test/java/org/elasticsearch/shield/test/ShieldTestUtils.java index 623c3b25e8f..97f58b2dfb2 100644 --- a/src/test/java/org/elasticsearch/shield/test/ShieldTestUtils.java +++ b/src/test/java/org/elasticsearch/shield/test/ShieldTestUtils.java @@ -7,6 +7,7 @@ package org.elasticsearch.shield.test; import com.google.common.base.Charsets; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.io.FileSystemUtils; import org.elasticsearch.common.io.Streams; import java.io.File; @@ -15,6 +16,20 @@ import java.nio.file.Path; public class ShieldTestUtils { + public static File createFolder(File parent, String name) { + File createdFolder = new File(parent, name); + //the directory might exist e.g. if the global cluster gets restarted, then we recreate the directory as well + if (createdFolder.exists()) { + if (!FileSystemUtils.deleteRecursively(createdFolder)) { + throw new RuntimeException("could not delete existing temporary folder: " + createdFolder.getAbsolutePath()); + } + } + if (!createdFolder.mkdir()) { + throw new RuntimeException("could not create temporary folder: " + createdFolder.getAbsolutePath()); + } + return createdFolder; + } + public static String writeFile(File folder, String name, byte[] content) { Path file = folder.toPath().resolve(name); try { diff --git a/src/test/java/org/elasticsearch/shield/transport/ServerTransportFilterIntegrationTest.java b/src/test/java/org/elasticsearch/shield/transport/ServerTransportFilterIntegrationTest.java index 59dab148868..4248e5daa55 100644 --- a/src/test/java/org/elasticsearch/shield/transport/ServerTransportFilterIntegrationTest.java +++ b/src/test/java/org/elasticsearch/shield/transport/ServerTransportFilterIntegrationTest.java @@ -5,13 +5,16 @@ */ package org.elasticsearch.shield.transport; -import org.elasticsearch.ElasticsearchTimeoutException; +import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.ImmutableMap; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.TransportAddress; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.discovery.MasterNotDiscoveredException; import org.elasticsearch.node.Node; import org.elasticsearch.node.internal.InternalNode; +import org.elasticsearch.shield.authc.esusers.ESUsersRealm; import org.elasticsearch.shield.signature.InternalSignatureService; import org.elasticsearch.test.ShieldIntegrationTest; import org.elasticsearch.test.ShieldSettingsSource; @@ -24,6 +27,8 @@ import java.net.InetSocketAddress; import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder; import static org.elasticsearch.node.NodeBuilder.nodeBuilder; +import static org.elasticsearch.shield.test.ShieldTestUtils.createFolder; +import static org.elasticsearch.shield.test.ShieldTestUtils.writeFile; import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope; import static org.hamcrest.CoreMatchers.instanceOf; @@ -108,11 +113,19 @@ public class ServerTransportFilterIntegrationTest extends ShieldIntegrationTest Settings dataNodeSettings = internalCluster().getDataNodeInstance(Settings.class); String systemKeyFile = dataNodeSettings.get(InternalSignatureService.FILE_SETTING); + File folder = createFolder(globalTempDir(), getClass().getSimpleName() + "-" + randomAsciiOfLength(10)); + // test that starting up a node works Settings nodeSettings = settingsBuilder() + .put("shield.authc.realms.esusers.type", ESUsersRealm.TYPE) + .put("shield.authc.realms.esusers.order", 0) + .put("shield.authc.realms.esusers.files.users", writeFile(folder, "users", configUsers())) + .put("shield.authc.realms.esusers.files.users_roles", writeFile(folder, "users_roles", configUsersRoles())) + .put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", configRoles())) .put(ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode")) .put("node.mode", "network") .put("node.name", "my-test-node") + .put("shield.user", "test_user:changeme") .put("cluster.name", internalCluster().getClusterName()) .put("discovery.zen.ping.multicast.enabled", false) .put("discovery.zen.ping.unicast.hosts", "localhost:" + randomClientPort) @@ -127,9 +140,21 @@ public class ServerTransportFilterIntegrationTest extends ShieldIntegrationTest // assert that node is not connected by waiting for the timeout try { - node.client().admin().cluster().prepareHealth().get("1s"); - fail("Expected timeout exception due to node unable to connect"); - } catch (ElasticsearchTimeoutException e) {} + // updating cluster settings requires a master. since the node should not be able to + // connect to the cluster, there should be no master, and therefore this + // operation should fail. we can't use cluster health/stats here to and + // wait for a timeout, because as long as the node is not connected to the cluster + // the license is disabled and therefore blocking health & stats calls. + node.client().admin().cluster().prepareUpdateSettings() + .setTransientSettings(ImmutableMap.of("key", "value")) + .setMasterNodeTimeout(TimeValue.timeValueSeconds(2)) + .get(); + fail("Expected to fail update settings as the node should not be able to connect to the cluster, and therefore there should be no master"); + } catch (MasterNotDiscoveredException e) { + // expected + logger.error("expected: " + e); + } } } + } diff --git a/src/test/java/org/elasticsearch/shield/transport/filter/IpFilteringIntegrationTests.java b/src/test/java/org/elasticsearch/shield/transport/filter/IpFilteringIntegrationTests.java index a17fccd9ea9..e93a3283536 100644 --- a/src/test/java/org/elasticsearch/shield/transport/filter/IpFilteringIntegrationTests.java +++ b/src/test/java/org/elasticsearch/shield/transport/filter/IpFilteringIntegrationTests.java @@ -29,7 +29,7 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; // no client nodes, no transport clients, as they all get rejected on network connections -@ClusterScope(scope = Scope.SUITE, numDataNodes = 1, numClientNodes = 0, transportClientRatio = 0.0) +@ClusterScope(scope = Scope.SUITE, numDataNodes = 0, numClientNodes = 0, transportClientRatio = 0.0) public class IpFilteringIntegrationTests extends ShieldIntegrationTest { private static int randomClientPort; diff --git a/src/test/java/org/elasticsearch/test/ShieldSettingsSource.java b/src/test/java/org/elasticsearch/test/ShieldSettingsSource.java index cbc0dc89883..ea76b716154 100644 --- a/src/test/java/org/elasticsearch/test/ShieldSettingsSource.java +++ b/src/test/java/org/elasticsearch/test/ShieldSettingsSource.java @@ -18,6 +18,7 @@ import org.elasticsearch.shield.authc.esusers.ESUsersRealm; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.signature.InternalSignatureService; +import org.elasticsearch.shield.test.ShieldTestUtils; import org.elasticsearch.shield.transport.netty.NettySecuredTransport; import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration; @@ -107,7 +108,7 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ @Override public Settings node(int nodeOrdinal) { - File folder = createFolder(parentFolder, subfolderPrefix + "-" + nodeOrdinal); + File folder = ShieldTestUtils.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", randomBoolean()) @@ -184,20 +185,6 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ } } - private static File createFolder(File parent, String name) { - File createdFolder = new File(parent, name); - //the directory might exist e.g. if the global cluster gets restarted, then we recreate the directory as well - if (createdFolder.exists()) { - if (!FileSystemUtils.deleteRecursively(createdFolder)) { - throw new RuntimeException("could not delete existing temporary folder: " + createdFolder.getAbsolutePath()); - } - } - if (!createdFolder.mkdir()) { - throw new RuntimeException("could not create temporary folder: " + createdFolder.getAbsolutePath()); - } - return createdFolder; - } - private static byte[] generateKey() { try { return InternalSignatureService.generateKey();