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 acd0809410fce..94d39d2b8dc8a 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,6 +146,7 @@ public void testCanManageIndexWithNoPermissions() throws Exception { assertThat(stepInfo.get("type"), equalTo("security_exception")); assertThat(stepInfo.get("reason"), equalTo("action [indices:monitor/stats] is unauthorized" + " for user [test_ilm]" + + " with roles [ilm]" + " on indices [not-ilm]," + " this action is granted by the index privileges [monitor,manage,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 86e907187514a..4e81f7f3260c5 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 @@ -28,6 +28,7 @@ import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; @@ -630,6 +631,9 @@ private ElasticsearchSecurityException denialException(Authentication authentica final String apiKeyId = (String) authentication.getMetadata().get(ApiKeyService.API_KEY_ID_KEY); assert apiKeyId != null : "api key id must be present in the metadata"; userText = "API key id [" + apiKeyId + "] of " + userText; + } else { + // Don't print roles for API keys because they're not meaningful + userText = userText + " with roles [" + Strings.arrayToCommaDelimitedString(authentication.getUser().roles()) + "]"; } String message = "action [" + action + "] is unauthorized for " + userText; 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 546625da6e30d..4949b12b4947d 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 @@ -677,8 +677,11 @@ public void testUnknownRoleCausesDenial() throws IOException { ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class, () -> authorize(authentication, action, request)); - assertThat(securityException, - throwableWithMessage(containsString("[" + action + "] is unauthorized for user [test user] on indices ["))); + assertThat(securityException, throwableWithMessage(containsString( + "[" + action + "] is unauthorized" + + " for user [test user]" + + " with roles [non-existent-role]" + + " on indices ["))); 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())); @@ -716,8 +719,11 @@ public void testThatRoleWithNoIndicesIsDenied() throws IOException { ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class, () -> authorize(authentication, action, request)); - assertThat(securityException, - throwableWithMessage(containsString("[" + action + "] is unauthorized for user [test user] on indices ["))); + assertThat(securityException, throwableWithMessage(containsString( + "[" + action + "] is unauthorized" + + " for user [test user]" + + " with roles [no_indices]" + + " on indices ["))); 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), @@ -888,14 +894,16 @@ public void testCreateIndexWithAlias() throws IOException { } public void testDenialErrorMessagesForSearchAction() throws IOException { - RoleDescriptor role = new RoleDescriptor("some_indices_" + randomAlphaOfLengthBetween(3, 6), null, new IndicesPrivileges[]{ + RoleDescriptor indexRole = new RoleDescriptor("some_indices_" + randomAlphaOfLengthBetween(3, 6), null, new IndicesPrivileges[]{ IndicesPrivileges.builder().indices("all*").privileges("all").build(), IndicesPrivileges.builder().indices("read*").privileges("read").build(), IndicesPrivileges.builder().indices("write*").privileges("write").build() }, null); - User user = new User(randomAlphaOfLengthBetween(6, 8), role.getName()); + RoleDescriptor emptyRole = new RoleDescriptor("empty_role_" + randomAlphaOfLengthBetween(1,4), null, null, null); + User user = new User(randomAlphaOfLengthBetween(6, 8), indexRole.getName(), emptyRole.getName()); final Authentication authentication = createAuthentication(user); - roleMap.put(role.getName(), role); + roleMap.put(indexRole.getName(), indexRole); + roleMap.put(emptyRole.getName(), emptyRole); AuditUtil.getOrGenerateRequestId(threadContext); @@ -903,8 +911,11 @@ public void testDenialErrorMessagesForSearchAction() throws IOException { ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class, () -> authorize(authentication, SearchAction.NAME, request)); - assertThat(securityException, throwableWithMessage( - containsString("[" + SearchAction.NAME + "] is unauthorized for user [" + user.principal() + "] on indices ["))); + assertThat(securityException, throwableWithMessage(containsString( + "[" + SearchAction.NAME + "] is unauthorized" + + " for user [" + user.principal() + "]" + + " with roles [" + indexRole.getName() + "," + emptyRole.getName() + "]" + + " on indices ["))); assertThat(securityException, throwableWithMessage(containsString("write-3"))); assertThat(securityException, throwableWithMessage(containsString("other-4"))); assertThat(securityException, throwableWithMessage(not(containsString("all-1")))); 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 6d11f3eabfcb3..52ff03ac6e46e 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,8 @@ 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 cluster 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] with roles [user_role], this action is granted by the cluster privileges [manage_api_key,manage_security,all]" - do: headers: @@ -189,7 +190,8 @@ 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 cluster 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] with roles [user_role], this action is granted by the cluster privileges [manage_api_key,manage_security,all]" - do: headers: