From 286d62f00e477cd70b5963ca0689e9c55b92e13a Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Tue, 7 Feb 2017 08:56:04 +1100 Subject: [PATCH] Don't clear realm-cache during security upgrade on basic license (elastic/elasticsearch#4806) If a user has a basic license, but previously had a full-featured license (e.g. a trial license that expired) then they may have .security index that needs to be migrated even though security is not allowed under their license. This change makes the clearing of the realm-cache conditional on the license state. If X-Pack is running on a license that does not allow auth, then, when the `logstash_system` user is disabled as part of an upgrade migration, the cache is not cleared. This change also fix a bug whereby a mapping update could take place even if a data migration was in progress, which could cause the `logstash_system` user to be temporarily enabled when it ought not be. Original commit: elastic/x-pack-elasticsearch@f272e2b19f77c1ad47995b819a82e15e24c3a0de --- .../xpack/security/Security.java | 2 +- .../security/SecurityLifecycleService.java | 6 +- .../security/SecurityTemplateService.java | 5 +- .../authc/esnative/NativeRealmMigrator.java | 10 +- .../authc/esnative/NativeUsersStore.java | 15 +- .../elasticsearch/license/LicensingTests.java | 156 +++++++++++++----- .../SecurityTemplateServiceTests.java | 6 +- .../esnative/NativeRealmMigratorTests.java | 20 ++- 8 files changed, 162 insertions(+), 58 deletions(-) diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/Security.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/Security.java index d70958c2994..0e367bbde25 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -337,7 +337,7 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin { components.add(authzService); components.add(new SecurityLifecycleService(settings, clusterService, threadPool, indexAuditTrail, - nativeUsersStore, nativeRolesStore, client)); + nativeUsersStore, nativeRolesStore, licenseState, client)); ipFilter.set(new IPFilter(settings, auditTrailService, clusterService.getClusterSettings(), licenseState)); components.add(ipFilter.get()); diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java index d75243185c3..8309fcff46a 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.component.LifecycleListener; import org.elasticsearch.common.inject.internal.Nullable; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.AbstractRunnable; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; import org.elasticsearch.xpack.security.authc.esnative.NativeRealmMigrator; @@ -40,7 +41,7 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust public SecurityLifecycleService(Settings settings, ClusterService clusterService, ThreadPool threadPool, @Nullable IndexAuditTrail indexAuditTrail, NativeUsersStore nativeUserStore, - NativeRolesStore nativeRolesStore, InternalClient client) { + NativeRolesStore nativeRolesStore, XPackLicenseState licenseState, InternalClient client) { super(settings); this.settings = settings; this.threadPool = threadPool; @@ -53,7 +54,8 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust clusterService.addListener(this); clusterService.addListener(nativeUserStore); clusterService.addListener(nativeRolesStore); - clusterService.addListener(new SecurityTemplateService(settings, client, new NativeRealmMigrator(settings, nativeUserStore))); + final NativeRealmMigrator nativeRealmMigrator = new NativeRealmMigrator(settings, nativeUserStore, licenseState); + clusterService.addListener(new SecurityTemplateService(settings, client, nativeRealmMigrator)); clusterService.addLifecycleListener(new LifecycleListener() { @Override diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/SecurityTemplateService.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/SecurityTemplateService.java index 8e866e40846..3ab973f3ef6 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/SecurityTemplateService.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/SecurityTemplateService.java @@ -140,12 +140,13 @@ public class SecurityTemplateService extends AbstractComponent implements Cluste }); return true; } else { - andThen.run(); + if (upgradeDataState.get() == UpgradeState.COMPLETE) { + andThen.run(); + } return false; } } - private void updateSecurityMapping() { // only update the mapping if this is not already in progress if (updateMappingPending.compareAndSet(false, true) ) { diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmMigrator.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmMigrator.java index 4b404e50e4a..0c7ee76e68e 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmMigrator.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmMigrator.java @@ -12,6 +12,7 @@ import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.common.inject.internal.Nullable; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.xpack.security.SecurityTemplateService; import org.elasticsearch.xpack.security.user.LogstashSystemUser; @@ -24,10 +25,12 @@ import org.elasticsearch.xpack.security.user.LogstashSystemUser; public class NativeRealmMigrator { private final NativeUsersStore nativeUsersStore; + private final XPackLicenseState licenseState; private final Logger logger; - public NativeRealmMigrator(Settings settings, NativeUsersStore nativeUsersStore) { + public NativeRealmMigrator(Settings settings, NativeUsersStore nativeUsersStore, XPackLicenseState licenseState) { this.nativeUsersStore = nativeUsersStore; + this.licenseState = licenseState; this.logger = Loggers.getLogger(getClass(), settings); } @@ -48,7 +51,10 @@ public class NativeRealmMigrator { if (shouldDisableLogstashUser(previousVersion)) { logger.info("Upgrading security from version [{}] - new reserved user [{}] will default to disabled", previousVersion, LogstashSystemUser.NAME); - nativeUsersStore.ensureReservedUserIsDisabled(LogstashSystemUser.NAME, new ActionListener() { + // Only clear the cache is authentication is allowed by the current license + // otherwise the license management checks will prevent it from completing successfully. + final boolean clearCache = licenseState.isAuthAllowed(); + nativeUsersStore.ensureReservedUserIsDisabled(LogstashSystemUser.NAME, clearCache, new ActionListener() { @Override public void onResponse(Void aVoid) { listener.onResponse(true); diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java index af4b16d1dcd..5f6c00d853d 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java @@ -12,7 +12,6 @@ import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.DocWriteResponse; -import org.elasticsearch.action.DocWriteResponse.Result; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetRequest; @@ -396,7 +395,7 @@ public class NativeUsersStore extends AbstractComponent implements ClusterStateL } if (ReservedRealm.isReserved(username, settings)) { - setReservedUserEnabled(username, enabled, refreshPolicy, listener); + setReservedUserEnabled(username, enabled, refreshPolicy, true, listener); } else { setRegularUserEnabled(username, enabled, refreshPolicy, listener); } @@ -434,10 +433,10 @@ public class NativeUsersStore extends AbstractComponent implements ClusterStateL } } - void ensureReservedUserIsDisabled(final String username, final ActionListener listener) { + void ensureReservedUserIsDisabled(final String username, boolean clearCache, final ActionListener listener) { getReservedUserInfo(username, ActionListener.wrap(userInfo -> { if (userInfo == null || userInfo.enabled) { - setReservedUserEnabled(username, false, RefreshPolicy.IMMEDIATE, listener); + setReservedUserEnabled(username, false, RefreshPolicy.IMMEDIATE, clearCache, listener); } else { listener.onResponse(null); } @@ -445,7 +444,7 @@ public class NativeUsersStore extends AbstractComponent implements ClusterStateL } private void setReservedUserEnabled(final String username, final boolean enabled, final RefreshPolicy refreshPolicy, - final ActionListener listener) { + boolean clearCache, final ActionListener listener) { try { client.prepareUpdate(SecurityTemplateService.SECURITY_INDEX_NAME, RESERVED_USER_DOC_TYPE, username) .setDoc(Requests.INDEX_CONTENT_TYPE, User.Fields.ENABLED.getPreferredName(), enabled) @@ -456,7 +455,11 @@ public class NativeUsersStore extends AbstractComponent implements ClusterStateL .execute(new ActionListener() { @Override public void onResponse(UpdateResponse updateResponse) { - clearRealmCache(username, listener, null); + if (clearCache) { + clearRealmCache(username, listener, null); + } else { + listener.onResponse(null); + } } @Override diff --git a/elasticsearch/src/test/java/org/elasticsearch/license/LicensingTests.java b/elasticsearch/src/test/java/org/elasticsearch/license/LicensingTests.java index 064eccc7a05..2d1710ca0c6 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/license/LicensingTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/license/LicensingTests.java @@ -7,21 +7,43 @@ package org.elasticsearch.license; import org.apache.http.message.BasicHeader; import org.elasticsearch.ElasticsearchSecurityException; +import org.elasticsearch.Version; +import org.elasticsearch.action.ActionFuture; +import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.DocWriteResponse; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse; import org.elasticsearch.action.admin.cluster.stats.ClusterStatsIndices; import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; +import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; +import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; +import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; +import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; +import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; +import org.elasticsearch.action.get.GetRequest; +import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.client.Client; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.test.SecurityIntegTestCase; @@ -31,18 +53,27 @@ import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.TestXPackTransportClient; import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.Security; +import org.elasticsearch.xpack.security.SecurityTemplateService; import org.elasticsearch.xpack.security.action.user.GetUsersResponse; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.template.TemplateUtils; import org.junit.Before; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; @@ -50,37 +81,37 @@ import static org.hamcrest.Matchers.notNullValue; public class LicensingTests extends SecurityIntegTestCase { public static final String ROLES = - SecuritySettingsSource.DEFAULT_ROLE + ":\n" + - " cluster: [ all ]\n" + - " indices:\n" + - " - names: '*'\n" + - " privileges: [manage]\n" + - " - names: '/.*/'\n" + - " privileges: [write]\n" + - " - names: 'test'\n" + - " privileges: [read]\n" + - " - names: 'test1'\n" + - " privileges: [read]\n" + - "\n" + - "role_a:\n" + - " indices:\n" + - " - names: 'a'\n" + - " privileges: [all]\n" + - "\n" + - "role_b:\n" + - " indices:\n" + - " - names: 'b'\n" + - " privileges: [all]\n"; + SecuritySettingsSource.DEFAULT_ROLE + ":\n" + + " cluster: [ all ]\n" + + " indices:\n" + + " - names: '*'\n" + + " privileges: [manage]\n" + + " - names: '/.*/'\n" + + " privileges: [write]\n" + + " - names: 'test'\n" + + " privileges: [read]\n" + + " - names: 'test1'\n" + + " privileges: [read]\n" + + "\n" + + "role_a:\n" + + " indices:\n" + + " - names: 'a'\n" + + " privileges: [all]\n" + + "\n" + + "role_b:\n" + + " indices:\n" + + " - names: 'b'\n" + + " privileges: [all]\n"; public static final String USERS = - SecuritySettingsSource.CONFIG_STANDARD_USER + - "user_a:{plain}passwd\n" + - "user_b:{plain}passwd\n"; + SecuritySettingsSource.CONFIG_STANDARD_USER + + "user_a:{plain}passwd\n" + + "user_b:{plain}passwd\n"; public static final String USERS_ROLES = - SecuritySettingsSource.CONFIG_STANDARD_USER_ROLES + - "role_a:user_a,user_b\n" + - "role_b:user_b\n"; + SecuritySettingsSource.CONFIG_STANDARD_USER_ROLES + + "role_a:user_a,user_b\n" + + "role_b:user_b\n"; @Override protected String configRoles() { @@ -100,8 +131,8 @@ public class LicensingTests extends SecurityIntegTestCase { @Override public Settings nodeSettings(int nodeOrdinal) { return Settings.builder().put(super.nodeSettings(nodeOrdinal)) - .put(NetworkModule.HTTP_ENABLED.getKey(), true) - .build(); + .put(NetworkModule.HTTP_ENABLED.getKey(), true) + .build(); } @Override @@ -118,16 +149,16 @@ public class LicensingTests extends SecurityIntegTestCase { public void testEnableDisableBehaviour() throws Exception { IndexResponse indexResponse = index("test", "type", jsonBuilder() - .startObject() - .field("name", "value") - .endObject()); + .startObject() + .field("name", "value") + .endObject()); assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult()); indexResponse = index("test1", "type", jsonBuilder() - .startObject() - .field("name", "value1") - .endObject()); + .startObject() + .field("name", "value1") + .endObject()); assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult()); refresh(); @@ -169,7 +200,7 @@ public class LicensingTests extends SecurityIntegTestCase { // generate a new license with a mode that enables auth License.OperationMode mode = randomFrom(License.OperationMode.GOLD, License.OperationMode.TRIAL, - License.OperationMode.PLATINUM, License.OperationMode.STANDARD); + License.OperationMode.PLATINUM, License.OperationMode.STANDARD); enableLicensing(mode); e = expectThrows(ResponseException.class, () -> getRestClient().performRequest("GET", "/")); assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401)); @@ -211,7 +242,7 @@ public class LicensingTests extends SecurityIntegTestCase { public void testTransportClientAuthenticationByLicenseType() throws Exception { Settings.Builder builder = Settings.builder() - .put(internalCluster().transportClient().settings()); + .put(internalCluster().transportClient().settings()); // remove user info builder.remove(Security.USER_SETTING.getKey()); builder.remove(ThreadContext.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER); @@ -224,7 +255,7 @@ public class LicensingTests extends SecurityIntegTestCase { // enable a license that enables security License.OperationMode mode = randomFrom(License.OperationMode.GOLD, License.OperationMode.TRIAL, - License.OperationMode.PLATINUM, License.OperationMode.STANDARD); + License.OperationMode.PLATINUM, License.OperationMode.STANDARD); enableLicensing(mode); try (TransportClient client = new TestXPackTransportClient(builder.build())) { @@ -236,6 +267,55 @@ public class LicensingTests extends SecurityIntegTestCase { } } + public void testNativeRealmMigratorWorksUnderBasicLicense() throws Exception { + final String securityIndex = ".security"; + final String reservedUserType = "reserved-user"; + final String oldVersionThatRequiresMigration = Version.V_5_0_2.toString(); + + final Client client = internalCluster().transportClient(); + final String template = TemplateUtils.loadTemplate("/" + SecurityTemplateService.SECURITY_TEMPLATE_NAME + ".json", + oldVersionThatRequiresMigration, Pattern.quote("${security.template.version}")); + + PutIndexTemplateRequest putTemplateRequest = client.admin().indices() + .preparePutTemplate(SecurityTemplateService.SECURITY_TEMPLATE_NAME) + .setSource(new BytesArray(template.getBytes(StandardCharsets.UTF_8)), XContentType.JSON) + .request(); + final PutIndexTemplateResponse putTemplateResponse = client.admin().indices().putTemplate(putTemplateRequest).actionGet(); + assertThat(putTemplateResponse.isAcknowledged(), equalTo(true)); + + final CreateIndexRequest createIndexRequest = client.admin().indices().prepareCreate(securityIndex).request(); + final CreateIndexResponse createIndexResponse = client.admin().indices().create(createIndexRequest).actionGet(); + assertThat(createIndexResponse.isAcknowledged(), equalTo(true)); + + final Map templateMap = XContentHelper.convertToMap(JsonXContent.jsonXContent, template, false); + final Map mappings = (Map) templateMap.get("mappings"); + final Map reservedUserMapping = (Map) mappings.get(reservedUserType); + + final PutMappingRequest putMappingRequest = client.admin().indices() + .preparePutMapping(securityIndex).setSource(reservedUserMapping).setType(reservedUserType).request(); + + final PutMappingResponse putMappingResponse = client.admin().indices().putMapping(putMappingRequest).actionGet(); + assertThat(putMappingResponse.isAcknowledged(), equalTo(true)); + + final GetMappingsRequest getMappingsRequest = client.admin().indices().prepareGetMappings(securityIndex).request(); + final boolean upgradeOk = awaitBusy(() -> { + final GetMappingsResponse getMappingsResponse = client.admin().indices().getMappings(getMappingsRequest).actionGet(); + final MappingMetaData metaData = getMappingsResponse.mappings().get(securityIndex).get(reservedUserType); + try { + Map meta = (Map) metaData.sourceAsMap().get("_meta"); + return meta != null && Version.CURRENT.toString().equals(meta.get("security-version")); + } catch (IOException e) { + return false; + } + }, 1, TimeUnit.SECONDS); + assertThat(upgradeOk, equalTo(true)); + + final GetRequest getRequest = client.prepareGet(securityIndex, reservedUserType, "logstash_system").setRefresh(true).request(); + final GetResponse getResponse = client.get(getRequest).actionGet(); + assertThat(getResponse.isExists(), equalTo(true)); + assertThat(getResponse.getFields(), equalTo(Collections.emptyMap())); + } + private static void assertElasticsearchSecurityException(ThrowingRunnable runnable) { ElasticsearchSecurityException ee = expectThrows(ElasticsearchSecurityException.class, runnable); assertThat(ee.getMetadata(LicenseUtils.EXPIRED_FEATURE_METADATA), hasItem(XPackPlugin.SECURITY)); diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/SecurityTemplateServiceTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/SecurityTemplateServiceTests.java index a6b0e67c374..b4a34dfc7ca 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/SecurityTemplateServiceTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/SecurityTemplateServiceTests.java @@ -217,8 +217,8 @@ public class SecurityTemplateServiceTests extends ESTestCase { assertThat(securityTemplateService.upgradeDataState.get(), equalTo(UpgradeState.NOT_STARTED)); - securityTemplateService.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build() - , EMPTY_CLUSTER_STATE)); + securityTemplateService.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build(), + EMPTY_CLUSTER_STATE)); assertThat(migratorVersionRef.get(), equalTo(expectedOldVersion)); assertThat(migratorListenerRef.get(), notNullValue()); @@ -241,7 +241,7 @@ public class SecurityTemplateServiceTests extends ESTestCase { assertTrue(securityTemplateService.updateMappingPending.get()); // if we now simulate an error... - listener.onFailure(new Exception()); + listener.onFailure(new Exception("Testing failure handling")); assertFalse(securityTemplateService.updateMappingPending.get()); // ... we should be able to send a new update diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmMigratorTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmMigratorTests.java index 8de4c204a89..9255d1615c6 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmMigratorTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmMigratorTests.java @@ -12,6 +12,7 @@ import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.security.user.LogstashSystemUser; import org.junit.Before; @@ -19,28 +20,38 @@ import org.mockito.Mockito; import static org.hamcrest.Matchers.is; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; public class NativeRealmMigratorTests extends ESTestCase { private Consumer> ensureDisabledHandler; private NativeUsersStore nativeUsersStore; private NativeRealmMigrator migrator; + private XPackLicenseState licenseState; @Before public void setupMocks() { + final boolean allowClearCache = randomBoolean(); + ensureDisabledHandler = listener -> listener.onResponse(null); nativeUsersStore = Mockito.mock(NativeUsersStore.class); Mockito.doAnswer(invocation -> { - ActionListener listener = (ActionListener) invocation.getArguments()[1]; + ActionListener listener = (ActionListener) invocation.getArguments()[2]; ensureDisabledHandler.accept(listener); return null; - }).when(nativeUsersStore).ensureReservedUserIsDisabled(any(), any()); + }).when(nativeUsersStore).ensureReservedUserIsDisabled(any(), eq(allowClearCache), any()); final Settings settings = Settings.EMPTY; - migrator = new NativeRealmMigrator(settings, nativeUsersStore); + + licenseState = mock(XPackLicenseState.class); + when(licenseState.isAuthAllowed()).thenReturn(allowClearCache); + + migrator = new NativeRealmMigrator(settings, nativeUsersStore, licenseState); } public void testNoChangeOnFreshInstall() throws Exception { @@ -71,7 +82,8 @@ public class NativeRealmMigratorTests extends ESTestCase { private void verifyUpgradeDisablesLogstashSystemUser(Version fromVersion) throws ExecutionException, InterruptedException { final PlainActionFuture future = doUpgrade(fromVersion); - verify(nativeUsersStore).ensureReservedUserIsDisabled(eq(LogstashSystemUser.NAME), any()); + final boolean clearCache = licenseState.isAuthAllowed(); + verify(nativeUsersStore).ensureReservedUserIsDisabled(eq(LogstashSystemUser.NAME), eq(clearCache), any()); verifyNoMoreInteractions(nativeUsersStore); assertThat(future.get(), is(Boolean.TRUE)); }