Remove implicit index monitor privilege (#37774)
Restricted indices (currently only .security-6 and .security) are special internal indices that require setting the `allow_restricted_indices` flag on every index permission that covers them. If this flag is `false` (default) the permission will not cover these and actions against them will not be authorized. However, the monitoring APIs were the only exception to this rule. This exception is herein forfeited and index monitoring privileges have to be granted explicitly, using the `allow_restricted_indices` flag on the permission, as is the case for any other index privilege.
This commit is contained in:
parent
34d61d3231
commit
697b2fbe52
|
@ -126,3 +126,15 @@ removed.
|
|||
|
||||
The `_termvector` endpoint was deprecated in 2.0 and has now been removed.
|
||||
The endpoint `_termvectors` (plural) should be used instead.
|
||||
|
||||
[float]
|
||||
==== When {security-features} are enabled, index monitoring APIs over restricted indices are not authorized implicitly anymore
|
||||
|
||||
Restricted indices (currently only `.security-6` and `.security`) are special internal
|
||||
indices that require setting the `allow_restricted_indices` flag on every index
|
||||
permission that covers them. If this flag is `false` (default) the permission
|
||||
will not cover these and actions against them will not be authorized.
|
||||
However, the monitoring APIs were the only exception to this rule. This exception
|
||||
has been forfeited and index monitoring privileges have to be granted explicitly,
|
||||
using the `allow_restricted_indices` flag on the permission (as any other index
|
||||
privilege).
|
||||
|
|
|
@ -259,12 +259,8 @@ public final class IndicesPermission {
|
|||
|
||||
private boolean check(String action, String index) {
|
||||
assert index != null;
|
||||
return check(action) && (indexNameMatcher.test(index)
|
||||
&& (allowRestrictedIndices
|
||||
// all good if it is not restricted
|
||||
|| (false == RestrictedIndicesNames.NAMES_SET.contains(index))
|
||||
// allow monitor as a special case, even for restricted
|
||||
|| IndexPrivilege.MONITOR.predicate().test(action)));
|
||||
return check(action) && indexNameMatcher.test(index)
|
||||
&& (allowRestrictedIndices || (false == RestrictedIndicesNames.NAMES_SET.contains(index)));
|
||||
}
|
||||
|
||||
boolean hasQuery() {
|
||||
|
|
|
@ -144,6 +144,7 @@ import org.joda.time.DateTimeZone;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
|
@ -563,9 +564,33 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX, RestrictedIndicesNames.SECURITY_INDEX_NAME)), is(false));
|
||||
|
||||
assertMonitoringOnRestrictedIndices(remoteMonitoringAgentRole);
|
||||
|
||||
assertNoAccessAllowed(remoteMonitoringAgentRole, RestrictedIndicesNames.NAMES_SET);
|
||||
}
|
||||
|
||||
private void assertMonitoringOnRestrictedIndices(Role role) {
|
||||
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
||||
final MetaData metaData = new MetaData.Builder()
|
||||
.put(new IndexMetaData.Builder(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX)
|
||||
.settings(indexSettings)
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
|
||||
.build(), true)
|
||||
.build();
|
||||
final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
|
||||
final List<String> indexMonitoringActionNamesList = Arrays.asList(IndicesStatsAction.NAME, IndicesSegmentsAction.NAME,
|
||||
GetSettingsAction.NAME, IndicesShardStoresAction.NAME, UpgradeStatusAction.NAME, RecoveryAction.NAME);
|
||||
for (final String indexMonitoringActionName : indexMonitoringActionNamesList) {
|
||||
final Map<String, IndexAccessControl> authzMap = role.indices().authorize(indexMonitoringActionName,
|
||||
Sets.newHashSet(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX, RestrictedIndicesNames.SECURITY_INDEX_NAME), metaData,
|
||||
fieldPermissionsCache);
|
||||
assertThat(authzMap.get(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX).isGranted(), is(true));
|
||||
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_INDEX_NAME).isGranted(), is(true));
|
||||
}
|
||||
}
|
||||
|
||||
public void testReportingUserRole() {
|
||||
final TransportRequest request = mock(TransportRequest.class);
|
||||
|
||||
|
|
|
@ -7,14 +7,27 @@ package org.elasticsearch.integration;
|
|||
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.DocWriteResponse;
|
||||
import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse;
|
||||
import org.elasticsearch.action.admin.indices.segments.IndicesSegmentResponse;
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
|
||||
import org.elasticsearch.action.admin.indices.shards.IndicesShardStoresResponse;
|
||||
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
|
||||
import org.elasticsearch.action.admin.indices.upgrade.get.UpgradeStatusResponse;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.action.search.MultiSearchResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
|
@ -25,11 +38,29 @@ import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswo
|
|||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
|
||||
public class MultipleIndicesPermissionsTests extends SecurityIntegTestCase {
|
||||
|
||||
protected static final SecureString USERS_PASSWD = new SecureString("passwd".toCharArray());
|
||||
|
||||
@Before
|
||||
public void waitForSecurityIndexWritable() throws Exception {
|
||||
// adds a dummy user to the native realm to force .security index creation
|
||||
securityClient().preparePutUser("dummy_user", "password".toCharArray(), Hasher.BCRYPT, "missing_role").get();
|
||||
assertSecurityIndexActive();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanupSecurityIndex() throws Exception {
|
||||
super.deleteSecurityIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean addMockHttpTransport() {
|
||||
return false; // enable http
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String configRoles() {
|
||||
return SecuritySettingsSource.TEST_ROLE + ":\n" +
|
||||
|
@ -49,6 +80,12 @@ public class MultipleIndicesPermissionsTests extends SecurityIntegTestCase {
|
|||
" - names: 'a'\n" +
|
||||
" privileges: [all]\n" +
|
||||
"\n" +
|
||||
"role_monitor_all_unrestricted_indices:\n" +
|
||||
" cluster: [monitor]\n" +
|
||||
" indices:\n" +
|
||||
" - names: '*'\n" +
|
||||
" privileges: [monitor]\n" +
|
||||
"\n" +
|
||||
"role_b:\n" +
|
||||
" indices:\n" +
|
||||
" - names: 'b'\n" +
|
||||
|
@ -60,14 +97,16 @@ public class MultipleIndicesPermissionsTests extends SecurityIntegTestCase {
|
|||
final String usersPasswdHashed = new String(getFastStoredHashAlgoForTests().hash(USERS_PASSWD));
|
||||
return SecuritySettingsSource.CONFIG_STANDARD_USER +
|
||||
"user_a:" + usersPasswdHashed + "\n" +
|
||||
"user_ab:" + usersPasswdHashed + "\n";
|
||||
"user_ab:" + usersPasswdHashed + "\n" +
|
||||
"user_monitor:" + usersPasswdHashed + "\n";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String configUsersRoles() {
|
||||
return SecuritySettingsSource.CONFIG_STANDARD_USER_ROLES +
|
||||
"role_a:user_a,user_ab\n" +
|
||||
"role_b:user_ab\n";
|
||||
"role_b:user_ab\n" +
|
||||
"role_monitor_all_unrestricted_indices:user_monitor\n";
|
||||
}
|
||||
|
||||
public void testSingleRole() throws Exception {
|
||||
|
@ -127,6 +166,71 @@ public class MultipleIndicesPermissionsTests extends SecurityIntegTestCase {
|
|||
assertHitCount(searchResponse, 1);
|
||||
}
|
||||
|
||||
public void testMonitorRestrictedWildcards() throws Exception {
|
||||
|
||||
IndexResponse indexResponse = index("foo", "type", jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "value")
|
||||
.endObject());
|
||||
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
|
||||
|
||||
indexResponse = index("foobar", "type", jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "value")
|
||||
.endObject());
|
||||
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
|
||||
|
||||
indexResponse = index("foobarfoo", "type", jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "value")
|
||||
.endObject());
|
||||
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
|
||||
|
||||
refresh();
|
||||
|
||||
final Client client = client()
|
||||
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_monitor", USERS_PASSWD)));
|
||||
|
||||
final GetSettingsResponse getSettingsResponse = client.admin().indices().prepareGetSettings(randomFrom("*", "_all", "foo*")).get();
|
||||
assertThat(getSettingsResponse.getIndexToSettings().size(), is(3));
|
||||
assertThat(getSettingsResponse.getIndexToSettings().containsKey("foo"), is(true));
|
||||
assertThat(getSettingsResponse.getIndexToSettings().containsKey("foobar"), is(true));
|
||||
assertThat(getSettingsResponse.getIndexToSettings().containsKey("foobarfoo"), is(true));
|
||||
|
||||
final IndicesShardStoresResponse indicesShardsStoresResponse = client.admin().indices()
|
||||
.prepareShardStores(randomFrom("*", "_all", "foo*")).setShardStatuses("all").get();
|
||||
assertThat(indicesShardsStoresResponse.getStoreStatuses().size(), is(3));
|
||||
assertThat(indicesShardsStoresResponse.getStoreStatuses().containsKey("foo"), is(true));
|
||||
assertThat(indicesShardsStoresResponse.getStoreStatuses().containsKey("foobar"), is(true));
|
||||
assertThat(indicesShardsStoresResponse.getStoreStatuses().containsKey("foobarfoo"), is(true));
|
||||
|
||||
final UpgradeStatusResponse upgradeStatusResponse = client.admin().indices().prepareUpgradeStatus(randomFrom("*", "_all", "foo*"))
|
||||
.get();
|
||||
assertThat(upgradeStatusResponse.getIndices().size(), is(3));
|
||||
assertThat(upgradeStatusResponse.getIndices().keySet(), containsInAnyOrder("foo", "foobar", "foobarfoo"));
|
||||
|
||||
final IndicesStatsResponse indicesStatsResponse = client.admin().indices().prepareStats(randomFrom("*", "_all", "foo*")).get();
|
||||
assertThat(indicesStatsResponse.getIndices().size(), is(3));
|
||||
assertThat(indicesStatsResponse.getIndices().keySet(), containsInAnyOrder("foo", "foobar", "foobarfoo"));
|
||||
|
||||
final IndicesSegmentResponse indicesSegmentResponse = client.admin().indices().prepareSegments("*").get();
|
||||
assertThat(indicesSegmentResponse.getIndices().size(), is(3));
|
||||
assertThat(indicesSegmentResponse.getIndices().keySet(), containsInAnyOrder("foo", "foobar", "foobarfoo"));
|
||||
|
||||
final RecoveryResponse indicesRecoveryResponse = client.admin().indices().prepareRecoveries("*").get();
|
||||
assertThat(indicesRecoveryResponse.shardRecoveryStates().size(), is(3));
|
||||
assertThat(indicesRecoveryResponse.shardRecoveryStates().keySet(), containsInAnyOrder("foo", "foobar", "foobarfoo"));
|
||||
|
||||
// test _cat/indices with wildcards that cover unauthorized indices (".security" in this case)
|
||||
RequestOptions.Builder optionsBuilder = RequestOptions.DEFAULT.toBuilder();
|
||||
optionsBuilder.addHeader("Authorization", UsernamePasswordToken.basicAuthHeaderValue("user_monitor", USERS_PASSWD));
|
||||
RequestOptions options = optionsBuilder.build();
|
||||
Request catIndicesRequest = new Request("GET", "/_cat/indices/" + randomFrom("*", "_all", "foo*"));
|
||||
catIndicesRequest.setOptions(options);
|
||||
Response catIndicesResponse = getRestClient().performRequest(catIndicesRequest);
|
||||
assertThat(catIndicesResponse.getStatusLine().getStatusCode() < 300, is(true));
|
||||
}
|
||||
|
||||
public void testMultipleRoles() throws Exception {
|
||||
IndexResponse indexResponse = index("a", "type", jsonBuilder()
|
||||
.startObject()
|
||||
|
|
|
@ -78,6 +78,7 @@ public class SecuritySettingsSource extends NodeConfigurationSource {
|
|||
" cluster: [ ALL ]\n" +
|
||||
" indices:\n" +
|
||||
" - names: '*'\n" +
|
||||
" allow_restricted_indices: true\n" +
|
||||
" privileges: [ ALL ]\n";
|
||||
|
||||
private final Path parentFolder;
|
||||
|
|
|
@ -73,6 +73,7 @@ import org.elasticsearch.action.update.UpdateAction;
|
|||
import org.elasticsearch.action.update.UpdateRequest;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.MetaData;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
|
@ -151,7 +152,8 @@ import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationExce
|
|||
import static org.elasticsearch.test.SecurityTestsUtils.assertThrowsAuthorizationException;
|
||||
import static org.elasticsearch.test.SecurityTestsUtils.assertThrowsAuthorizationExceptionRunAs;
|
||||
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX;
|
||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -804,7 +806,7 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
verifyNoMoreInteractions(auditTrail);
|
||||
}
|
||||
|
||||
public void testNonXPackUserCannotExecuteOperationAgainstSecurityIndex() {
|
||||
public void testGrantAllRestrictedUserCannotExecuteOperationAgainstSecurityIndices() {
|
||||
RoleDescriptor role = new RoleDescriptor("all access", new String[]{"all"},
|
||||
new IndicesPrivileges[]{IndicesPrivileges.builder().indices("*").privileges("all").build()}, null);
|
||||
final Authentication authentication = createAuthentication(new User("all_access_user", "all_access"));
|
||||
|
@ -812,29 +814,41 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
ClusterState state = mock(ClusterState.class);
|
||||
when(clusterService.state()).thenReturn(state);
|
||||
when(state.metaData()).thenReturn(MetaData.builder()
|
||||
.put(new IndexMetaData.Builder(SECURITY_INDEX_NAME)
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1).numberOfReplicas(0).build(), true)
|
||||
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
|
||||
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.build(),true)
|
||||
.build());
|
||||
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
|
||||
|
||||
List<Tuple<String, TransportRequest>> requests = new ArrayList<>();
|
||||
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
|
||||
new DeleteRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(UpdateAction.NAME,
|
||||
new UpdateRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
|
||||
new IndexRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(SECURITY_INDEX_NAME)));
|
||||
requests.add(new Tuple<>(TermVectorsAction.NAME,
|
||||
new TermVectorsRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(GetAction.NAME, new GetRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(TermVectorsAction.NAME,
|
||||
new TermVectorsRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest()
|
||||
.addAliasAction(AliasActions.add().alias("security_alias").index(SECURITY_INDEX_NAME))));
|
||||
requests.add(
|
||||
new Tuple<>(UpdateSettingsAction.NAME, new UpdateSettingsRequest().indices(SECURITY_INDEX_NAME)));
|
||||
new Tuple<>(BulkAction.NAME + "[s]", new DeleteRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
|
||||
requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
|
||||
requests.add(new Tuple<>(BulkAction.NAME + "[s]", new IndexRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(TermVectorsAction.NAME,
|
||||
new TermVectorsRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
|
||||
requests.add(new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
|
||||
requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest()
|
||||
.addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(UpdateSettingsAction.NAME,
|
||||
new UpdateSettingsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
// cannot execute monitor operations
|
||||
requests.add(new Tuple<>(IndicesStatsAction.NAME,
|
||||
new IndicesStatsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(
|
||||
new Tuple<>(RecoveryAction.NAME, new RecoveryRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(IndicesSegmentsAction.NAME,
|
||||
new IndicesSegmentsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(GetSettingsAction.NAME,
|
||||
new GetSettingsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(IndicesShardStoresAction.NAME,
|
||||
new IndicesShardStoresRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(UpgradeStatusAction.NAME,
|
||||
new UpgradeStatusRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
|
||||
for (Tuple<String, TransportRequest> requestTuple : requests) {
|
||||
String action = requestTuple.v1();
|
||||
|
@ -847,12 +861,12 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
// we should allow waiting for the health of the index or any index if the user has this permission
|
||||
ClusterHealthRequest request = new ClusterHealthRequest(SECURITY_INDEX_NAME);
|
||||
ClusterHealthRequest request = new ClusterHealthRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX));
|
||||
authorize(authentication, ClusterHealthAction.NAME, request);
|
||||
verify(auditTrail).accessGranted(requestId, authentication, ClusterHealthAction.NAME, request, new String[]{role.getName()});
|
||||
|
||||
// multiple indices
|
||||
request = new ClusterHealthRequest(SECURITY_INDEX_NAME, "foo", "bar");
|
||||
request = new ClusterHealthRequest(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX, "foo", "bar");
|
||||
authorize(authentication, ClusterHealthAction.NAME, request);
|
||||
verify(auditTrail).accessGranted(requestId, authentication, ClusterHealthAction.NAME, request, new String[]{role.getName()});
|
||||
verifyNoMoreInteractions(auditTrail);
|
||||
|
@ -863,17 +877,24 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
assertEquals(IndicesAndAliasesResolver.NO_INDICES_OR_ALIASES_LIST, Arrays.asList(searchRequest.indices()));
|
||||
}
|
||||
|
||||
public void testGrantedNonXPackUserCanExecuteMonitoringOperationsAgainstSecurityIndex() {
|
||||
RoleDescriptor role = new RoleDescriptor("all access", new String[]{"all"},
|
||||
new IndicesPrivileges[]{IndicesPrivileges.builder().indices("*").privileges("all").build()}, null);
|
||||
final Authentication authentication = createAuthentication(new User("all_access_user", "all_access"));
|
||||
roleMap.put("all_access", role);
|
||||
public void testMonitoringOperationsAgainstSecurityIndexRequireAllowRestricted() {
|
||||
final RoleDescriptor restrictedMonitorRole = new RoleDescriptor("restricted_monitor", null,
|
||||
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("*").privileges("monitor").build() }, null);
|
||||
final RoleDescriptor unrestrictedMonitorRole = new RoleDescriptor("unrestricted_monitor", null, new IndicesPrivileges[] {
|
||||
IndicesPrivileges.builder().indices("*").privileges("monitor").allowRestrictedIndices(true).build() }, null);
|
||||
roleMap.put("restricted_monitor", restrictedMonitorRole);
|
||||
roleMap.put("unrestricted_monitor", unrestrictedMonitorRole);
|
||||
final Authentication restrictedUserAuthn = createAuthentication(new User("restricted_user", "restricted_monitor"));
|
||||
final Authentication unrestrictedUserAuthn = createAuthentication(new User("unrestricted_user", "unrestricted_monitor"));
|
||||
ClusterState state = mock(ClusterState.class);
|
||||
when(clusterService.state()).thenReturn(state);
|
||||
when(state.metaData()).thenReturn(MetaData.builder()
|
||||
.put(new IndexMetaData.Builder(SECURITY_INDEX_NAME)
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1).numberOfReplicas(0).build(), true)
|
||||
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
|
||||
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.build(), true)
|
||||
.build());
|
||||
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
|
||||
|
||||
|
@ -882,16 +903,18 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
requests.add(new Tuple<>(RecoveryAction.NAME, new RecoveryRequest().indices(SECURITY_INDEX_NAME)));
|
||||
requests.add(new Tuple<>(IndicesSegmentsAction.NAME, new IndicesSegmentsRequest().indices(SECURITY_INDEX_NAME)));
|
||||
requests.add(new Tuple<>(GetSettingsAction.NAME, new GetSettingsRequest().indices(SECURITY_INDEX_NAME)));
|
||||
requests.add(new Tuple<>(IndicesShardStoresAction.NAME,
|
||||
new IndicesShardStoresRequest().indices(SECURITY_INDEX_NAME)));
|
||||
requests.add(new Tuple<>(UpgradeStatusAction.NAME,
|
||||
new UpgradeStatusRequest().indices(SECURITY_INDEX_NAME)));
|
||||
requests.add(new Tuple<>(IndicesShardStoresAction.NAME, new IndicesShardStoresRequest().indices(SECURITY_INDEX_NAME)));
|
||||
requests.add(new Tuple<>(UpgradeStatusAction.NAME, new UpgradeStatusRequest().indices(SECURITY_INDEX_NAME)));
|
||||
|
||||
for (final Tuple<String, ? extends TransportRequest> requestTuple : requests) {
|
||||
final String action = requestTuple.v1();
|
||||
final TransportRequest request = requestTuple.v2();
|
||||
authorize(authentication, action, request);
|
||||
verify(auditTrail).accessGranted(requestId, authentication, action, request, new String[]{role.getName()});
|
||||
assertThrowsAuthorizationException(() -> authorize(restrictedUserAuthn, action, request), action, "restricted_user");
|
||||
verify(auditTrail).accessDenied(requestId, restrictedUserAuthn, action, request, new String[] { "restricted_monitor" });
|
||||
verifyNoMoreInteractions(auditTrail);
|
||||
authorize(unrestrictedUserAuthn, action, request);
|
||||
verify(auditTrail).accessGranted(requestId, unrestrictedUserAuthn, action, request, new String[] { "unrestricted_monitor" });
|
||||
verifyNoMoreInteractions(auditTrail);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -901,34 +924,35 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
ClusterState state = mock(ClusterState.class);
|
||||
when(clusterService.state()).thenReturn(state);
|
||||
when(state.metaData()).thenReturn(MetaData.builder()
|
||||
.put(new IndexMetaData.Builder(SECURITY_INDEX_NAME)
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1).numberOfReplicas(0).build(), true)
|
||||
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
|
||||
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.build(), true)
|
||||
.build());
|
||||
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
|
||||
|
||||
List<Tuple<String, TransportRequest>> requests = new ArrayList<>();
|
||||
requests.add(new Tuple<>(DeleteAction.NAME,
|
||||
new DeleteRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(DeleteAction.NAME, new DeleteRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
|
||||
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
|
||||
createBulkShardRequest(SECURITY_INDEX_NAME, DeleteRequest::new)));
|
||||
requests.add(new Tuple<>(UpdateAction.NAME,
|
||||
new UpdateRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(IndexAction.NAME,
|
||||
new IndexRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
createBulkShardRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), DeleteRequest::new)));
|
||||
requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
|
||||
requests.add(new Tuple<>(IndexAction.NAME, new IndexRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
|
||||
createBulkShardRequest(SECURITY_INDEX_NAME, IndexRequest::new)));
|
||||
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(SECURITY_INDEX_NAME)));
|
||||
createBulkShardRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), IndexRequest::new)));
|
||||
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(TermVectorsAction.NAME,
|
||||
new TermVectorsRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(GetAction.NAME, new GetRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
new TermVectorsRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
|
||||
requests.add(new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
|
||||
requests.add(new Tuple<>(TermVectorsAction.NAME,
|
||||
new TermVectorsRequest(SECURITY_INDEX_NAME, "type", "id")));
|
||||
requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest()
|
||||
.addAliasAction(AliasActions.add().alias("security_alias").index(SECURITY_INDEX_NAME))));
|
||||
requests.add(new Tuple<>(ClusterHealthAction.NAME, new ClusterHealthRequest(SECURITY_INDEX_NAME)));
|
||||
new TermVectorsRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
|
||||
requests.add(new Tuple<>(IndicesAliasesAction.NAME,
|
||||
new IndicesAliasesRequest().addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(
|
||||
new Tuple<>(ClusterHealthAction.NAME, new ClusterHealthRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
||||
requests.add(new Tuple<>(ClusterHealthAction.NAME,
|
||||
new ClusterHealthRequest(SECURITY_INDEX_NAME, "foo", "bar")));
|
||||
new ClusterHealthRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "foo", "bar")));
|
||||
|
||||
for (final Tuple<String, TransportRequest> requestTuple : requests) {
|
||||
final String action = requestTuple.v1();
|
||||
|
@ -946,9 +970,12 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
ClusterState state = mock(ClusterState.class);
|
||||
when(clusterService.state()).thenReturn(state);
|
||||
when(state.metaData()).thenReturn(MetaData.builder()
|
||||
.put(new IndexMetaData.Builder(SECURITY_INDEX_NAME)
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1).numberOfReplicas(0).build(), true)
|
||||
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
|
||||
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.build(), true)
|
||||
.build());
|
||||
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
|
||||
|
||||
|
@ -956,7 +983,7 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
SearchRequest request = new SearchRequest("_all");
|
||||
authorize(createAuthentication(superuser), action, request);
|
||||
verify(auditTrail).accessGranted(requestId, authentication, action, request, superuser.roles());
|
||||
assertThat(request.indices(), arrayContaining(".security"));
|
||||
assertThat(request.indices(), arrayContainingInAnyOrder(INTERNAL_SECURITY_INDEX, SECURITY_INDEX_NAME));
|
||||
}
|
||||
|
||||
public void testAnonymousRolesAreAppliedToOtherUsers() {
|
||||
|
|
Loading…
Reference in New Issue