security: protect the user and roles index

This commit adds the logic to protect the user and roles index that we store locally
by restricting access to the internal XPack user. We need to do this in two places;
the first is when resolving wildcards and the other is when authorizing requests
made against specific indices.

Original commit: elastic/x-pack-elasticsearch@8ee0ce02db
This commit is contained in:
jaymode 2016-03-03 20:16:21 -05:00
parent c1c78911b9
commit 186dbf547a
11 changed files with 432 additions and 232 deletions

View File

@ -48,7 +48,8 @@ public class TransportClearRealmCacheAction extends TransportNodesAction<ClearRe
Object resp = responses.get(i); Object resp = responses.get(i);
if (resp instanceof ClearRealmCacheResponse.Node) { if (resp instanceof ClearRealmCacheResponse.Node) {
nodes.add((ClearRealmCacheResponse.Node) resp); nodes.add((ClearRealmCacheResponse.Node) resp);
} else { } else if (resp != null) {
// null is possible if there is an error and we do not accumulate exceptions...
throw new IllegalArgumentException("node response [" + resp.getClass() + "] is not the correct type"); throw new IllegalArgumentException("node response [" + resp.getClass() + "] is not the correct type");
} }
} }

View File

@ -45,7 +45,8 @@ public class TransportClearRolesCacheAction extends TransportNodesAction<ClearRo
Object resp = nodesResponses.get(i); Object resp = nodesResponses.get(i);
if (resp instanceof ClearRolesCacheResponse.Node) { if (resp instanceof ClearRolesCacheResponse.Node) {
responses.add((ClearRolesCacheResponse.Node) resp); responses.add((ClearRolesCacheResponse.Node) resp);
} else { } else if (resp == null) {
// null is possible if there is an error and we do not accumulate exceptions...
throw new IllegalArgumentException("node response [" + resp.getClass() + "] is not the correct type"); throw new IllegalArgumentException("node response [" + resp.getClass() + "] is not the correct type");
} }
} }

View File

@ -22,6 +22,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.search.action.SearchTransportService; import org.elasticsearch.search.action.SearchTransportService;
import org.elasticsearch.shield.ShieldTemplateService;
import org.elasticsearch.shield.SystemUser; import org.elasticsearch.shield.SystemUser;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.XPackUser; import org.elasticsearch.shield.XPackUser;
@ -112,6 +113,13 @@ public class InternalAuthorizationService extends AbstractComponent implements A
} }
} }
if (XPackUser.is(user) == false) {
// we should filter out the .security index from wildcards
if (indicesAndAliases.remove(ShieldTemplateService.SECURITY_INDEX_NAME)) {
logger.debug("removed [{}] from user [{}] list of authorized indices",
ShieldTemplateService.SECURITY_INDEX_NAME, user.principal());
}
}
return Collections.unmodifiableList(indicesAndAliases); return Collections.unmodifiableList(indicesAndAliases);
} }
@ -208,6 +216,13 @@ public class InternalAuthorizationService extends AbstractComponent implements A
IndicesAccessControl indicesAccessControl = permission.authorize(action, indexNames, metaData); IndicesAccessControl indicesAccessControl = permission.authorize(action, indexNames, metaData);
if (!indicesAccessControl.isGranted()) { if (!indicesAccessControl.isGranted()) {
throw denial(user, action, request); throw denial(user, action, request);
} else if (indicesAccessControl.getIndexPermissions(ShieldTemplateService.SECURITY_INDEX_NAME) != null
&& indicesAccessControl.getIndexPermissions(ShieldTemplateService.SECURITY_INDEX_NAME).isGranted()
&& XPackUser.is(user) == false) {
// only the XPackUser is allowed to work with this index, but we should allow health/stats through
logger.debug("user [{}] attempted to directly perform [{}] against the security index [{}]", user.principal(), action,
ShieldTemplateService.SECURITY_INDEX_NAME);
throw denial(user, action, request);
} else { } else {
setIndicesAccessControl(indicesAccessControl); setIndicesAccessControl(indicesAccessControl);
} }

View File

@ -166,6 +166,7 @@ public class DefaultIndicesAndAliasesResolver implements IndicesAndAliasesResolv
private List<String> replaceWildcardsWithAuthorizedIndices(String[] indices, IndicesOptions indicesOptions, MetaData metaData, private List<String> replaceWildcardsWithAuthorizedIndices(String[] indices, IndicesOptions indicesOptions, MetaData metaData,
List<String> authorizedIndices) { List<String> authorizedIndices) {
// check for all and return list of authorized indices
if (IndexNameExpressionResolver.isAllIndices(indicesList(indices))) { if (IndexNameExpressionResolver.isAllIndices(indicesList(indices))) {
List<String> visibleIndices = new ArrayList<>(); List<String> visibleIndices = new ArrayList<>();
for (String authorizedIndex : authorizedIndices) { for (String authorizedIndex : authorizedIndices) {

View File

@ -16,17 +16,15 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.shield.action.role.PutRoleResponse; import org.elasticsearch.shield.action.role.PutRoleResponse;
import org.elasticsearch.shield.action.role.GetRolesResponse; import org.elasticsearch.shield.action.role.GetRolesResponse;
import org.elasticsearch.shield.ShieldTemplateService; 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.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.authz.RoleDescriptor; import org.elasticsearch.shield.authz.RoleDescriptor;
import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore; import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore;
import org.elasticsearch.shield.client.SecurityClient; 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.ShieldSettingsSource;
import org.elasticsearch.test.junit.annotations.TestLogging; import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.test.rest.client.http.HttpResponse; import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -35,7 +33,6 @@ import java.util.List;
import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isOneOf;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
/** /**
@ -43,7 +40,7 @@ import static org.hamcrest.Matchers.notNullValue;
* test the cache clearing APIs. * test the cache clearing APIs.
*/ */
@TestLogging("shield.authc.esnative:TRACE,shield.authz.esnative:TRACE,integration:DEBUG") @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; private static String[] roles;
@ -56,29 +53,7 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
} }
@Before @Before
public void setupForTest() throws Exception { public void setupForTests() {
// 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));
}
});
}
SecurityClient c = securityClient(); SecurityClient c = securityClient();
// create roles // create roles
for (String role : roles) { for (String role : roles) {
@ -129,13 +104,11 @@ public class ClearRolesCacheTests extends ShieldIntegTestCase {
} }
public void testModifyingDocumentsDirectly() throws Exception { public void testModifyingDocumentsDirectly() throws Exception {
Client client = internalCluster().transportClient();
int modifiedRolesCount = randomIntBetween(1, roles.length); int modifiedRolesCount = randomIntBetween(1, roles.length);
List<String> toModify = randomSubsetOf(modifiedRolesCount, roles); List<String> toModify = randomSubsetOf(modifiedRolesCount, roles);
logger.debug("--> modifying roles {} to have run_as", toModify); logger.debug("--> modifying roles {} to have run_as", toModify);
for (String role : 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) .setType(ESNativeRolesStore.ROLE_DOC_TYPE)
.setDoc("run_as", new String[] { role }) .setDoc("run_as", new String[] { role })
.get(); .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 // 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! // 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 useHttp = randomBoolean();
final boolean clearAll = randomBoolean(); final boolean clearAll = randomBoolean();
logger.debug("--> starting to clear roles. using http [{}] clearing all [{}]", useHttp, clearAll); 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 { public void testDeletingRoleDocumentDirectly() throws Exception {
Client client = internalCluster().transportClient(); SecurityClient securityClient = securityClient(internalCluster().transportClient());
SecurityClient securityClient = securityClient(client);
final String role = randomFrom(roles); final String role = randomFrom(roles);
RoleDescriptor[] foundRoles = securityClient.prepareGetRoles().names(role).get().roles(); RoleDescriptor[] foundRoles = securityClient.prepareGetRoles().names(role).get().roles();
assertThat(foundRoles.length, is(1)); assertThat(foundRoles.length, is(1));
logger.debug("--> deleting role [{}]", role); logger.debug("--> deleting role [{}]", role);
DeleteResponse response = client DeleteResponse response = internalClient()
.prepareDelete(ShieldTemplateService.SECURITY_INDEX_NAME, ESNativeRolesStore.ROLE_DOC_TYPE, role).get(); .prepareDelete(ShieldTemplateService.SECURITY_INDEX_NAME, ESNativeRolesStore.ROLE_DOC_TYPE, role).get();
assertThat(response.isFound(), is(true)); 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();
}
}
} }

View File

@ -20,13 +20,10 @@ import org.elasticsearch.shield.action.user.DeleteUserResponse;
import org.elasticsearch.shield.action.user.GetUsersResponse; import org.elasticsearch.shield.action.user.GetUsersResponse;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authz.RoleDescriptor; import org.elasticsearch.shield.authz.RoleDescriptor;
import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore;
import org.elasticsearch.shield.authz.permission.Role; import org.elasticsearch.shield.authz.permission.Role;
import org.elasticsearch.shield.client.SecurityClient; 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.ShieldSettingsSource;
import org.junit.After;
import org.junit.Before;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; 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.arrayContaining;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isOneOf;
/** /**
* Tests for the ESNativeUsersStore and ESNativeRolesStore * Tests for the ESNativeUsersStore and ESNativeRolesStore
*/ */
public class ESNativeTests extends ShieldIntegTestCase { public class ESNativeTests extends NativeRealmIntegTestCase {
public void testDeletingNonexistingUserAndRole() throws Exception { public void testDeletingNonexistingUserAndRole() throws Exception {
SecurityClient c = securityClient(); SecurityClient c = securityClient();
@ -390,56 +386,4 @@ public class ESNativeTests extends ShieldIntegTestCase {
.admin().cluster().prepareHealth().get(); .admin().cluster().prepareHealth().get();
assertFalse(response.isTimedOut()); 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();
}
}
} }

View File

@ -7,26 +7,43 @@ package org.elasticsearch.shield.authz;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version; 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.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction; 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.CreateIndexAction;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; 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.ClearScrollAction;
import org.elasticsearch.action.search.ClearScrollRequest; import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.SearchAction; import org.elasticsearch.action.search.SearchAction;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchScrollAction; import org.elasticsearch.action.search.SearchScrollAction;
import org.elasticsearch.action.search.SearchScrollRequest; 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.ClusterService;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.search.action.SearchTransportService; import org.elasticsearch.search.action.SearchTransportService;
import org.elasticsearch.shield.ShieldTemplateService;
import org.elasticsearch.shield.SystemUser; import org.elasticsearch.shield.SystemUser;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.XPackUser;
import org.elasticsearch.shield.audit.AuditTrail; import org.elasticsearch.shield.audit.AuditTrail;
import org.elasticsearch.shield.authc.AnonymousService; import org.elasticsearch.shield.authc.AnonymousService;
import org.elasticsearch.shield.authc.DefaultAuthenticationFailureHandler; import org.elasticsearch.shield.authc.DefaultAuthenticationFailureHandler;
@ -40,6 +57,7 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
import org.junit.Before; import org.junit.Before;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.elasticsearch.test.ShieldTestsUtils.assertAuthenticationException; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthenticationException;
@ -452,4 +470,84 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
verify(auditTrail).accessGranted(user, "indices:a", request); verify(auditTrail).accessGranted(user, "indices:a", request);
verifyNoMoreInteractions(auditTrail); 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<Tuple<String, TransportRequest>> 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<String, TransportRequest> 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<Tuple<String, TransportRequest>> 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<String, TransportRequest> requestTuple : requests) {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
internalAuthorizationService.authorize(XPackUser.INSTANCE, action, request);
verify(auditTrail).accessGranted(XPackUser.INSTANCE, action, request);
}
}
} }

View File

@ -6,6 +6,8 @@
package org.elasticsearch.shield.authz.indicesresolver; package org.elasticsearch.shield.authz.indicesresolver;
import org.elasticsearch.Version; 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.IndicesAliasesAction;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesAction; 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.search.SearchRequest;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Requests; 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.AliasAction;
import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.shield.ShieldTemplateService;
import org.elasticsearch.shield.User; 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.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.junit.Before; import org.junit.Before;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set; 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.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
public class DefaultIndicesResolverTests extends ESTestCase { public class DefaultIndicesResolverTests extends ESTestCase {
private User user; private User user;
private User userNoIndices; private User userNoIndices;
private RolesStore rolesStore;
private MetaData metaData; private MetaData metaData;
private DefaultIndicesAndAliasesResolver defaultIndicesResolver; private DefaultIndicesAndAliasesResolver defaultIndicesResolver;
@ -66,35 +82,23 @@ public class DefaultIndicesResolverTests extends ESTestCase {
.put(indexBuilder("foofoo").putAlias(AliasMetaData.builder("barbaz")).settings(settings)) .put(indexBuilder("foofoo").putAlias(AliasMetaData.builder("barbaz")).settings(settings))
.put(indexBuilder("bar").settings(settings)) .put(indexBuilder("bar").settings(settings))
.put(indexBuilder("bar-closed").state(IndexMetaData.State.CLOSE).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(); metaData = mdBuilder.build();
AuthorizationService authzService = mock(AuthorizationService.class);
user = new User("user", "role"); 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"); userNoIndices = new User("test", "test");
when(authzService.authorizedIndicesAndAliases(userNoIndices, IndicesAliasesAction.NAME)) rolesStore = mock(RolesStore.class);
.thenReturn(Collections.<String>emptyList()); String[] authorizedIndices = new String[] { "bar", "bar-closed", "foofoobar", "foofoo", "missing", "foofoo-closed" };
when(authzService.authorizedIndicesAndAliases(userNoIndices, GetAliasesAction.NAME)) when(rolesStore.role("role")).thenReturn(Role.builder("role").add(IndexPrivilege.ALL, authorizedIndices).build());
.thenReturn(Collections.<String>emptyList()); when(rolesStore.role("test")).thenReturn(Role.builder("test").cluster(ClusterPrivilege.MONITOR).build());
when(authzService.authorizedIndicesAndAliases(userNoIndices, SearchAction.NAME)) ClusterService clusterService = mock(ClusterService.class);
.thenReturn(Collections.<String>emptyList()); ClusterState state = mock(ClusterState.class);
when(authzService.authorizedIndicesAndAliases(userNoIndices, MultiSearchAction.NAME)) when(clusterService.state()).thenReturn(state);
.thenReturn(Collections.<String>emptyList()); 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); defaultIndicesResolver = new DefaultIndicesAndAliasesResolver(authzService);
} }
@ -104,8 +108,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"}; String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveEmptyIndicesExpandWilcardsOpen() { public void testResolveEmptyIndicesExpandWilcardsOpen() {
@ -114,8 +119,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"}; String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveAllExpandWilcardsOpenAndClosed() { public void testResolveAllExpandWilcardsOpenAndClosed() {
@ -124,8 +130,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"}; String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveAllExpandWilcardsOpen() { public void testResolveAllExpandWilcardsOpen() {
@ -134,8 +141,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"}; String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveWildcardsExpandWilcardsOpenAndClosed() { public void testResolveWildcardsExpandWilcardsOpenAndClosed() {
@ -144,8 +152,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"barbaz", "foofoobar", "foofoo", "foofoo-closed"}; String[] replacedIndices = new String[]{"barbaz", "foofoobar", "foofoo", "foofoo-closed"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveWildcardsExpandWilcardsOpen() { public void testResolveWildcardsExpandWilcardsOpen() {
@ -154,8 +163,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"barbaz", "foofoobar", "foofoo"}; String[] replacedIndices = new String[]{"barbaz", "foofoobar", "foofoo"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveWildcardsMinusExpandWilcardsOpen() { public void testResolveWildcardsMinusExpandWilcardsOpen() {
@ -164,8 +174,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"bar"}; String[] replacedIndices = new String[]{"bar"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveWildcardsMinusExpandWilcardsOpenAndClosed() { public void testResolveWildcardsMinusExpandWilcardsOpenAndClosed() {
@ -174,8 +185,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"bar", "bar-closed"}; String[] replacedIndices = new String[]{"bar", "bar-closed"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveWildcardsPlusAndMinusExpandWilcardsOpen() { public void testResolveWildcardsPlusAndMinusExpandWilcardsOpen() {
@ -184,8 +196,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"bar", "barbaz"}; String[] replacedIndices = new String[]{"bar", "barbaz"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveWildcardsPlusAndMinusExpandWilcardsOpenAndClosed() { public void testResolveWildcardsPlusAndMinusExpandWilcardsOpenAndClosed() {
@ -194,8 +207,9 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] replacedIndices = new String[]{"bar", "bar-closed", "barbaz"}; String[] replacedIndices = new String[]{"bar", "bar-closed", "barbaz"};
assertThat(indices.size(), equalTo(replacedIndices.length)); assertThat(indices.size(), equalTo(replacedIndices.length));
assertThat(request.indices().length, equalTo(replacedIndices.length));
assertThat(indices, hasItems(replacedIndices)); assertThat(indices, hasItems(replacedIndices));
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
} }
public void testResolveNonMatchingIndices() { public void testResolveNonMatchingIndices() {
@ -223,6 +237,7 @@ public class DefaultIndicesResolverTests extends ESTestCase {
Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData); Set<String> indices = defaultIndicesResolver.resolve(user, SearchAction.NAME, request, metaData);
String[] expectedIndices = new String[]{"bar", "missing"}; String[] expectedIndices = new String[]{"bar", "missing"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(request.indices().length, equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.indices(), equalTo(expectedIndices)); assertThat(request.indices(), equalTo(expectedIndices));
} }
@ -253,10 +268,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
String[] expectedIndices = new String[]{"alias1", "alias2", "foo", "foofoo", "foobar"}; String[] expectedIndices = new String[]{"alias1", "alias2", "foo", "foofoo", "foobar"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo", "foofoo")); assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo", "foofoo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("foo", "foobar")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("foo", "foobar"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("alias2")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("alias2"));
} }
public void testResolveIndicesAliasesRequestExistingAlias() { public void testResolveIndicesAliasesRequestExistingAlias() {
@ -268,10 +283,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
String[] expectedIndices = new String[]{"alias1", "foofoobar", "foo", "foofoo", "foobar"}; String[] expectedIndices = new String[]{"alias1", "foofoobar", "foo", "foofoo", "foobar"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo", "foofoo")); assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo", "foofoo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("foo", "foobar")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("foo", "foobar"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("foofoobar"));
} }
public void testResolveIndicesAliasesRequestMissingIndex() { public void testResolveIndicesAliasesRequestMissingIndex() {
@ -283,10 +298,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
String[] expectedIndices = new String[]{"alias1", "alias2", "foo", "foofoo", "missing"}; String[] expectedIndices = new String[]{"alias1", "alias2", "foo", "foofoo", "missing"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo", "foofoo")); assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo", "foofoo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("missing")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("missing"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("alias2")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("alias2"));
} }
public void testResolveWildcardsIndicesAliasesRequest() { public void testResolveWildcardsIndicesAliasesRequest() {
@ -299,10 +314,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//wildcards get replaced on each single action //wildcards get replaced on each single action
assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foofoobar", "foofoo")); assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foofoobar", "foofoo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("bar")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("bar"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("alias2")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("alias2"));
} }
public void testResolveWildcardsIndicesAliasesRequestNoMatchingIndices() { public void testResolveWildcardsIndicesAliasesRequestNoMatchingIndices() {
@ -330,10 +345,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"}; String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"};
//_all gets replaced with all indices that user is authorized for, on each single action //_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).indices(), arrayContainingInAnyOrder(replacedIndices));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("alias1")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("alias1"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining(replacedIndices)); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder(replacedIndices));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("alias2")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("alias2"));
} }
public void testResolveAllIndicesAliasesRequestNoAuthorizedIndices() { public void testResolveAllIndicesAliasesRequestNoAuthorizedIndices() {
@ -369,10 +384,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
String[] expectedIndices = new String[]{"foo", "foofoobar", "foofoo", "barbaz"}; String[] expectedIndices = new String[]{"foo", "foofoobar", "foofoo", "barbaz"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo")); assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("foofoo")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("foofoo"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("barbaz")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("barbaz"));
} }
public void testResolveIndicesAliasesRequestDeleteActionsMissingIndex() { public void testResolveIndicesAliasesRequestDeleteActionsMissingIndex() {
@ -384,10 +399,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
String[] expectedIndices = new String[]{"foo", "foofoobar", "missing_index", "missing_alias"}; String[] expectedIndices = new String[]{"foo", "foofoobar", "missing_index", "missing_alias"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foo")); assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("missing_index")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("missing_index"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("missing_alias")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("missing_alias"));
} }
public void testResolveWildcardsIndicesAliasesRequestDeleteActions() { public void testResolveWildcardsIndicesAliasesRequestDeleteActions() {
@ -400,10 +415,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//wildcards get replaced within each single action //wildcards get replaced within each single action
assertThat(request.getAliasActions().get(0).indices(), arrayContaining("foofoobar", "foofoo")); assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("foofoobar", "foofoo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("bar")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("bar"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("barbaz")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("barbaz"));
} }
public void testResolveAliasesWildcardsIndicesAliasesRequestDeleteActions() { public void testResolveAliasesWildcardsIndicesAliasesRequestDeleteActions() {
@ -418,10 +433,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//alias foofoobar on both sides, that's fine, es core would do the same, same as above //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).indices(), arrayContainingInAnyOrder("bar", "foofoobar", "foofoo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("bar", "foofoobar")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("bar", "foofoobar"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("foofoobar"));
} }
public void testResolveAllAliasesWildcardsIndicesAliasesRequestDeleteActions() { public void testResolveAllAliasesWildcardsIndicesAliasesRequestDeleteActions() {
@ -436,10 +451,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//alias foofoobar on both sides, that's fine, es core would do the same, same as above //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).indices(), arrayContainingInAnyOrder("bar", "foofoobar", "foofoo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar"));
assertThat(request.getAliasActions().get(0).indices(), arrayContaining("bar", "foofoobar", "foofoo")); assertThat(request.getAliasActions().get(0).indices(), arrayContainingInAnyOrder("bar", "foofoobar", "foofoo"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar", "explicit")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("foofoobar", "explicit"));
} }
public void testResolveAliasesWildcardsIndicesAliasesRequestDeleteActionsNoAuthorizedIndices() { public void testResolveAliasesWildcardsIndicesAliasesRequestDeleteActionsNoAuthorizedIndices() {
@ -465,10 +480,10 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//every single action has its indices replaced with matching (authorized) ones //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).indices(), arrayContainingInAnyOrder("foofoobar", "foofoo"));
assertThat(request.getAliasActions().get(0).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(0).aliases(), arrayContainingInAnyOrder("foofoobar"));
assertThat(request.getAliasActions().get(1).indices(), arrayContaining("bar")); assertThat(request.getAliasActions().get(1).indices(), arrayContainingInAnyOrder("bar"));
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar")); assertThat(request.getAliasActions().get(1).aliases(), arrayContainingInAnyOrder("foofoobar"));
} }
public void testResolveGetAliasesRequest() { public void testResolveGetAliasesRequest() {
@ -478,8 +493,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
String[] expectedIndices = new String[]{"alias1", "foo", "foofoo"}; String[] expectedIndices = new String[]{"alias1", "foo", "foofoo"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.indices(), arrayContaining("foo", "foofoo")); assertThat(request.indices(), arrayContainingInAnyOrder("foo", "foofoo"));
assertThat(request.aliases(), arrayContaining("alias1")); assertThat(request.aliases(), arrayContainingInAnyOrder("alias1"));
} }
public void testResolveGetAliasesRequestMissingIndex() { public void testResolveGetAliasesRequestMissingIndex() {
@ -491,8 +506,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
String[] expectedIndices = new String[]{"alias2", "missing"}; String[] expectedIndices = new String[]{"alias2", "missing"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.indices(), arrayContaining("missing")); assertThat(request.indices(), arrayContainingInAnyOrder("missing"));
assertThat(request.aliases(), arrayContaining("alias2")); assertThat(request.aliases(), arrayContainingInAnyOrder("alias2"));
} }
public void testResolveWildcardsGetAliasesRequest() { public void testResolveWildcardsGetAliasesRequest() {
@ -505,8 +520,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//wildcards get replaced on each single action //wildcards get replaced on each single action
assertThat(request.indices(), arrayContaining("foofoobar", "foofoo", "foofoo-closed")); assertThat(request.indices(), arrayContainingInAnyOrder("foofoobar", "foofoo", "foofoo-closed"));
assertThat(request.aliases(), arrayContaining("alias1")); assertThat(request.aliases(), arrayContainingInAnyOrder("alias1"));
} }
public void testResolveWildcardsGetAliasesRequestNoMatchingIndices() { public void testResolveWildcardsGetAliasesRequestNoMatchingIndices() {
@ -536,8 +551,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"}; String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"};
//_all gets replaced with all indices that user is authorized for //_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
assertThat(request.aliases(), arrayContaining("alias1")); assertThat(request.aliases(), arrayContainingInAnyOrder("alias1"));
} }
public void testResolveAllGetAliasesRequestExpandWildcardsOpenOnly() { public void testResolveAllGetAliasesRequestExpandWildcardsOpenOnly() {
@ -556,8 +571,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"}; String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"};
//_all gets replaced with all indices that user is authorized for //_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContaining(replacedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
assertThat(request.aliases(), arrayContaining("alias1")); assertThat(request.aliases(), arrayContainingInAnyOrder("alias1"));
} }
public void testResolveAllGetAliasesRequestNoAuthorizedIndices() { public void testResolveAllGetAliasesRequestNoAuthorizedIndices() {
@ -600,8 +615,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//_all gets replaced with all indices that user is authorized for //_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContaining(expectedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(expectedIndices));
assertThat(request.aliases(), arrayContaining("foofoobar")); assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar"));
} }
public void testResolveAllAndExplicitAliasesGetAliasesRequest() { public void testResolveAllAndExplicitAliasesGetAliasesRequest() {
@ -615,8 +630,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//_all gets replaced with all indices that user is authorized for //_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContaining("bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed")); assertThat(request.indices(), arrayContainingInAnyOrder("bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"));
assertThat(request.aliases(), arrayContaining("foofoobar", "explicit")); assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar", "explicit"));
} }
public void testResolveAllAndWildcardsAliasesGetAliasesRequest() { public void testResolveAllAndWildcardsAliasesGetAliasesRequest() {
@ -630,8 +645,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//_all gets replaced with all indices that user is authorized for //_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContaining(expectedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(expectedIndices));
assertThat(request.aliases(), arrayContaining("foofoobar", "foofoobar")); assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar", "foofoobar"));
} }
public void testResolveAliasesWildcardsGetAliasesRequest() { public void testResolveAliasesWildcardsGetAliasesRequest() {
@ -646,8 +661,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
//alias foofoobar on both sides, that's fine, es core would do the same, same as above //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.indices(), arrayContainingInAnyOrder("bar", "foofoobar"));
assertThat(request.aliases(), arrayContaining("foofoobar")); assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar"));
} }
public void testResolveAliasesWildcardsGetAliasesRequestNoAuthorizedIndices() { public void testResolveAliasesWildcardsGetAliasesRequestNoAuthorizedIndices() {
@ -797,7 +812,33 @@ public class DefaultIndicesResolverTests extends ESTestCase {
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"}; String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"};
assertThat(indices.size(), equalTo(expectedIndices.length)); assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices)); assertThat(indices, hasItems(expectedIndices));
assertThat(request.indices(), arrayContaining(expectedIndices)); assertThat(request.indices(), arrayContainingInAnyOrder(expectedIndices));
}
public void testXPackUserHasAccessToSecurityIndex() {
SearchRequest request = new SearchRequest();
Set<String> 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<String> 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? // TODO with the removal of DeleteByQuery is there another way to test resolving a write action?

View File

@ -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();
}
}
}

View File

@ -12,15 +12,21 @@ import org.elasticsearch.client.Client;
import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.InternalClient; 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.authc.support.SecuredString;
import org.elasticsearch.shield.authz.esnative.ESNativeRolesStore;
import org.elasticsearch.shield.client.SecurityClient; import org.elasticsearch.shield.client.SecurityClient;
import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode; import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode;
import org.elasticsearch.test.transport.AssertingLocalTransport; import org.elasticsearch.test.transport.AssertingLocalTransport;
import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.test.transport.MockTransportService;
import org.elasticsearch.xpack.XPackClient; import org.elasticsearch.xpack.XPackClient;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; 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.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; 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; import static org.hamcrest.core.IsCollectionContaining.hasItem;
/** /**
@ -79,7 +86,7 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
return getAnnotation(clazz.getSuperclass()); return getAnnotation(clazz.getSuperclass());
} }
private Scope getCurrentClusterScope() { Scope getCurrentClusterScope() {
return getCurrentClusterScope(this.getClass()); return getCurrentClusterScope(this.getClass());
} }

View File

@ -6,28 +6,43 @@
package org.elasticsearch.xpack.test.rest; package org.elasticsearch.xpack.test.rest;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; 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.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager; 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.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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.shield.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.parser.RestTestParseException;
import org.elasticsearch.xpack.common.xcontent.XContentUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.is;
public abstract class XPackRestTestCase extends ESRestTestCase { 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) { public XPackRestTestCase(@Name("yaml") RestTestCandidate testCandidate) {
super(testCandidate); super(testCandidate);
} }
@ -39,14 +54,16 @@ public abstract class XPackRestTestCase extends ESRestTestCase {
@Before @Before
public void startWatcher() throws Exception { public void startWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { try (CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) {
URL url = getClusterUrls()[0]; URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", HttpPut request = new HttpPut(new URI("http",
"test_user:changeme", null,
url.getHost(), url.getHost(),
url.getPort(), url.getPort(),
"/_watcher/_start", null, null)); "/_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())) { try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) {
URL url = getClusterUrls()[0]; URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", HttpPut request = new HttpPut(new URI("http",
"test_user:changeme", null,
url.getHost(), url.getHost(),
url.getPort(), url.getPort(),
"/_watcher/_stop", null, null)); "/_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<String, Object> 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<String, Object> 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 @Override
protected Settings restClientSettings() { protected Settings restClientSettings() {
String token = basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray()));
return Settings.builder() return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", token) .put(ThreadContext.PREFIX + ".Authorization", BASIC_AUTH_VALUE)
.build(); .build();
} }
} }