From 5e5e66cde8ac0b4376d04959dd8faf585d745677 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Mon, 1 Feb 2021 10:41:10 +1100 Subject: [PATCH] Fix identification of action type in error message Some actions that start with "indices:" are actually handled by cluster privileges in ES security (e.g. indices:admin/template/*) In #60357 and #66900 we added better context information for the error messages that are generated when an action is denied, but the generation of that message did not correctly classify actions between cluster and index level privileges. This change does 2 things: 1. It fixes the code that determines whether an action is handled by a cluster privilege or an index privilege 2. Includes the words "cluster" and "index" in the error message so that classification is clear to the reader The latter change is not directly related to the issue being resolved, but in the course of fixing the issue it became evident that the message lacked clarity because it did not tell the reader what type of privilege would be needed to resolve the access denied issue. Resolves: #68144 --- .../xpack/security/PermissionsIT.java | 2 +- .../security/authc/ApiKeyIntegTests.java | 4 +- .../security/authz/AuthorizationService.java | 14 +- .../authz/AuthorizationServiceTests.java | 259 ++++++++++-------- .../test/api_key/11_invalidation.yml | 4 +- 5 files changed, 157 insertions(+), 126 deletions(-) diff --git a/x-pack/plugin/ilm/qa/with-security/src/javaRestTest/java/org/elasticsearch/xpack/security/PermissionsIT.java b/x-pack/plugin/ilm/qa/with-security/src/javaRestTest/java/org/elasticsearch/xpack/security/PermissionsIT.java index 4d2df7d925397..4c30f598cd94d 100644 --- a/x-pack/plugin/ilm/qa/with-security/src/javaRestTest/java/org/elasticsearch/xpack/security/PermissionsIT.java +++ b/x-pack/plugin/ilm/qa/with-security/src/javaRestTest/java/org/elasticsearch/xpack/security/PermissionsIT.java @@ -146,7 +146,7 @@ public void testCanManageIndexWithNoPermissions() throws Exception { assertThat(stepInfo.get("reason"), equalTo("action [indices:monitor/stats] is unauthorized" + " for user [test_ilm]" + " on indices [not-ilm]," + - " this action is granted by the privileges [monitor,manage,all]")); + " this action is granted by the index privileges [monitor,manage,all]")); } }); } diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java index 8c54c78c376b5..cadf5020bf423 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java @@ -1217,14 +1217,14 @@ private Client getClientForRunAsUser() { private void assertErrorMessage(final ElasticsearchSecurityException ese, String action, String userName, String apiKeyId) { assertThat(ese, throwableWithMessage( containsString("action [" + action + "] is unauthorized for API key id [" + apiKeyId + "] of user [" + userName + "]"))); - assertThat(ese, throwableWithMessage(containsString(", this action is granted by the privileges ["))); + assertThat(ese, throwableWithMessage(containsString(", this action is granted by the cluster privileges ["))); assertThat(ese, throwableWithMessage(containsString("manage_api_key,manage_security,all]"))); } private void assertErrorMessage(final ElasticsearchSecurityException ese, String action, String userName) { assertThat(ese, throwableWithMessage( containsString("action [" + action + "] is unauthorized for user [" + userName + "]"))); - assertThat(ese, throwableWithMessage(containsString(", this action is granted by the privileges ["))); + assertThat(ese, throwableWithMessage(containsString(", this action is granted by the cluster privileges ["))); assertThat(ese, throwableWithMessage(containsString("manage_api_key,manage_security,all]"))); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index 60af63f313c49..fdb822b0a76ae 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -635,15 +635,17 @@ private ElasticsearchSecurityException denialException(Authentication authentica message = message + " " + context; } - if (isIndexAction(action)) { - final Collection privileges = IndexPrivilege.findPrivilegesThatGrant(action); + if (ClusterPrivilegeResolver.isClusterAction(action)) { + final Collection privileges = ClusterPrivilegeResolver.findPrivilegesThatGrant(action, request, authentication); if (privileges != null && privileges.size() > 0) { - message = message + ", this action is granted by the privileges [" + collectionToCommaDelimitedString(privileges) + "]"; + message = message + ", this action is granted by the cluster privileges [" + + collectionToCommaDelimitedString(privileges) + "]"; } - } else if (ClusterPrivilegeResolver.isClusterAction(action)) { - final Collection privileges = ClusterPrivilegeResolver.findPrivilegesThatGrant(action, request, authentication); + } else if (isIndexAction(action)) { + final Collection privileges = IndexPrivilege.findPrivilegesThatGrant(action); if (privileges != null && privileges.size() > 0) { - message = message + ", this action is granted by the privileges [" + collectionToCommaDelimitedString(privileges) + "]"; + message = message + ", this action is granted by the index privileges [" + + collectionToCommaDelimitedString(privileges) + "]"; } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index 03784207a7ff6..15424cf068c06 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -36,6 +36,8 @@ import org.elasticsearch.action.admin.indices.shards.IndicesShardStoresRequest; import org.elasticsearch.action.admin.indices.stats.IndicesStatsAction; import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequest; +import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateAction; +import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.bulk.BulkAction; import org.elasticsearch.action.bulk.BulkItemRequest; import org.elasticsearch.action.bulk.BulkRequest; @@ -285,9 +287,9 @@ auditTrailService, new DefaultAuthenticationFailureHandler(Collections.emptyMap( private void authorize(Authentication authentication, String action, TransportRequest request) { PlainActionFuture done = new PlainActionFuture<>(); - PlainActionFuture indicesPermissions = new PlainActionFuture<>(); - PlainActionFuture originatingAction = new PlainActionFuture<>(); - PlainActionFuture authorizationInfo = new PlainActionFuture<>(); + PlainActionFuture indicesPermissions = new PlainActionFuture<>(); + PlainActionFuture originatingAction = new PlainActionFuture<>(); + PlainActionFuture authorizationInfo = new PlainActionFuture<>(); String someRandomHeader = "test_" + UUIDs.randomBase64UUID(); Object someRandomHeaderValue = mock(Object.class); threadContext.putTransient(someRandomHeader, someRandomHeaderValue); @@ -371,23 +373,23 @@ public void testActionsForSystemUserIsAuthorized() throws IOException { // A failure would throw an exception final Authentication authentication = createAuthentication(SystemUser.INSTANCE); final String[] actions = { - "indices:monitor/whatever", - "internal:whatever", - "cluster:monitor/whatever", - "cluster:admin/reroute", - "indices:admin/mapping/put", - "indices:admin/template/put", - "indices:admin/seq_no/global_checkpoint_sync", - "indices:admin/seq_no/retention_lease_sync", - "indices:admin/seq_no/retention_lease_background_sync", - "indices:admin/seq_no/add_retention_lease", - "indices:admin/seq_no/remove_retention_lease", - "indices:admin/seq_no/renew_retention_lease", - "indices:admin/settings/update" }; + "indices:monitor/whatever", + "internal:whatever", + "cluster:monitor/whatever", + "cluster:admin/reroute", + "indices:admin/mapping/put", + "indices:admin/template/put", + "indices:admin/seq_no/global_checkpoint_sync", + "indices:admin/seq_no/retention_lease_sync", + "indices:admin/seq_no/retention_lease_background_sync", + "indices:admin/seq_no/add_retention_lease", + "indices:admin/seq_no/remove_retention_lease", + "indices:admin/seq_no/renew_retention_lease", + "indices:admin/settings/update"}; for (String action : actions) { authorize(authentication, action, request); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), - authzInfoRoles(new String[] { SystemUser.ROLE_NAME })); + authzInfoRoles(new String[]{SystemUser.ROLE_NAME})); } verifyNoMoreInteractions(auditTrail); @@ -397,13 +399,13 @@ public void testAuthorizationForSecurityChange() { final Authentication authentication = createAuthentication(new User("user", "manage_security_role")); final String requestId = AuditUtil.getOrGenerateRequestId(threadContext); RoleDescriptor role = new RoleDescriptor("manage_security_role", new String[]{ClusterPrivilegeResolver.MANAGE_SECURITY.name()}, - null,null, null, null, null, null); + null, null, null, null, null, null); roleMap.put("manage_security_role", role); for (String action : LoggingAuditTrail.SECURITY_CHANGE_ACTIONS) { TransportRequest request = mock(TransportRequest.class); authorize(authentication, action, request); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), - authzInfoRoles(new String[]{role.getName()})); + authzInfoRoles(new String[]{role.getName()})); } verifyNoMoreInteractions(auditTrail); } @@ -428,7 +430,7 @@ public void testClusterAdminActionsForSystemUserWhichAreNotAuthorized() throws I () -> authorize(authentication, "cluster:admin/whatever", request), "cluster:admin/whatever", SystemUser.INSTANCE.principal()); verify(auditTrail).accessDenied(eq(requestId), eq(authentication), eq("cluster:admin/whatever"), eq(request), - authzInfoRoles(new String[] { SystemUser.ROLE_NAME })); + authzInfoRoles(new String[]{SystemUser.ROLE_NAME})); verifyNoMoreInteractions(auditTrail); } @@ -440,7 +442,7 @@ public void testClusterAdminSnapshotStatusActionForSystemUserWhichIsNotAuthorize () -> authorize(authentication, "cluster:admin/snapshot/status", request), "cluster:admin/snapshot/status", SystemUser.INSTANCE.principal()); verify(auditTrail).accessDenied(eq(requestId), eq(authentication), eq("cluster:admin/snapshot/status"), eq(request), - authzInfoRoles(new String[] { SystemUser.ROLE_NAME })); + authzInfoRoles(new String[]{SystemUser.ROLE_NAME})); verifyNoMoreInteractions(auditTrail); } @@ -457,11 +459,11 @@ public ClusterPermission.Builder buildPermission(ClusterPermission.Builder build return builder; } }; - final ConfigurableClusterPrivilege[] configurableClusterPrivileges = new ConfigurableClusterPrivilege[] { + final ConfigurableClusterPrivilege[] configurableClusterPrivileges = new ConfigurableClusterPrivilege[]{ configurableClusterPrivilege }; final String requestId = AuditUtil.getOrGenerateRequestId(threadContext); - RoleDescriptor role = new RoleDescriptor("role1", null, null, null, configurableClusterPrivileges, null, null ,null); + RoleDescriptor role = new RoleDescriptor("role1", null, null, null, configurableClusterPrivileges, null, null, null); roleMap.put("role1", role); authorize(authentication, DeletePrivilegesAction.NAME, request); @@ -483,11 +485,11 @@ public ClusterPermission.Builder buildPermission(ClusterPermission.Builder build return builder; } }; - final ConfigurableClusterPrivilege[] configurableClusterPrivileges = new ConfigurableClusterPrivilege[] { + final ConfigurableClusterPrivilege[] configurableClusterPrivileges = new ConfigurableClusterPrivilege[]{ configurableClusterPrivilege }; final String requestId = AuditUtil.getOrGenerateRequestId(threadContext); - RoleDescriptor role = new RoleDescriptor("role1", null, null, null, configurableClusterPrivileges, null, null ,null); + RoleDescriptor role = new RoleDescriptor("role1", null, null, null, configurableClusterPrivileges, null, null, null); roleMap.put("role1", role); assertThrowsAuthorizationException( @@ -530,7 +532,7 @@ public void testUserWithNoRolesPerformsRemoteSearchWithScroll() { final Authentication authentication = createAuthentication(new User("test user")); mockEmptyMetadata(); final String requestId = AuditUtil.getOrGenerateRequestId(threadContext); - for (final boolean hasLocalIndices: List.of(true, false)) { + for (final boolean hasLocalIndices : List.of(true, false)) { when(parsedScrollId.hasLocalIndices()).thenReturn(hasLocalIndices); if (hasLocalIndices) { assertThrowsAuthorizationException( @@ -538,12 +540,12 @@ public void testUserWithNoRolesPerformsRemoteSearchWithScroll() { "indices:data/read/scroll", "test user" ); verify(auditTrail).accessDenied(eq(requestId), eq(authentication), - eq("indices:data/read/scroll"), eq(searchScrollRequest), - authzInfoRoles(Role.EMPTY.names())); + eq("indices:data/read/scroll"), eq(searchScrollRequest), + authzInfoRoles(Role.EMPTY.names())); } else { authorize(authentication, SearchScrollAction.NAME, searchScrollRequest); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(SearchScrollAction.NAME), eq(searchScrollRequest), - authzInfoRoles(Role.EMPTY.names())); + authzInfoRoles(Role.EMPTY.names())); } verifyNoMoreInteractions(auditTrail); } @@ -621,8 +623,8 @@ public void testUserWithNoRolesOpenPointInTimeWithRemoteIndices() { final Authentication authentication = createAuthentication(new User("test user")); mockEmptyMetadata(); final String requestId = AuditUtil.getOrGenerateRequestId(threadContext); - for (final boolean hasLocalIndices: List.of(true, false)) { - final String[] indices = new String[] { + for (final boolean hasLocalIndices : List.of(true, false)) { + final String[] indices = new String[]{ hasLocalIndices ? randomAlphaOfLength(5) : "other_cluster:" + randomFrom(randomAlphaOfLength(5), "*", randomAlphaOfLength(4) + "*"), @@ -638,13 +640,13 @@ public void testUserWithNoRolesOpenPointInTimeWithRemoteIndices() { "indices:data/read/open_point_in_time", "test user" ); verify(auditTrail).accessDenied(eq(requestId), eq(authentication), - eq("indices:data/read/open_point_in_time"), eq(openPointInTimeRequest), - authzInfoRoles(Role.EMPTY.names())); + eq("indices:data/read/open_point_in_time"), eq(openPointInTimeRequest), + authzInfoRoles(Role.EMPTY.names())); } else { authorize(authentication, OpenPointInTimeAction.NAME, openPointInTimeRequest); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), - eq("indices:data/read/open_point_in_time"), eq(openPointInTimeRequest), - authzInfoRoles(Role.EMPTY.names())); + eq("indices:data/read/open_point_in_time"), eq(openPointInTimeRequest), + authzInfoRoles(Role.EMPTY.names())); } verifyNoMoreInteractions(auditTrail); } @@ -657,8 +659,8 @@ public void testUserWithNoRolesCanClosePointInTime() { final String requestId = AuditUtil.getOrGenerateRequestId(threadContext); authorize(authentication, ClosePointInTimeAction.NAME, closePointInTimeRequest); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), - eq("indices:data/read/close_point_in_time"), eq(closePointInTimeRequest), - authzInfoRoles(Role.EMPTY.names())); + eq("indices:data/read/close_point_in_time"), eq(closePointInTimeRequest), + authzInfoRoles(Role.EMPTY.names())); verifyNoMoreInteractions(auditTrail); } @@ -676,7 +678,7 @@ public void testUnknownRoleCausesDenial() throws IOException { () -> authorize(authentication, action, request)); assertThat(securityException, throwableWithMessage(containsString("[" + action + "] is unauthorized for user [test user] on indices ["))); - assertThat(securityException, throwableWithMessage(containsString("this action is granted by the privileges [read,all]"))); + assertThat(securityException, throwableWithMessage(containsString("this action is granted by the index privileges [read,all]"))); verify(auditTrail).accessDenied(eq(requestId), eq(authentication), eq(action), eq(request), authzInfoRoles(Role.EMPTY.names())); verifyNoMoreInteractions(auditTrail); @@ -715,7 +717,7 @@ public void testThatRoleWithNoIndicesIsDenied() throws IOException { () -> authorize(authentication, action, request)); assertThat(securityException, throwableWithMessage(containsString("[" + action + "] is unauthorized for user [test user] on indices ["))); - assertThat(securityException, throwableWithMessage(containsString("this action is granted by the privileges [read,all]"))); + assertThat(securityException, throwableWithMessage(containsString("this action is granted by the index privileges [read,all]"))); verify(auditTrail).accessDenied(eq(requestId), eq(authentication), eq(action), eq(request), authzInfoRoles(new String[]{role.getName()})); @@ -906,7 +908,7 @@ public void testDenialErrorMessagesForSearchAction() throws IOException { assertThat(securityException, throwableWithMessage(containsString("other-4"))); assertThat(securityException, throwableWithMessage(not(containsString("all-1")))); assertThat(securityException, throwableWithMessage(not(containsString("read-2")))); - assertThat(securityException, throwableWithMessage(containsString(", this action is granted by the privileges [read,all]"))); + assertThat(securityException, throwableWithMessage(containsString(", this action is granted by the index privileges [read,all]"))); } public void testDenialErrorMessagesForBulkIngest() throws Exception { @@ -948,15 +950,15 @@ public void testDenialErrorMessagesForBulkIngest() throws Exception { assertThat(response.getResponses(), arrayWithSize(3)); assertThat(response.getResponses()[0].getFailureMessage(), containsString("unauthorized for user [" + user.principal() + "]")); assertThat(response.getResponses()[0].getFailureMessage(), containsString("on indices [" + index + "]")); - assertThat(response.getResponses()[0].getFailureMessage(), containsString("[create_doc,create,index,write,all]") ); - assertThat(response.getResponses()[1].getFailureMessage(), containsString("[create,index,write,all]") ); - assertThat(response.getResponses()[2].getFailureMessage(), containsString("[delete,write,all]") ); + assertThat(response.getResponses()[0].getFailureMessage(), containsString("[create_doc,create,index,write,all]")); + assertThat(response.getResponses()[1].getFailureMessage(), containsString("[create,index,write,all]")); + assertThat(response.getResponses()[2].getFailureMessage(), containsString("[delete,write,all]")); } public void testDenialErrorMessagesForClusterHealthAction() throws IOException { RoleDescriptor role = new RoleDescriptor("role_" + randomAlphaOfLengthBetween(3, 6), new String[0], // no cluster privileges - new IndicesPrivileges[] { IndicesPrivileges.builder().indices("index-*").privileges("all").build() } , null); + new IndicesPrivileges[]{IndicesPrivileges.builder().indices("index-*").privileges("all").build()}, null); User user = new User(randomAlphaOfLengthBetween(6, 8), role.getName()); final Authentication authentication = createAuthentication(user); roleMap.put(role.getName(), role); @@ -970,7 +972,33 @@ public void testDenialErrorMessagesForClusterHealthAction() throws IOException { assertThat(securityException, throwableWithMessage( containsString("[" + ClusterHealthAction.NAME + "] is unauthorized for user [" + user.principal() + "]"))); assertThat(securityException, - throwableWithMessage(containsString("this action is granted by the privileges [monitor,manage,all]"))); + throwableWithMessage(containsString("this action is granted by the cluster privileges [monitor,manage,all]"))); + } + + /** + * Per {@link ClusterPrivilegeResolver#isClusterAction(String)}, there are some actions that start with "indices:" but are treated as + * cluster level actions for the purposes of security. + * This test case checks that the error message for these actions handles this edge-case. + */ + public void testDenialErrorMessagesForIndexTemplateAction() throws IOException { + RoleDescriptor role = new RoleDescriptor("role_" + randomAlphaOfLengthBetween(3, 6), + new String[0], // no cluster privileges + new IndicesPrivileges[0], // no index privileges + null); + User user = new User(randomAlphaOfLengthBetween(6, 8), role.getName()); + final Authentication authentication = createAuthentication(user); + roleMap.put(role.getName(), role); + + AuditUtil.getOrGenerateRequestId(threadContext); + + TransportRequest request = new PutIndexTemplateRequest(randomAlphaOfLengthBetween(4, 20)); + + ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class, + () -> authorize(authentication, PutIndexTemplateAction.NAME, request)); + assertThat(securityException, throwableWithMessage( + containsString("[" + PutIndexTemplateAction.NAME + "] is unauthorized for user [" + user.principal() + "]"))); + assertThat(securityException, + throwableWithMessage(containsString("this action is granted by the cluster privileges [manage_index_templates,manage,all]"))); } public void testDenialErrorMessagesForInvalidateApiKeyAction() throws IOException { @@ -992,7 +1020,8 @@ public void testDenialErrorMessagesForInvalidateApiKeyAction() throws IOExceptio assertThat(securityException, throwableWithMessage( containsString("[" + InvalidateApiKeyAction.NAME + "] is unauthorized for user [" + user.principal() + "]"))); assertThat(securityException, throwableWithMessage( - containsString("this action is granted by the privileges [manage_own_api_key,manage_api_key,manage_security,all]"))); + containsString("this action is granted by the cluster privileges [manage_own_api_key,manage_api_key,manage_security,all]") + )); } // All API Keys @@ -1004,7 +1033,7 @@ public void testDenialErrorMessagesForInvalidateApiKeyAction() throws IOExceptio assertThat(securityException, throwableWithMessage( containsString("[" + InvalidateApiKeyAction.NAME + "] is unauthorized for user [" + user.principal() + "]"))); assertThat(securityException, throwableWithMessage( - containsString("this action is granted by the privileges [manage_api_key,manage_security,all]"))); + containsString("this action is granted by the cluster privileges [manage_api_key,manage_security,all]"))); } } @@ -1019,7 +1048,7 @@ public void testDenialForAnonymousUser() throws IOException { new IndexNameExpressionResolver(new ThreadContext(Settings.EMPTY)), operatorPrivilegesService); RoleDescriptor role = new RoleDescriptor("a_all", null, - new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null); + new IndicesPrivileges[]{IndicesPrivileges.builder().indices("a").privileges("all").build()}, null); roleMap.put("a_all", role); final String requestId = AuditUtil.getOrGenerateRequestId(threadContext); @@ -1109,7 +1138,7 @@ public void testRunAsRequestWithoutLookedUpBy() throws IOException { () -> authorize(authentication, AuthenticateAction.NAME, request), AuthenticateAction.NAME, "test user", "run as me"); // run as [run as me] verify(auditTrail).runAsDenied(eq(requestId), eq(authentication), eq(AuthenticateAction.NAME), eq(request), - authzInfoRoles(new String[] { ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName() })); + authzInfoRoles(new String[]{ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName()})); verifyNoMoreInteractions(auditTrail); } @@ -1214,40 +1243,40 @@ public void testGrantAllRestrictedUserCannotExecuteOperationAgainstSecurityIndic when(clusterService.state()).thenReturn(state); when(state.metadata()).thenReturn(Metadata.builder() .put(new IndexMetadata.Builder(INTERNAL_SECURITY_MAIN_INDEX_7) - .putAlias(new AliasMetadata.Builder(SECURITY_MAIN_ALIAS).build()) - .settings(Settings.builder().put("index.version.created", Version.CURRENT).build()) - .numberOfShards(1) - .numberOfReplicas(0) - .build(),true) + .putAlias(new AliasMetadata.Builder(SECURITY_MAIN_ALIAS).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> requests = new ArrayList<>(); requests.add(new Tuple<>(BulkAction.NAME + "[s]", - new DeleteRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); + new DeleteRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add( - new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); + new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add( - new Tuple<>(BulkAction.NAME + "[s]", new IndexRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); + new Tuple<>(BulkAction.NAME + "[s]", new IndexRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(TermVectorsAction.NAME, - new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); + new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add(new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest() - .addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_MAIN_INDEX_7)))); + .addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(UpdateSettingsAction.NAME, - new UpdateSettingsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); + new UpdateSettingsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); // cannot execute monitor operations requests.add(new Tuple<>(IndicesStatsAction.NAME, - new IndicesStatsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); + new IndicesStatsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(RecoveryAction.NAME, - new RecoveryRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); + new RecoveryRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(IndicesSegmentsAction.NAME, - new IndicesSegmentsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); + new IndicesSegmentsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(GetSettingsAction.NAME, - new GetSettingsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); + new GetSettingsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(IndicesShardStoresAction.NAME, - new IndicesShardStoresRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); + new IndicesShardStoresRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); for (Tuple requestTuple : requests) { String action = requestTuple.v1(); @@ -1281,20 +1310,20 @@ public void testGrantAllRestrictedUserCannotExecuteOperationAgainstSecurityIndic public void testMonitoringOperationsAgainstSecurityIndexRequireAllowRestricted() throws IOException { 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); + 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); ClusterState state = mock(ClusterState.class); when(clusterService.state()).thenReturn(state); when(state.metadata()).thenReturn(Metadata.builder() .put(new IndexMetadata.Builder(INTERNAL_SECURITY_MAIN_INDEX_7) - .putAlias(new AliasMetadata.Builder(SECURITY_MAIN_ALIAS).build()) - .settings(Settings.builder().put("index.version.created", Version.CURRENT).build()) - .numberOfShards(1) - .numberOfReplicas(0) - .build(), true) + .putAlias(new AliasMetadata.Builder(SECURITY_MAIN_ALIAS).build()) + .settings(Settings.builder().put("index.version.created", Version.CURRENT).build()) + .numberOfShards(1) + .numberOfReplicas(0) + .build(), true) .build()); List> requests = new ArrayList<>(); @@ -1312,7 +1341,7 @@ public void testMonitoringOperationsAgainstSecurityIndexRequireAllowRestricted() final Authentication restrictedUserAuthn = createAuthentication(new User("restricted_user", "restricted_monitor")); assertThrowsAuthorizationException(() -> authorize(restrictedUserAuthn, action, request), action, "restricted_user"); verify(auditTrail).accessDenied(eq(requestId), eq(restrictedUserAuthn), eq(action), eq(request), - authzInfoRoles(new String[] { "restricted_monitor" })); + authzInfoRoles(new String[]{"restricted_monitor"})); verifyNoMoreInteractions(auditTrail); } try (StoredContext ignore = threadContext.stashContext()) { @@ -1320,7 +1349,7 @@ public void testMonitoringOperationsAgainstSecurityIndexRequireAllowRestricted() final Authentication unrestrictedUserAuthn = createAuthentication(new User("unrestricted_user", "unrestricted_monitor")); authorize(unrestrictedUserAuthn, action, request); verify(auditTrail).accessGranted(eq(requestId), eq(unrestrictedUserAuthn), eq(action), eq(request), - authzInfoRoles(new String[] { "unrestricted_monitor" })); + authzInfoRoles(new String[]{"unrestricted_monitor"})); verifyNoMoreInteractions(auditTrail); } } @@ -1333,38 +1362,38 @@ public void testSuperusersCanExecuteOperationAgainstSecurityIndex() throws IOExc when(clusterService.state()).thenReturn(state); when(state.metadata()).thenReturn(Metadata.builder() .put(new IndexMetadata.Builder(INTERNAL_SECURITY_MAIN_INDEX_7) - .putAlias(new AliasMetadata.Builder(SECURITY_MAIN_ALIAS).build()) - .settings(Settings.builder().put("index.version.created", Version.CURRENT).build()) - .numberOfShards(1) - .numberOfReplicas(0) - .build(), true) + .putAlias(new AliasMetadata.Builder(SECURITY_MAIN_ALIAS).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> requests = new ArrayList<>(); requests.add( - new Tuple<>(DeleteAction.NAME, new DeleteRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); + new Tuple<>(DeleteAction.NAME, new DeleteRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add(new Tuple<>(BulkAction.NAME + "[s]", - createBulkShardRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), DeleteRequest::new))); + createBulkShardRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), DeleteRequest::new))); requests.add( - new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); + new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add(new Tuple<>(IndexAction.NAME, new IndexRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(BulkAction.NAME + "[s]", - createBulkShardRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), - (index, id) -> new IndexRequest(index).id(id)))); + createBulkShardRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), + (index, id) -> new IndexRequest(index).id(id)))); requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(TermVectorsAction.NAME, - new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); + new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add( - new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); + new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add(new Tuple<>(TermVectorsAction.NAME, - new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); + new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id"))); requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest() - .addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_MAIN_INDEX_7)))); + .addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(ClusterHealthAction.NAME, - new ClusterHealthRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); + new ClusterHealthRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7)))); requests.add(new Tuple<>(ClusterHealthAction.NAME, - new ClusterHealthRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "foo", "bar"))); + new ClusterHealthRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "foo", "bar"))); for (final Tuple requestTuple : requests) { final String action = requestTuple.v1(); @@ -1386,11 +1415,11 @@ public void testSuperusersCanExecuteOperationAgainstSecurityIndexWithWildcard() when(clusterService.state()).thenReturn(state); when(state.metadata()).thenReturn(Metadata.builder() .put(new IndexMetadata.Builder(INTERNAL_SECURITY_MAIN_INDEX_7) - .putAlias(new AliasMetadata.Builder(SECURITY_MAIN_ALIAS).build()) - .settings(Settings.builder().put("index.version.created", Version.CURRENT).build()) - .numberOfShards(1) - .numberOfReplicas(0) - .build(), true) + .putAlias(new AliasMetadata.Builder(SECURITY_MAIN_ALIAS).build()) + .settings(Settings.builder().put("index.version.created", Version.CURRENT).build()) + .numberOfShards(1) + .numberOfReplicas(0) + .build(), true) .build()); final String requestId = AuditUtil.getOrGenerateRequestId(threadContext); @@ -1414,7 +1443,7 @@ public void testCompositeActionsAreImmediatelyRejected() { assertThrowsAuthorizationException( () -> authorize(authentication, action, request), action, "test user"); verify(auditTrail).accessDenied(eq(requestId), eq(authentication), eq(action), eq(request), - authzInfoRoles(new String[] { role.getName() })); + authzInfoRoles(new String[]{role.getName()})); verifyNoMoreInteractions(auditTrail); } @@ -1432,7 +1461,7 @@ public void testCompositeActionsIndicesAreNotChecked() throws IOException { authorize(authentication, action, request); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), - authzInfoRoles(new String[] { role.getName() })); + authzInfoRoles(new String[]{role.getName()})); verifyNoMoreInteractions(auditTrail); } @@ -1521,25 +1550,25 @@ public void testAuthorizationOfIndividualBulkItems() throws IOException { authorize(authentication, action, request); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(DeleteAction.NAME), eq("concrete-index"), eq(BulkItemRequest.class.getSimpleName()), - eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); + eq(DeleteAction.NAME), eq("concrete-index"), eq(BulkItemRequest.class.getSimpleName()), + eq(request.remoteAddress()), authzInfoRoles(new String[]{role.getName()})); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(DeleteAction.NAME), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), - eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); + eq(DeleteAction.NAME), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), + eq(request.remoteAddress()), authzInfoRoles(new String[]{role.getName()})); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME + ":op_type/index"), eq("concrete-index"), eq(BulkItemRequest.class.getSimpleName()), - eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); + eq(IndexAction.NAME + ":op_type/index"), eq("concrete-index"), eq(BulkItemRequest.class.getSimpleName()), + eq(request.remoteAddress()), authzInfoRoles(new String[]{role.getName()})); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME + ":op_type/index"), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), - eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); + eq(IndexAction.NAME + ":op_type/index"), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), + eq(request.remoteAddress()), authzInfoRoles(new String[]{role.getName()})); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_DENIED), eq(authentication), - eq(DeleteAction.NAME), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), - eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); + eq(DeleteAction.NAME), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), + eq(request.remoteAddress()), authzInfoRoles(new String[]{role.getName()})); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_DENIED), eq(authentication), - eq(IndexAction.NAME + ":op_type/index"), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), - eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); + eq(IndexAction.NAME + ":op_type/index"), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), + eq(request.remoteAddress()), authzInfoRoles(new String[]{role.getName()})); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), - authzInfoRoles(new String[] { role.getName() })); // bulk request is allowed + authzInfoRoles(new String[]{role.getName()})); // bulk request is allowed verifyNoMoreInteractions(auditTrail); } @@ -1567,11 +1596,11 @@ public void testAuthorizationOfIndividualBulkItemsWithDateMath() throws IOExcept // both deletes should fail verify(auditTrail, times(2)).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_DENIED), eq(authentication), - eq(DeleteAction.NAME), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), - eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); + eq(DeleteAction.NAME), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), + eq(request.remoteAddress()), authzInfoRoles(new String[]{role.getName()})); verify(auditTrail, times(2)).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME + ":op_type/index"), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), - eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); + eq(IndexAction.NAME + ":op_type/index"), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), + eq(request.remoteAddress()), authzInfoRoles(new String[]{role.getName()})); // bulk request is allowed verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), authzInfoRoles(new String[]{role.getName()})); diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/api_key/11_invalidation.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/api_key/11_invalidation.yml index 06f75cbb8ac16..6d11f3eabfcb3 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/api_key/11_invalidation.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/api_key/11_invalidation.yml @@ -126,7 +126,7 @@ teardown: "username": "api_key_manager" } - match: { "error.type": "security_exception" } - - match: { "error.reason": "action [cluster:admin/xpack/security/api_key/invalidate] is unauthorized for user [api_key_user_1], this action is granted by the privileges [manage_api_key,manage_security,all]" } + - match: { "error.reason": "action [cluster:admin/xpack/security/api_key/invalidate] is unauthorized for user [api_key_user_1], this action is granted by the cluster privileges [manage_api_key,manage_security,all]" } - do: headers: @@ -189,7 +189,7 @@ teardown: "realm_name": "default_native" } - match: { "error.type": "security_exception" } - - match: { "error.reason": "action [cluster:admin/xpack/security/api_key/invalidate] is unauthorized for user [api_key_user_1], this action is granted by the privileges [manage_api_key,manage_security,all]" } + - match: { "error.reason": "action [cluster:admin/xpack/security/api_key/invalidate] is unauthorized for user [api_key_user_1], this action is granted by the cluster privileges [manage_api_key,manage_security,all]" } - do: headers: