security: wildcards for superusers includes the security index

The superuser role is the only user assignable role that grants access to the .security index, but when
resolving wildcards the index was not getting resolved. The resolution of indices and aliases explicitly
excludes the .security index for users that are not the internal user without checking if the user has the
superuser role. This commit adds a check in for the superuser role.

Original commit: elastic/x-pack-elasticsearch@02ee0a8740
This commit is contained in:
Jay Modi 2016-10-12 11:42:02 -04:00 committed by GitHub
parent 6284db3a4d
commit 68eb4d981e
2 changed files with 54 additions and 23 deletions

View File

@ -138,7 +138,7 @@ public class AuthorizationService extends AbstractComponent {
} }
} }
if (XPackUser.is(user) == false) { if (XPackUser.is(user) == false && Arrays.binarySearch(user.roles(), SuperuserRole.NAME) < 0) {
// we should filter out the .security index from wildcards // we should filter out the .security index from wildcards
if (indicesAndAliases.remove(SecurityTemplateService.SECURITY_INDEX_NAME)) { if (indicesAndAliases.remove(SecurityTemplateService.SECURITY_INDEX_NAME)) {
logger.debug("removed [{}] from user [{}] list of authorized indices", logger.debug("removed [{}] from user [{}] list of authorized indices",

View File

@ -56,6 +56,7 @@ 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.action.search.SearchTransportService; import org.elasticsearch.action.search.SearchTransportService;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
@ -77,10 +78,12 @@ import org.elasticsearch.xpack.security.user.XPackUser;
import org.junit.Before; import org.junit.Before;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationException; import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationException;
import static org.elasticsearch.test.SecurityTestsUtils.assertAuthorizationException; import static org.elasticsearch.test.SecurityTestsUtils.assertAuthorizationException;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -543,6 +546,11 @@ public class AuthorizationServiceTests extends ESTestCase {
request = new ClusterHealthRequest(SecurityTemplateService.SECURITY_INDEX_NAME, "foo", "bar"); request = new ClusterHealthRequest(SecurityTemplateService.SECURITY_INDEX_NAME, "foo", "bar");
authorizationService.authorize(createAuthentication(user), ClusterHealthAction.NAME, request); authorizationService.authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request); verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request);
SearchRequest searchRequest = new SearchRequest("_all");
IndexNotFoundException e = expectThrows(IndexNotFoundException.class,
() -> authorizationService.authorize(createAuthentication(user), SearchAction.NAME, searchRequest));
assertThat(e.getMessage(), containsString("no such index"));
} }
public void testGrantedNonXPackUserCanExecuteMonitoringOperationsAgainstSecurityIndex() { public void testGrantedNonXPackUserCanExecuteMonitoringOperationsAgainstSecurityIndex() {
@ -589,6 +597,7 @@ public class AuthorizationServiceTests extends ESTestCase {
.numberOfShards(1).numberOfReplicas(0).build(), true) .numberOfShards(1).numberOfReplicas(0).build(), true)
.build()); .build());
for (User user : Arrays.asList(XPackUser.INSTANCE, superuser)) {
List<Tuple<String, TransportRequest>> requests = new ArrayList<>(); List<Tuple<String, TransportRequest>> requests = new ArrayList<>();
requests.add(new Tuple<>(DeleteAction.NAME, new DeleteRequest(SecurityTemplateService.SECURITY_INDEX_NAME, "type", "id"))); requests.add(new Tuple<>(DeleteAction.NAME, new DeleteRequest(SecurityTemplateService.SECURITY_INDEX_NAME, "type", "id")));
requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(SecurityTemplateService.SECURITY_INDEX_NAME, "type", "id"))); requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(SecurityTemplateService.SECURITY_INDEX_NAME, "type", "id")));
@ -608,10 +617,9 @@ public class AuthorizationServiceTests extends ESTestCase {
for (Tuple<String, TransportRequest> requestTuple : requests) { for (Tuple<String, TransportRequest> requestTuple : requests) {
String action = requestTuple.v1(); String action = requestTuple.v1();
TransportRequest request = requestTuple.v2(); TransportRequest request = requestTuple.v2();
authorizationService.authorize(createAuthentication(XPackUser.INSTANCE), action, request); authorizationService.authorize(createAuthentication(user), action, request);
verify(auditTrail).accessGranted(XPackUser.INSTANCE, action, request); verify(auditTrail).accessGranted(user, action, request);
authorizationService.authorize(createAuthentication(superuser), action, request); }
verify(auditTrail).accessGranted(superuser, action, request);
} }
} }
@ -641,6 +649,29 @@ public class AuthorizationServiceTests extends ESTestCase {
authorizationService.authorize(createAuthentication(userWithNoRoles), IndicesExistsAction.NAME, new IndicesExistsRequest("a")); authorizationService.authorize(createAuthentication(userWithNoRoles), IndicesExistsAction.NAME, new IndicesExistsRequest("a"));
} }
public void testXPackUserAndSuperusersCanExecuteOperationAgainstSecurityIndexWithWildcard() {
final User superuser = new User("custom_admin", SuperuserRole.NAME);
when(rolesStore.role(SuperuserRole.NAME)).thenReturn(Role.builder(SuperuserRole.DESCRIPTOR).build());
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
.put(new IndexMetaData.Builder(SecurityTemplateService.SECURITY_INDEX_NAME)
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
.numberOfShards(1).numberOfReplicas(0).build(), true)
.build());
String action = SearchAction.NAME;
SearchRequest request = new SearchRequest("_all");
authorizationService.authorize(createAuthentication(XPackUser.INSTANCE), action, request);
verify(auditTrail).accessGranted(XPackUser.INSTANCE, action, request);
assertThat(request.indices(), arrayContaining(".security"));
request = new SearchRequest("_all");
authorizationService.authorize(createAuthentication(superuser), action, request);
verify(auditTrail).accessGranted(superuser, action, request);
assertThat(request.indices(), arrayContaining(".security"));
}
private Authentication createAuthentication(User user) { private Authentication createAuthentication(User user) {
RealmRef lookedUpBy = user.runAs() == null ? null : new RealmRef("looked", "up", "by"); RealmRef lookedUpBy = user.runAs() == null ? null : new RealmRef("looked", "up", "by");
return new Authentication(user, new RealmRef("test", "test", "foo"), lookedUpBy); return new Authentication(user, new RealmRef("test", "test", "foo"), lookedUpBy);