diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/realm/TransportClearRealmCacheAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/realm/TransportClearRealmCacheAction.java index 48ed469a325..2bffcec0a8c 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/realm/TransportClearRealmCacheAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/realm/TransportClearRealmCacheAction.java @@ -48,7 +48,8 @@ public class TransportClearRealmCacheAction extends TransportNodesAction replaceWildcardsWithAuthorizedIndices(String[] indices, IndicesOptions indicesOptions, MetaData metaData, List authorizedIndices) { + // check for all and return list of authorized indices if (IndexNameExpressionResolver.isAllIndices(indicesList(indices))) { List visibleIndices = new ArrayList<>(); for (String authorizedIndex : authorizedIndices) { diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ClearRolesCacheTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ClearRolesCacheTests.java index 0626330c0a8..8ba77b32d07 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ClearRolesCacheTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ClearRolesCacheTests.java @@ -16,17 +16,15 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.shield.action.role.PutRoleResponse; import org.elasticsearch.shield.action.role.GetRolesResponse; import org.elasticsearch.shield.ShieldTemplateService; -import org.elasticsearch.shield.authc.esnative.ESNativeUsersStore; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authz.RoleDescriptor; import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore; import org.elasticsearch.shield.client.SecurityClient; -import org.elasticsearch.test.ShieldIntegTestCase; +import org.elasticsearch.test.NativeRealmIntegTestCase; import org.elasticsearch.test.ShieldSettingsSource; import org.elasticsearch.test.junit.annotations.TestLogging; import org.elasticsearch.test.rest.client.http.HttpResponse; -import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -35,7 +33,6 @@ import java.util.List; import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isOneOf; import static org.hamcrest.Matchers.notNullValue; /** @@ -43,7 +40,7 @@ import static org.hamcrest.Matchers.notNullValue; * test the cache clearing APIs. */ @TestLogging("shield.authc.esnative:TRACE,shield.authz.esnative:TRACE,integration:DEBUG") -public class ClearRolesCacheTests extends ShieldIntegTestCase { +public class ClearRolesCacheTests extends NativeRealmIntegTestCase { private static String[] roles; @@ -56,29 +53,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase { } @Before - public void setupForTest() throws Exception { - // Clear the realm cache for all realms since we use a SUITE scoped cluster - SecurityClient client = securityClient(internalCluster().transportClient()); - client.prepareClearRealmCache().get(); - - for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) { - assertBusy(new Runnable() { - @Override - public void run() { - assertThat(store.state(), is(ESNativeUsersStore.State.STARTED)); - } - }); - } - - for (ESNativeRolesStore store : internalCluster().getInstances(ESNativeRolesStore.class)) { - assertBusy(new Runnable() { - @Override - public void run() { - assertThat(store.state(), is(ESNativeRolesStore.State.STARTED)); - } - }); - } - + public void setupForTests() { SecurityClient c = securityClient(); // create roles for (String role : roles) { @@ -129,13 +104,11 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase { } public void testModifyingDocumentsDirectly() throws Exception { - Client client = internalCluster().transportClient(); - int modifiedRolesCount = randomIntBetween(1, roles.length); List toModify = randomSubsetOf(modifiedRolesCount, roles); logger.debug("--> modifying roles {} to have run_as", toModify); for (String role : toModify) { - UpdateResponse response = client.prepareUpdate().setId(role).setIndex(ShieldTemplateService.SECURITY_INDEX_NAME) + UpdateResponse response = internalClient().prepareUpdate().setId(role).setIndex(ShieldTemplateService.SECURITY_INDEX_NAME) .setType(ESNativeRolesStore.ROLE_DOC_TYPE) .setDoc("run_as", new String[] { role }) .get(); @@ -145,7 +118,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase { // in this test, the poller runs too frequently to check the cache still has roles without run as // clear the cache and we should definitely see the latest values! - SecurityClient securityClient = securityClient(client); + SecurityClient securityClient = securityClient(internalCluster().transportClient()); final boolean useHttp = randomBoolean(); final boolean clearAll = randomBoolean(); logger.debug("--> starting to clear roles. using http [{}] clearing all [{}]", useHttp, clearAll); @@ -171,14 +144,13 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase { } public void testDeletingRoleDocumentDirectly() throws Exception { - Client client = internalCluster().transportClient(); - SecurityClient securityClient = securityClient(client); + SecurityClient securityClient = securityClient(internalCluster().transportClient()); final String role = randomFrom(roles); RoleDescriptor[] foundRoles = securityClient.prepareGetRoles().names(role).get().roles(); assertThat(foundRoles.length, is(1)); logger.debug("--> deleting role [{}]", role); - DeleteResponse response = client + DeleteResponse response = internalClient() .prepareDelete(ShieldTemplateService.SECURITY_INDEX_NAME, ESNativeRolesStore.ROLE_DOC_TYPE, role).get(); assertThat(response.isFound(), is(true)); @@ -205,31 +177,4 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase { } } } - - @After - public void stopESNativeStores() throws Exception { - for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) { - store.stop(); - // the store may already be stopping so wait until it is stopped - assertBusy(new Runnable() { - @Override - public void run() { - assertThat(store.state(), isOneOf(ESNativeUsersStore.State.STOPPED, ESNativeUsersStore.State.FAILED)); - } - }); - store.reset(); - } - - for (ESNativeRolesStore store : internalCluster().getInstances(ESNativeRolesStore.class)) { - store.stop(); - // the store may already be stopping so wait until it is stopped - assertBusy(new Runnable() { - @Override - public void run() { - assertThat(store.state(), isOneOf(ESNativeRolesStore.State.STOPPED, ESNativeRolesStore.State.FAILED)); - } - }); - store.reset(); - } - } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esnative/ESNativeTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esnative/ESNativeTests.java index d3b76181a02..0700b09d5f4 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esnative/ESNativeTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esnative/ESNativeTests.java @@ -20,13 +20,10 @@ import org.elasticsearch.shield.action.user.DeleteUserResponse; import org.elasticsearch.shield.action.user.GetUsersResponse; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authz.RoleDescriptor; -import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore; import org.elasticsearch.shield.authz.permission.Role; import org.elasticsearch.shield.client.SecurityClient; -import org.elasticsearch.test.ShieldIntegTestCase; +import org.elasticsearch.test.NativeRealmIntegTestCase; import org.elasticsearch.test.ShieldSettingsSource; -import org.junit.After; -import org.junit.Before; import java.util.ArrayList; import java.util.Collections; @@ -36,12 +33,11 @@ import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basic import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isOneOf; /** * Tests for the ESNativeUsersStore and ESNativeRolesStore */ -public class ESNativeTests extends ShieldIntegTestCase { +public class ESNativeTests extends NativeRealmIntegTestCase { public void testDeletingNonexistingUserAndRole() throws Exception { SecurityClient c = securityClient(); @@ -390,56 +386,4 @@ public class ESNativeTests extends ShieldIntegTestCase { .admin().cluster().prepareHealth().get(); assertFalse(response.isTimedOut()); } - - @Before - public void ensureStoresStarted() throws Exception { - // Clear the realm cache for all realms since we use a SUITE scoped cluster - SecurityClient client = securityClient(); - client.prepareClearRealmCache().get(); - - for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) { - assertBusy(new Runnable() { - @Override - public void run() { - assertThat(store.state(), is(ESNativeUsersStore.State.STARTED)); - } - }); - } - - for (ESNativeRolesStore store : internalCluster().getInstances(ESNativeRolesStore.class)) { - assertBusy(new Runnable() { - @Override - public void run() { - assertThat(store.state(), is(ESNativeRolesStore.State.STARTED)); - } - }); - } - } - - @After - public void stopESNativeStores() throws Exception { - for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) { - store.stop(); - // the store may already be stopping so wait until it is stopped - assertBusy(new Runnable() { - @Override - public void run() { - assertThat(store.state(), isOneOf(ESNativeUsersStore.State.STOPPED, ESNativeUsersStore.State.FAILED)); - } - }); - store.reset(); - } - - for (ESNativeRolesStore store : internalCluster().getInstances(ESNativeRolesStore.class)) { - store.stop(); - // the store may already be stopping so wait until it is stopped - assertBusy(new Runnable() { - @Override - public void run() { - assertThat(store.state(), isOneOf(ESNativeRolesStore.State.STOPPED, ESNativeRolesStore.State.FAILED)); - } - }); - store.reset(); - } - } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/InternalAuthorizationServiceTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/InternalAuthorizationServiceTests.java index e9484a1a1e1..3e11e9dd00e 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/InternalAuthorizationServiceTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/InternalAuthorizationServiceTests.java @@ -7,26 +7,43 @@ package org.elasticsearch.shield.authz; import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.Version; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest; import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexAction; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; +import org.elasticsearch.action.delete.DeleteAction; +import org.elasticsearch.action.delete.DeleteRequest; +import org.elasticsearch.action.get.GetAction; +import org.elasticsearch.action.get.GetRequest; +import org.elasticsearch.action.index.IndexAction; +import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.ClearScrollAction; import org.elasticsearch.action.search.ClearScrollRequest; import org.elasticsearch.action.search.SearchAction; +import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchScrollAction; import org.elasticsearch.action.search.SearchScrollRequest; +import org.elasticsearch.action.termvectors.TermVectorsAction; +import org.elasticsearch.action.termvectors.TermVectorsRequest; +import org.elasticsearch.action.update.UpdateAction; +import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.cluster.ClusterService; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.search.action.SearchTransportService; +import org.elasticsearch.shield.ShieldTemplateService; import org.elasticsearch.shield.SystemUser; import org.elasticsearch.shield.User; +import org.elasticsearch.shield.XPackUser; import org.elasticsearch.shield.audit.AuditTrail; import org.elasticsearch.shield.authc.AnonymousService; import org.elasticsearch.shield.authc.DefaultAuthenticationFailureHandler; @@ -40,6 +57,7 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportRequest; import org.junit.Before; +import java.util.ArrayList; import java.util.List; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthenticationException; @@ -452,4 +470,84 @@ public class InternalAuthorizationServiceTests extends ESTestCase { verify(auditTrail).accessGranted(user, "indices:a", request); verifyNoMoreInteractions(auditTrail); } + + public void testNonXPackUserCannotExecuteOperationAgainstShieldIndex() { + User user = new User("all_access_user", "all_access"); + when(rolesStore.role("all_access")).thenReturn(Role.builder("all_access") + .add(IndexPrivilege.ALL, "*") + .cluster(ClusterPrivilege.ALL) + .build()); + ClusterState state = mock(ClusterState.class); + when(clusterService.state()).thenReturn(state); + when(state.metaData()).thenReturn(MetaData.builder() + .put(new IndexMetaData.Builder(ShieldTemplateService.SECURITY_INDEX_NAME) + .settings(Settings.builder().put("index.version.created", Version.CURRENT).build()) + .numberOfShards(1).numberOfReplicas(0).build(), true) + .build()); + + List> requests = new ArrayList<>(); + requests.add(new Tuple<>(DeleteAction.NAME, new DeleteRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(IndexAction.NAME, new IndexRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(ShieldTemplateService.SECURITY_INDEX_NAME))); + requests.add(new Tuple<>(TermVectorsAction.NAME, new TermVectorsRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(GetAction.NAME, new GetRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(TermVectorsAction.NAME, new TermVectorsRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest().addAlias("shield_alias", + ShieldTemplateService.SECURITY_INDEX_NAME))); + + for (Tuple requestTuple : requests) { + String action = requestTuple.v1(); + TransportRequest request = requestTuple.v2(); + try { + internalAuthorizationService.authorize(user, action, request); + fail("only the xpack user can execute operation [" + action + "] against the internal index"); + } catch (ElasticsearchSecurityException e) { + assertAuthorizationException(e, containsString("action [" + action + "] is unauthorized for user [all_access_user]")); + verify(auditTrail).accessDenied(user, action, request); + verifyNoMoreInteractions(auditTrail); + } + } + + // we should allow waiting for the health of the index or any index if the user has this permission + ClusterHealthRequest request = new ClusterHealthRequest(ShieldTemplateService.SECURITY_INDEX_NAME); + internalAuthorizationService.authorize(user, ClusterHealthAction.NAME, request); + verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request); + + // multiple indices + request = new ClusterHealthRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "foo", "bar"); + internalAuthorizationService.authorize(user, ClusterHealthAction.NAME, request); + verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request); + } + + public void testXPackUserCanExecuteOperationAgainstShieldIndex() { + ClusterState state = mock(ClusterState.class); + when(clusterService.state()).thenReturn(state); + when(state.metaData()).thenReturn(MetaData.builder() + .put(new IndexMetaData.Builder(ShieldTemplateService.SECURITY_INDEX_NAME) + .settings(Settings.builder().put("index.version.created", Version.CURRENT).build()) + .numberOfShards(1).numberOfReplicas(0).build(), true) + .build()); + + List> requests = new ArrayList<>(); + requests.add(new Tuple<>(DeleteAction.NAME, new DeleteRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(IndexAction.NAME, new IndexRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(ShieldTemplateService.SECURITY_INDEX_NAME))); + requests.add(new Tuple<>(TermVectorsAction.NAME, new TermVectorsRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(GetAction.NAME, new GetRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(TermVectorsAction.NAME, new TermVectorsRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "type", "id"))); + requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest().addAlias("shield_alias", + ShieldTemplateService.SECURITY_INDEX_NAME))); + requests.add(new Tuple<>(ClusterHealthAction.NAME, new ClusterHealthRequest(ShieldTemplateService.SECURITY_INDEX_NAME))); + requests.add(new Tuple<>(ClusterHealthAction.NAME, + new ClusterHealthRequest(ShieldTemplateService.SECURITY_INDEX_NAME, "foo", "bar"))); + + for (Tuple requestTuple : requests) { + String action = requestTuple.v1(); + TransportRequest request = requestTuple.v2(); + internalAuthorizationService.authorize(XPackUser.INSTANCE, action, request); + verify(auditTrail).accessGranted(XPackUser.INSTANCE, action, request); + } + } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolverTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolverTests.java index fb527aa4d3e..fe780d71b5a 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolverTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolverTests.java @@ -6,6 +6,8 @@ package org.elasticsearch.shield.authz.indicesresolver; import org.elasticsearch.Version; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesAction; @@ -20,31 +22,45 @@ import org.elasticsearch.action.search.SearchAction; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.Requests; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.AliasAction; import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexNotFoundException; +import org.elasticsearch.shield.ShieldTemplateService; import org.elasticsearch.shield.User; -import org.elasticsearch.shield.authz.AuthorizationService; +import org.elasticsearch.shield.XPackUser; +import org.elasticsearch.shield.audit.AuditTrail; +import org.elasticsearch.shield.authc.AnonymousService; +import org.elasticsearch.shield.authc.DefaultAuthenticationFailureHandler; +import org.elasticsearch.shield.authz.InternalAuthorizationService; +import org.elasticsearch.shield.authz.permission.Role; +import org.elasticsearch.shield.authz.privilege.ClusterPrivilege; +import org.elasticsearch.shield.authz.privilege.IndexPrivilege; +import org.elasticsearch.shield.authz.store.RolesStore; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.ThreadPool; import org.junit.Before; -import java.util.Arrays; -import java.util.Collections; import java.util.Set; -import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.arrayContainingInAnyOrder; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class DefaultIndicesResolverTests extends ESTestCase { + private User user; private User userNoIndices; + private RolesStore rolesStore; private MetaData metaData; private DefaultIndicesAndAliasesResolver defaultIndicesResolver; @@ -66,35 +82,23 @@ public class DefaultIndicesResolverTests extends ESTestCase { .put(indexBuilder("foofoo").putAlias(AliasMetaData.builder("barbaz")).settings(settings)) .put(indexBuilder("bar").settings(settings)) .put(indexBuilder("bar-closed").state(IndexMetaData.State.CLOSE).settings(settings)) - .put(indexBuilder("bar2").settings(settings)); + .put(indexBuilder("bar2").settings(settings)) + .put(indexBuilder(ShieldTemplateService.SECURITY_INDEX_NAME).settings(settings)); metaData = mdBuilder.build(); - AuthorizationService authzService = mock(AuthorizationService.class); user = new User("user", "role"); - - String[] authorizedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "missing", "foofoo-closed"}; - when(authzService.authorizedIndicesAndAliases(user, SearchAction.NAME)) - .thenReturn(Collections.unmodifiableList(Arrays.asList(authorizedIndices))); - when(authzService.authorizedIndicesAndAliases(user, MultiSearchAction.NAME)) - .thenReturn(Collections.unmodifiableList(Arrays.asList(authorizedIndices))); - when(authzService.authorizedIndicesAndAliases(user, MultiGetAction.NAME)) - .thenReturn(Collections.unmodifiableList(Arrays.asList(authorizedIndices))); - when(authzService.authorizedIndicesAndAliases(user, IndicesAliasesAction.NAME)) - .thenReturn(Collections.unmodifiableList(Arrays.asList(authorizedIndices))); - when(authzService.authorizedIndicesAndAliases(user, GetAliasesAction.NAME)) - .thenReturn(Collections.unmodifiableList(Arrays.asList(authorizedIndices))); - when(authzService.authorizedIndicesAndAliases(user, DeleteIndexAction.NAME)) - .thenReturn(Collections.unmodifiableList(Arrays.asList(authorizedIndices))); userNoIndices = new User("test", "test"); - when(authzService.authorizedIndicesAndAliases(userNoIndices, IndicesAliasesAction.NAME)) - .thenReturn(Collections.emptyList()); - when(authzService.authorizedIndicesAndAliases(userNoIndices, GetAliasesAction.NAME)) - .thenReturn(Collections.emptyList()); - when(authzService.authorizedIndicesAndAliases(userNoIndices, SearchAction.NAME)) - .thenReturn(Collections.emptyList()); - when(authzService.authorizedIndicesAndAliases(userNoIndices, MultiSearchAction.NAME)) - .thenReturn(Collections.emptyList()); + rolesStore = mock(RolesStore.class); + String[] authorizedIndices = new String[] { "bar", "bar-closed", "foofoobar", "foofoo", "missing", "foofoo-closed" }; + when(rolesStore.role("role")).thenReturn(Role.builder("role").add(IndexPrivilege.ALL, authorizedIndices).build()); + when(rolesStore.role("test")).thenReturn(Role.builder("test").cluster(ClusterPrivilege.MONITOR).build()); + ClusterService clusterService = mock(ClusterService.class); + ClusterState state = mock(ClusterState.class); + when(clusterService.state()).thenReturn(state); + when(state.metaData()).thenReturn(metaData); + InternalAuthorizationService authzService = new InternalAuthorizationService(settings, rolesStore, clusterService, + mock(AuditTrail.class), new AnonymousService(settings), new DefaultAuthenticationFailureHandler(), mock(ThreadPool.class)); defaultIndicesResolver = new DefaultIndicesAndAliasesResolver(authzService); } @@ -104,8 +108,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveEmptyIndicesExpandWilcardsOpen() { @@ -114,8 +119,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveAllExpandWilcardsOpenAndClosed() { @@ -124,8 +130,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveAllExpandWilcardsOpen() { @@ -134,8 +141,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveWildcardsExpandWilcardsOpenAndClosed() { @@ -144,8 +152,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"barbaz", "foofoobar", "foofoo", "foofoo-closed"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveWildcardsExpandWilcardsOpen() { @@ -154,8 +163,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"barbaz", "foofoobar", "foofoo"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveWildcardsMinusExpandWilcardsOpen() { @@ -164,8 +174,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"bar"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveWildcardsMinusExpandWilcardsOpenAndClosed() { @@ -174,8 +185,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"bar", "bar-closed"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveWildcardsPlusAndMinusExpandWilcardsOpen() { @@ -184,8 +196,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"bar", "barbaz"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveWildcardsPlusAndMinusExpandWilcardsOpenAndClosed() { @@ -194,8 +207,9 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] replacedIndices = new String[]{"bar", "bar-closed", "barbaz"}; assertThat(indices.size(), equalTo(replacedIndices.length)); + assertThat(request.indices().length, equalTo(replacedIndices.length)); assertThat(indices, hasItems(replacedIndices)); - assertThat(request.indices(), arrayContaining(replacedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); } public void testResolveNonMatchingIndices() { @@ -223,6 +237,7 @@ public class DefaultIndicesResolverTests extends ESTestCase { Set indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); String[] expectedIndices = new String[]{"bar", "missing"}; assertThat(indices.size(), equalTo(expectedIndices.length)); + assertThat(request.indices().length, equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); assertThat(request.indices(), equalTo(expectedIndices)); } @@ -253,10 +268,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { String[] expectedIndices = new String[]{"alias1", "alias2", "foo", "foofoo", "foobar"}; assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo", "foofoo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("foo", "foobar")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("alias2")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo", "foofoo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("foo", "foobar")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("alias2")); } public void testResolveIndicesAliasesRequestExistingAlias() { @@ -268,10 +283,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { String[] expectedIndices = new String[]{"alias1", "foofoobar", "foo", "foofoo", "foobar"}; assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo", "foofoo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("foo", "foobar")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo", "foofoo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("foo", "foobar")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("foofoobar")); } public void testResolveIndicesAliasesRequestMissingIndex() { @@ -283,10 +298,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { String[] expectedIndices = new String[]{"alias1", "alias2", "foo", "foofoo", "missing"}; assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo", "foofoo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("missing")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("alias2")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo", "foofoo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("missing")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("alias2")); } public void testResolveWildcardsIndicesAliasesRequest() { @@ -299,10 +314,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //wildcards get replaced on each single action - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foofoobar", "foofoo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("bar")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("alias2")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foofoobar", "foofoo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("bar")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("alias2")); } public void testResolveWildcardsIndicesAliasesRequestNoMatchingIndices() { @@ -330,10 +345,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices, hasItems(expectedIndices)); String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"}; //_all gets replaced with all indices that user is authorized for, on each single action - assertThat(request.getAliasActions().get(0).indices(), arrayContaining(replacedIndices)); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining(replacedIndices)); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("alias2")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder(replacedIndices)); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder(replacedIndices)); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("alias2")); } public void testResolveAllIndicesAliasesRequestNoAuthorizedIndices() { @@ -369,10 +384,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { String[] expectedIndices = new String[]{"foo", "foofoobar", "foofoo", "barbaz"}; assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("foofoo")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("barbaz")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("foofoo")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("barbaz")); } public void testResolveIndicesAliasesRequestDeleteActionsMissingIndex() { @@ -384,10 +399,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { String[] expectedIndices = new String[]{"foo", "foofoobar", "missing_index", "missing_alias"}; assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("missing_index")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("missing_alias")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("missing_index")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("missing_alias")); } public void testResolveWildcardsIndicesAliasesRequestDeleteActions() { @@ -400,10 +415,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //wildcards get replaced within each single action - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foofoobar", "foofoo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("bar")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("barbaz")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foofoobar", "foofoo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("bar")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("barbaz")); } public void testResolveAliasesWildcardsIndicesAliasesRequestDeleteActions() { @@ -418,10 +433,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //alias foofoobar on both sides, that's fine, es core would do the same, same as above - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("bar", "foofoobar", "foofoo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("bar", "foofoobar")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("bar", "foofoobar", "foofoo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("bar", "foofoobar")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("foofoobar")); } public void testResolveAllAliasesWildcardsIndicesAliasesRequestDeleteActions() { @@ -436,10 +451,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //alias foofoobar on both sides, that's fine, es core would do the same, same as above - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("bar", "foofoobar", "foofoo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("bar", "foofoobar", "foofoo")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar", "explicit")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("bar", "foofoobar", "foofoo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("bar", "foofoobar", "foofoo")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("foofoobar", "explicit")); } public void testResolveAliasesWildcardsIndicesAliasesRequestDeleteActionsNoAuthorizedIndices() { @@ -465,10 +480,10 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //every single action has its indices replaced with matching (authorized) ones - assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foofoobar", "foofoo")); - assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); - assertThat(request.getAliasActions().get(1).indices(), arrayContaining("bar")); - assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar")); + assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foofoobar", "foofoo")); + assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar")); + assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("bar")); + assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("foofoobar")); } public void testResolveGetAliasesRequest() { @@ -478,8 +493,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { String[] expectedIndices = new String[]{"alias1", "foo", "foofoo"}; assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); - assertThat(request.indices(), arrayContaining("foo", "foofoo")); - assertThat(request.aliases(), arrayContaining("alias1")); + assertThat(request.indices(), arrayContainingInAnyOrder("foo", "foofoo")); + assertThat(request.aliases(), arrayContainingInAnyOrder("alias1")); } public void testResolveGetAliasesRequestMissingIndex() { @@ -491,8 +506,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { String[] expectedIndices = new String[]{"alias2", "missing"}; assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); - assertThat(request.indices(), arrayContaining("missing")); - assertThat(request.aliases(), arrayContaining("alias2")); + assertThat(request.indices(), arrayContainingInAnyOrder("missing")); + assertThat(request.aliases(), arrayContainingInAnyOrder("alias2")); } public void testResolveWildcardsGetAliasesRequest() { @@ -505,8 +520,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //wildcards get replaced on each single action - assertThat(request.indices(), arrayContaining("foofoobar", "foofoo", "foofoo-closed")); - assertThat(request.aliases(), arrayContaining("alias1")); + assertThat(request.indices(), arrayContainingInAnyOrder("foofoobar", "foofoo", "foofoo-closed")); + assertThat(request.aliases(), arrayContainingInAnyOrder("alias1")); } public void testResolveWildcardsGetAliasesRequestNoMatchingIndices() { @@ -536,8 +551,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices, hasItems(expectedIndices)); String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"}; //_all gets replaced with all indices that user is authorized for - assertThat(request.indices(), arrayContaining(replacedIndices)); - assertThat(request.aliases(), arrayContaining("alias1")); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); + assertThat(request.aliases(), arrayContainingInAnyOrder("alias1")); } public void testResolveAllGetAliasesRequestExpandWildcardsOpenOnly() { @@ -556,8 +571,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices, hasItems(expectedIndices)); String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"}; //_all gets replaced with all indices that user is authorized for - assertThat(request.indices(), arrayContaining(replacedIndices)); - assertThat(request.aliases(), arrayContaining("alias1")); + assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices)); + assertThat(request.aliases(), arrayContainingInAnyOrder("alias1")); } public void testResolveAllGetAliasesRequestNoAuthorizedIndices() { @@ -600,8 +615,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //_all gets replaced with all indices that user is authorized for - assertThat(request.indices(), arrayContaining(expectedIndices)); - assertThat(request.aliases(), arrayContaining("foofoobar")); + assertThat(request.indices(), arrayContainingInAnyOrder(expectedIndices)); + assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar")); } public void testResolveAllAndExplicitAliasesGetAliasesRequest() { @@ -615,8 +630,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //_all gets replaced with all indices that user is authorized for - assertThat(request.indices(), arrayContaining("bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed")); - assertThat(request.aliases(), arrayContaining("foofoobar", "explicit")); + assertThat(request.indices(), arrayContainingInAnyOrder("bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed")); + assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar", "explicit")); } public void testResolveAllAndWildcardsAliasesGetAliasesRequest() { @@ -630,8 +645,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //_all gets replaced with all indices that user is authorized for - assertThat(request.indices(), arrayContaining(expectedIndices)); - assertThat(request.aliases(), arrayContaining("foofoobar", "foofoobar")); + assertThat(request.indices(), arrayContainingInAnyOrder(expectedIndices)); + assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar", "foofoobar")); } public void testResolveAliasesWildcardsGetAliasesRequest() { @@ -646,8 +661,8 @@ public class DefaultIndicesResolverTests extends ESTestCase { assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); //alias foofoobar on both sides, that's fine, es core would do the same, same as above - assertThat(request.indices(), arrayContaining("bar", "foofoobar")); - assertThat(request.aliases(), arrayContaining("foofoobar")); + assertThat(request.indices(), arrayContainingInAnyOrder("bar", "foofoobar")); + assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar")); } public void testResolveAliasesWildcardsGetAliasesRequestNoAuthorizedIndices() { @@ -797,7 +812,33 @@ public class DefaultIndicesResolverTests extends ESTestCase { String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"}; assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices, hasItems(expectedIndices)); - assertThat(request.indices(), arrayContaining(expectedIndices)); + assertThat(request.indices(), arrayContainingInAnyOrder(expectedIndices)); + } + + public void testXPackUserHasAccessToSecurityIndex() { + SearchRequest request = new SearchRequest(); + Set indices = defaultIndicesResolver.resolve(XPackUser.INSTANCE, SearchAction.NAME, request, metaData); + assertThat(indices, hasItem(ShieldTemplateService.SECURITY_INDEX_NAME)); + + IndicesAliasesRequest aliasesRequest = new IndicesAliasesRequest(); + aliasesRequest.addAlias("shield_alias", "*"); + indices = defaultIndicesResolver.resolve(XPackUser.INSTANCE, IndicesAliasesAction.NAME, aliasesRequest, metaData); + assertThat(indices, hasItem(ShieldTemplateService.SECURITY_INDEX_NAME)); + } + + public void testNonXPackUserAccessingSecurityIndex() { + User allAccessUser = new User("all_access", new String[] { "all_access" } ); + when(rolesStore.role("all_access")).thenReturn( + Role.builder("all_access").add(IndexPrivilege.ALL, "*").cluster(ClusterPrivilege.ALL).build()); + + SearchRequest request = new SearchRequest(); + Set indices = defaultIndicesResolver.resolve(allAccessUser, SearchAction.NAME, request, metaData); + assertThat(indices, not(hasItem(ShieldTemplateService.SECURITY_INDEX_NAME))); + + IndicesAliasesRequest aliasesRequest = new IndicesAliasesRequest(); + aliasesRequest.addAlias("shield_alias1", "*"); + indices = defaultIndicesResolver.resolve(allAccessUser, IndicesAliasesAction.NAME, aliasesRequest, metaData); + assertThat(indices, not(hasItem(ShieldTemplateService.SECURITY_INDEX_NAME))); } // TODO with the removal of DeleteByQuery is there another way to test resolving a write action? diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/NativeRealmIntegTestCase.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/NativeRealmIntegTestCase.java new file mode 100644 index 00000000000..f517663cda4 --- /dev/null +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/NativeRealmIntegTestCase.java @@ -0,0 +1,84 @@ +/* + * 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.test; + +import org.elasticsearch.index.IndexNotFoundException; +import org.elasticsearch.shield.ShieldTemplateService; +import org.elasticsearch.shield.authc.esnative.ESNativeUsersStore; +import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore; +import org.elasticsearch.shield.client.SecurityClient; +import org.junit.After; +import org.junit.Before; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isOneOf; + +/** + * Test case with method to handle the starting and stopping the stores for native users and roles + */ +public abstract class NativeRealmIntegTestCase extends ShieldIntegTestCase { + + @Before + public void ensureNativeStoresStarted() throws Exception { + for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) { + assertBusy(new Runnable() { + @Override + public void run() { + assertThat(store.state(), is(ESNativeUsersStore.State.STARTED)); + } + }); + } + + for (ESNativeRolesStore store : internalCluster().getInstances(ESNativeRolesStore.class)) { + assertBusy(new Runnable() { + @Override + public void run() { + assertThat(store.state(), is(ESNativeRolesStore.State.STARTED)); + } + }); + } + } + + @After + public void stopESNativeStores() throws Exception { + for (ESNativeUsersStore store : internalCluster().getInstances(ESNativeUsersStore.class)) { + store.stop(); + // the store may already be stopping so wait until it is stopped + assertBusy(new Runnable() { + @Override + public void run() { + assertThat(store.state(), isOneOf(ESNativeUsersStore.State.STOPPED, ESNativeUsersStore.State.FAILED)); + } + }); + store.reset(); + } + + for (ESNativeRolesStore store : internalCluster().getInstances(ESNativeRolesStore.class)) { + store.stop(); + // the store may already be stopping so wait until it is stopped + assertBusy(new Runnable() { + @Override + public void run() { + assertThat(store.state(), isOneOf(ESNativeRolesStore.State.STOPPED, ESNativeRolesStore.State.FAILED)); + } + }); + store.reset(); + } + + try { + // this is a hack to clean up the .security index since only the XPack user can delete it + internalClient().admin().indices().prepareDelete(ShieldTemplateService.SECURITY_INDEX_NAME).get(); + } catch (IndexNotFoundException e) { + // ignore it since not all tests create this index... + } + + if (getCurrentClusterScope() == Scope.SUITE) { + // Clear the realm cache for all realms since we use a SUITE scoped cluster + SecurityClient client = securityClient(internalCluster().transportClient()); + client.prepareClearRealmCache().get(); + } + } +} diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldIntegTestCase.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldIntegTestCase.java index 49a98d873d1..8866c705029 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldIntegTestCase.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldIntegTestCase.java @@ -12,15 +12,21 @@ import org.elasticsearch.client.Client; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.shield.InternalClient; +import org.elasticsearch.shield.Shield; +import org.elasticsearch.shield.ShieldTemplateService; +import org.elasticsearch.shield.authc.esnative.ESNativeUsersStore; import org.elasticsearch.shield.authc.support.SecuredString; +import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore; import org.elasticsearch.shield.client.SecurityClient; import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode; import org.elasticsearch.test.transport.AssertingLocalTransport; import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.xpack.XPackClient; import org.elasticsearch.xpack.XPackPlugin; +import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -38,7 +44,8 @@ import java.util.stream.Collectors; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; -import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isOneOf; import static org.hamcrest.core.IsCollectionContaining.hasItem; /** @@ -79,7 +86,7 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase { return getAnnotation(clazz.getSuperclass()); } - private Scope getCurrentClusterScope() { + Scope getCurrentClusterScope() { return getCurrentClusterScope(this.getClass()); } diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java index 7010174def7..f72c5986bec 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java @@ -6,28 +6,43 @@ package org.elasticsearch.xpack.test.rest; import java.io.IOException; +import java.io.InputStreamReader; import java.net.URI; import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Map; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.lucene.util.IOUtils; +import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.common.xcontent.XContentUtils; import org.junit.After; import org.junit.Before; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; +import static org.hamcrest.Matchers.is; public abstract class XPackRestTestCase extends ESRestTestCase { + private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray())); + public XPackRestTestCase(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); } @@ -39,14 +54,16 @@ public abstract class XPackRestTestCase extends ESRestTestCase { @Before public void startWatcher() throws Exception { - try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { + try (CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { URL url = getClusterUrls()[0]; HttpPut request = new HttpPut(new URI("http", - "test_user:changeme", + null, url.getHost(), url.getPort(), "/_watcher/_start", null, null)); - client.execute(request); + request.addHeader("Authorization", BASIC_AUTH_VALUE); + try (CloseableHttpResponse response = client.execute(request)) { + } } } @@ -55,19 +72,65 @@ public abstract class XPackRestTestCase extends ESRestTestCase { try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { URL url = getClusterUrls()[0]; HttpPut request = new HttpPut(new URI("http", - "test_user:changeme", + null, url.getHost(), url.getPort(), "/_watcher/_stop", null, null)); - client.execute(request); + request.addHeader("Authorization", BASIC_AUTH_VALUE); + try (CloseableHttpResponse response = client.execute(request)) { + } + } + } + + @After + public void clearShieldUsersAndRoles() throws Exception { + // we cannot delete the .security index from a rest test since we aren't the internal user, lets wipe the data + // TODO remove this once the built-in SUPERUSER role is added that can delete the index and we use the built in admin user here + try (CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { + final URL url = getClusterUrls()[0]; + HttpGet getUsersRequest = new HttpGet(new URI("http", null, url.getHost(), url.getPort(), "/_shield/user", null, null)); + getUsersRequest.addHeader("Authorization", BASIC_AUTH_VALUE); + try (CloseableHttpResponse closeableHttpResponse = client.execute(getUsersRequest)) { + assertThat(closeableHttpResponse.getStatusLine().getStatusCode(), is(200)); + String response = Streams.copyToString( + new InputStreamReader(closeableHttpResponse.getEntity().getContent(), StandardCharsets.UTF_8)); + Map responseMap = XContentFactory.xContent(response).createParser(response).map(); + + // in the structure of this API, the users are the keyset + for (String user : responseMap.keySet()) { + HttpDelete delete = new HttpDelete(new URI("http", null, url.getHost(), url.getPort(), + "/_shield/user/" + user, null, null)); + delete.addHeader("Authorization", BASIC_AUTH_VALUE); + try (CloseableHttpResponse deleteResponse = client.execute(delete)) { + } + } + } + + HttpGet getRolesRequest = new HttpGet(new URI("http", null, url.getHost(), url.getPort(), "/_shield/role", + null, null)); + getRolesRequest.addHeader("Authorization", BASIC_AUTH_VALUE); + try (CloseableHttpResponse closeableHttpResponse = client.execute(getRolesRequest)) { + assertThat(closeableHttpResponse.getStatusLine().getStatusCode(), is(200)); + String response = Streams.copyToString( + new InputStreamReader(closeableHttpResponse.getEntity().getContent(), StandardCharsets.UTF_8)); + Map responseMap = XContentFactory.xContent(response).createParser(response).map(); + + // in the structure of this API, the users are the keyset + for (String role : responseMap.keySet()) { + HttpDelete delete = new HttpDelete(new URI("http", null, url.getHost(), url.getPort(), + "/_shield/role/" + role, null, null)); + delete.addHeader("Authorization", BASIC_AUTH_VALUE); + try (CloseableHttpResponse deleteResponse = client.execute(delete)) { + } + } + } } } @Override protected Settings restClientSettings() { - String token = basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray())); return Settings.builder() - .put(ThreadContext.PREFIX + ".Authorization", token) + .put(ThreadContext.PREFIX + ".Authorization", BASIC_AUTH_VALUE) .build(); } }