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:
parent
6284db3a4d
commit
68eb4d981e
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue