diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityContext.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityContext.java index a7c9071ef9c25..e8f390c57380d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityContext.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityContext.java @@ -187,7 +187,7 @@ public void executeAfterRewritingAuthentication(Consumer consumer private Map rewriteMetadataForApiKeyRoleDescriptors(Version streamVersion, Authentication authentication) { Map metadata = authentication.getMetadata(); // If authentication type is API key, regardless whether it has run-as, the metadata must contain API key role descriptors - if (authentication.isAuthenticatedWithApiKey()) { + if (authentication.isAuthenticatedAsApiKey()) { if (authentication.getVersion().onOrAfter(VERSION_API_KEY_ROLES_AS_BYTES) && streamVersion.before(VERSION_API_KEY_ROLES_AS_BYTES)) { metadata = new HashMap<>(metadata); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java index 3f49b2227c617..0485f23a82349 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java @@ -121,22 +121,34 @@ public boolean isAuthenticatedWithServiceAccount() { return ServiceAccountSettings.REALM_TYPE.equals(getAuthenticatedBy().getType()); } - public boolean isAuthenticatedWithApiKey() { - return AuthenticationType.API_KEY.equals(getAuthenticationType()); + /** + * Whether the authenticating user is an API key, including a simple API key or a token created by an API key. + * @return + */ + public boolean isAuthenticatedAsApiKey() { + final boolean result = AuthenticationField.API_KEY_REALM_TYPE.equals(getAuthenticatedBy().getType()); + assert false == result || AuthenticationField.API_KEY_REALM_NAME.equals(getAuthenticatedBy().getName()); + return result; } /** * Authenticate with a service account and no run-as */ public boolean isServiceAccount() { - return isAuthenticatedWithServiceAccount() && false == getUser().isRunAs(); + final boolean result = ServiceAccountSettings.REALM_TYPE.equals(getSourceRealm().getType()); + assert false == result || ServiceAccountSettings.REALM_NAME.equals(getSourceRealm().getName()) + : "service account realm name mismatch"; + return result; } /** - * Authenticated with an API key and no run-as + * Whether the effective user is an API key, this including a simple API key authentication + * or a token created by the API key. */ public boolean isApiKey() { - return isAuthenticatedWithApiKey() && false == getUser().isRunAs(); + final boolean result = AuthenticationField.API_KEY_REALM_TYPE.equals(getSourceRealm().getType()); + assert false == result || AuthenticationField.API_KEY_REALM_NAME.equals(getSourceRealm().getName()) : "api key realm name mismatch"; + return result; } /** @@ -292,7 +304,7 @@ public void toXContentFragment(XContentBuilder builder) throws IOException { } private void assertApiKeyMetadata() { - assert (false == isAuthenticatedWithApiKey()) || (this.metadata.get(AuthenticationField.API_KEY_ID_KEY) != null) + assert (false == isAuthenticatedAsApiKey()) || (this.metadata.get(AuthenticationField.API_KEY_ID_KEY) != null) : "API KEY authentication requires metadata to contain API KEY id, and the value must be non-null."; } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilegeTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilegeTests.java index 267461cbf73ce..13c40a356022c 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilegeTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilegeTests.java @@ -187,8 +187,9 @@ private Authentication createMockAuthentication( when(authentication.getSourceRealm()).thenReturn(authenticatedBy); when(authentication.getAuthenticationType()).thenReturn(authenticationType); when(authenticatedBy.getName()).thenReturn(realmName); + when(authenticatedBy.getType()).thenReturn(realmName); when(authentication.getMetadata()).thenReturn(metadata); - when(authentication.isAuthenticatedWithApiKey()).thenCallRealMethod(); + when(authentication.isAuthenticatedAsApiKey()).thenCallRealMethod(); when(authentication.isApiKey()).thenCallRealMethod(); return authentication; } diff --git a/x-pack/plugin/identity-provider/src/test/java/org/elasticsearch/xpack/idp/action/TransportSamlInitiateSingleSignOnActionTests.java b/x-pack/plugin/identity-provider/src/test/java/org/elasticsearch/xpack/idp/action/TransportSamlInitiateSingleSignOnActionTests.java index ca18d12939a7e..5246a55056dbd 100644 --- a/x-pack/plugin/identity-provider/src/test/java/org/elasticsearch/xpack/idp/action/TransportSamlInitiateSingleSignOnActionTests.java +++ b/x-pack/plugin/identity-provider/src/test/java/org/elasticsearch/xpack/idp/action/TransportSamlInitiateSingleSignOnActionTests.java @@ -6,6 +6,7 @@ */ package org.elasticsearch.xpack.idp.action; +import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.PlainActionFuture; @@ -19,6 +20,7 @@ import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.security.SecurityContext; import org.elasticsearch.xpack.core.security.authc.Authentication; +import org.elasticsearch.xpack.core.security.authc.AuthenticationField; import org.elasticsearch.xpack.core.security.authc.support.SecondaryAuthentication; import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.idp.privileges.ServiceProviderPrivileges; @@ -40,6 +42,7 @@ import java.time.Duration; import java.util.Collections; import java.util.HashMap; +import java.util.Map; import java.util.Set; import static org.hamcrest.CoreMatchers.containsString; @@ -162,7 +165,10 @@ private TransportSamlInitiateSingleSignOnAction setupTransportAction(boolean wit true ), new Authentication.RealmRef("_es_api_key", "_es_api_key", "node_name"), - new Authentication.RealmRef("_es_api_key", "_es_api_key", "node_name") + new Authentication.RealmRef("_es_api_key", "_es_api_key", "node_name"), + Version.CURRENT, + Authentication.AuthenticationType.API_KEY, + Map.of(AuthenticationField.API_KEY_ID_KEY, randomAlphaOfLength(20)) ) ).writeToContext(threadContext); } 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 2ba3035e4993e..7397210b6b94d 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 @@ -52,6 +52,9 @@ import org.elasticsearch.xpack.core.security.action.apikey.InvalidateApiKeyAction; import org.elasticsearch.xpack.core.security.action.apikey.InvalidateApiKeyRequest; import org.elasticsearch.xpack.core.security.action.apikey.InvalidateApiKeyResponse; +import org.elasticsearch.xpack.core.security.action.token.CreateTokenAction; +import org.elasticsearch.xpack.core.security.action.token.CreateTokenRequestBuilder; +import org.elasticsearch.xpack.core.security.action.token.CreateTokenResponse; import org.elasticsearch.xpack.core.security.action.user.PutUserAction; import org.elasticsearch.xpack.core.security.action.user.PutUserRequest; import org.elasticsearch.xpack.core.security.action.user.PutUserResponse; @@ -109,6 +112,7 @@ public Settings nodeSettings(int nodeOrdinal, Settings otherSettings) { return Settings.builder() .put(super.nodeSettings(nodeOrdinal, otherSettings)) .put(XPackSettings.API_KEY_SERVICE_ENABLED_SETTING.getKey(), true) + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true) .put(ApiKeyService.DELETE_INTERVAL.getKey(), TimeValue.timeValueMillis(DELETE_INTERVAL_MILLIS)) .put(ApiKeyService.DELETE_TIMEOUT.getKey(), TimeValue.timeValueSeconds(5L)) .put("xpack.security.crypto.thread_pool.queue_size", CRYPTO_THREAD_POOL_QUEUE_SIZE) @@ -1111,7 +1115,9 @@ public void testDerivedKeys() throws ExecutionException, InterruptedException { Collections.singletonMap("Authorization", basicAuthHeaderValue(ES_TEST_ROOT_USER, TEST_PASSWORD_SECURE_STRING)) ); final CreateApiKeyResponse response = new CreateApiKeyRequestBuilder(client).setName("key-1") - .setRoleDescriptors(Collections.singletonList(new RoleDescriptor("role", new String[] { "manage_api_key" }, null, null))) + .setRoleDescriptors( + Collections.singletonList(new RoleDescriptor("role", new String[] { "manage_api_key", "manage_token" }, null, null)) + ) .setMetadata(ApiKeyTests.randomMetadata()) .get(); @@ -1122,7 +1128,17 @@ public void testDerivedKeys() throws ExecutionException, InterruptedException { // use the first ApiKey for authorized action final String base64ApiKeyKeyValue = Base64.getEncoder() .encodeToString((response.getId() + ":" + response.getKey().toString()).getBytes(StandardCharsets.UTF_8)); - final Client clientKey1 = client().filterWithHeader(Collections.singletonMap("Authorization", "ApiKey " + base64ApiKeyKeyValue)); + + final Client clientKey1; + if (randomBoolean()) { + clientKey1 = client().filterWithHeader(Collections.singletonMap("Authorization", "ApiKey " + base64ApiKeyKeyValue)); + } else { + final CreateTokenResponse createTokenResponse = new CreateTokenRequestBuilder( + client().filterWithHeader(Collections.singletonMap("Authorization", "ApiKey " + base64ApiKeyKeyValue)), + CreateTokenAction.INSTANCE + ).setGrantType("client_credentials").get(); + clientKey1 = client().filterWithHeader(Map.of("Authorization", "Bearer " + createTokenResponse.getTokenString())); + } final String expectedMessage = "creating derived api keys requires an explicit role descriptor that is empty"; diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java index 55fe797c27090..35b7645b5a4aa 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java @@ -157,7 +157,7 @@ public void testRunAsUsingApiKey() throws IOException { createApiKeyResponse.getEntity().getContent() ); - final boolean runAsTestUser = false; + final boolean runAsTestUser = randomBoolean(); final Request authenticateRequest = new Request("GET", "/_security/_authenticate"); authenticateRequest.setOptions( @@ -194,6 +194,32 @@ public void testRunAsUsingApiKey() throws IOException { final ResponseException e = expectThrows(ResponseException.class, () -> getRestClient().performRequest(getUserRequest)); assertThat(e.getResponse().getStatusLine().getStatusCode(), equalTo(403)); } + + // Run-as ignored if using a token created by the API key + final Request createTokenRequest = new Request("POST", "/_security/oauth2/token"); + createTokenRequest.setOptions( + createTokenRequest.getOptions().toBuilder().addHeader("Authorization", "ApiKey " + apiKeyMapView.get("encoded")) + ); + createTokenRequest.setJsonEntity("{\"grant_type\":\"client_credentials\"}"); + final Response createTokenResponse = getRestClient().performRequest(createTokenRequest); + final XContentTestUtils.JsonMapView createTokenJsonView = XContentTestUtils.createJsonMapView( + createTokenResponse.getEntity().getContent() + ); + + authenticateRequest.setOptions( + RequestOptions.DEFAULT.toBuilder() + .addHeader("Authorization", "Bearer " + createTokenJsonView.get("access_token")) + .addHeader( + AuthenticationServiceField.RUN_AS_USER_HEADER, + runAsTestUser ? SecuritySettingsSource.TEST_USER_NAME : NO_ROLE_USER + ) + ); + final Response authenticateResponse2 = getRestClient().performRequest(authenticateRequest); + final XContentTestUtils.JsonMapView authenticateJsonView2 = XContentTestUtils.createJsonMapView( + authenticateResponse2.getEntity().getContent() + ); + // run-as header is ignored, the user is still the run_as_user + assertThat(authenticateJsonView2.get("username"), equalTo(RUN_AS_USER)); } public void testRunAsIgnoredForOAuthToken() throws IOException { diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java index 609a8d96d08f2..2634590b77084 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java @@ -15,6 +15,7 @@ import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.main.MainAction; import org.elasticsearch.action.main.MainRequest; +import org.elasticsearch.client.internal.Client; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; @@ -27,6 +28,9 @@ import org.elasticsearch.xpack.core.security.action.apikey.CreateApiKeyAction; import org.elasticsearch.xpack.core.security.action.apikey.CreateApiKeyRequest; import org.elasticsearch.xpack.core.security.action.apikey.CreateApiKeyResponse; +import org.elasticsearch.xpack.core.security.action.apikey.GetApiKeyAction; +import org.elasticsearch.xpack.core.security.action.apikey.GetApiKeyRequest; +import org.elasticsearch.xpack.core.security.action.apikey.GetApiKeyResponse; import org.elasticsearch.xpack.core.security.action.apikey.GrantApiKeyAction; import org.elasticsearch.xpack.core.security.action.apikey.GrantApiKeyRequest; import org.elasticsearch.xpack.core.security.action.apikey.QueryApiKeyAction; @@ -35,6 +39,9 @@ import org.elasticsearch.xpack.core.security.action.service.CreateServiceAccountTokenAction; import org.elasticsearch.xpack.core.security.action.service.CreateServiceAccountTokenRequest; import org.elasticsearch.xpack.core.security.action.service.CreateServiceAccountTokenResponse; +import org.elasticsearch.xpack.core.security.action.token.CreateTokenAction; +import org.elasticsearch.xpack.core.security.action.token.CreateTokenRequestBuilder; +import org.elasticsearch.xpack.core.security.action.token.CreateTokenResponse; import org.elasticsearch.xpack.core.security.action.user.PutUserAction; import org.elasticsearch.xpack.core.security.action.user.PutUserRequest; import org.elasticsearch.xpack.core.security.authc.support.Hasher; @@ -45,6 +52,7 @@ import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.Base64; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -60,6 +68,7 @@ public class ApiKeySingleNodeTests extends SecuritySingleNodeTestCase { protected Settings nodeSettings() { Settings.Builder builder = Settings.builder().put(super.nodeSettings()); builder.put(XPackSettings.API_KEY_SERVICE_ENABLED_SETTING.getKey(), true); + builder.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true); return builder.build(); } @@ -185,6 +194,50 @@ public void testServiceAccountApiKey() throws IOException { assertThat(roleDescriptor, equalTo(ServiceAccountService.getServiceAccounts().get("elastic/fleet-server").roleDescriptor())); } + public void testGetApiKeyWorksForTheApiKeyItself() { + final String apiKeyName = randomAlphaOfLength(10); + final CreateApiKeyResponse createApiKeyResponse = client().execute( + CreateApiKeyAction.INSTANCE, + new CreateApiKeyRequest( + apiKeyName, + List.of(new RoleDescriptor("x", new String[] { "manage_own_api_key", "manage_token" }, null, null, null, null, null, null)), + null, + null + ) + ).actionGet(); + + final String apiKeyId = createApiKeyResponse.getId(); + final String base64ApiKeyKeyValue = Base64.getEncoder() + .encodeToString((apiKeyId + ":" + createApiKeyResponse.getKey().toString()).getBytes(StandardCharsets.UTF_8)); + + // Works for both the API key itself or the token created by it + final Client clientKey1; + if (randomBoolean()) { + clientKey1 = client().filterWithHeader(Collections.singletonMap("Authorization", "ApiKey " + base64ApiKeyKeyValue)); + } else { + final CreateTokenResponse createTokenResponse = new CreateTokenRequestBuilder( + client().filterWithHeader(Collections.singletonMap("Authorization", "ApiKey " + base64ApiKeyKeyValue)), + CreateTokenAction.INSTANCE + ).setGrantType("client_credentials").get(); + clientKey1 = client().filterWithHeader(Map.of("Authorization", "Bearer " + createTokenResponse.getTokenString())); + } + + // Can get its own info + final GetApiKeyResponse getApiKeyResponse = clientKey1.execute( + GetApiKeyAction.INSTANCE, + GetApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()) + ).actionGet(); + assertThat(getApiKeyResponse.getApiKeyInfos().length, equalTo(1)); + assertThat(getApiKeyResponse.getApiKeyInfos()[0].getId(), equalTo(apiKeyId)); + + // Cannot get any other keys + final ElasticsearchSecurityException e = expectThrows( + ElasticsearchSecurityException.class, + () -> clientKey1.execute(GetApiKeyAction.INSTANCE, GetApiKeyRequest.forAllApiKeys()).actionGet() + ); + assertThat(e.getMessage(), containsString("unauthorized for API key id [" + apiKeyId + "]")); + } + private Map getApiKeyDocument(String apiKeyId) { final GetResponse getResponse = client().execute(GetAction.INSTANCE, new GetRequest(".security-7", apiKeyId)).actionGet(); return getResponse.getSource(); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java index 23e87db5c2d25..434389bd729ef 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java @@ -1371,10 +1371,12 @@ public static String getCreatorRealmType(final Authentication authentication) { * @return A map for the metadata or an empty map if no metadata is found. */ public static Map getApiKeyMetadata(Authentication authentication) { - if (false == authentication.isAuthenticatedWithApiKey()) { + if (false == authentication.isAuthenticatedAsApiKey()) { throw new IllegalArgumentException( - "authentication type must be [api_key], got [" - + authentication.getAuthenticationType().name().toLowerCase(Locale.ROOT) + "authentication realm must be [" + + AuthenticationField.API_KEY_REALM_TYPE + + "], got [" + + authentication.getAuthenticatedBy().getType() + "]" ); } 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 6bf84a7884d6f..72484ff5e32b4 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 @@ -879,7 +879,7 @@ private ElasticsearchSecurityException denialException( userText = userText + " run as [" + authentication.getUser().principal() + "]"; } // check for authentication by API key - if (authentication.isAuthenticatedWithApiKey()) { + if (authentication.isAuthenticatedAsApiKey()) { final String apiKeyId = (String) authentication.getMetadata().get(AuthenticationField.API_KEY_ID_KEY); assert apiKeyId != null : "api key id must be present in the metadata"; userText = "API key id [" + apiKeyId + "] of " + userText; diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java index af6cdd19209c9..479bfb2cb4c77 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java @@ -1234,7 +1234,7 @@ public void testGetCreatorRealm() { assertThat(ApiKeyService.getCreatorRealmName(authentication2), equalTo(lookupRealmRef.getName())); assertThat(ApiKeyService.getCreatorRealmType(authentication2), equalTo(lookupRealmRef.getType())); - // Realm run-as + // Realm final Authentication authentication3 = AuthenticationTests.randomRealmAuthentication(); assertThat(ApiKeyService.getCreatorRealmName(authentication3), equalTo(authentication3.getSourceRealm().getName())); assertThat(ApiKeyService.getCreatorRealmType(authentication3), equalTo(authentication3.getSourceRealm().getType())); @@ -1464,7 +1464,10 @@ public void testApiKeyDocDeserializationWithNullValues() throws IOException { public void testGetApiKeyMetadata() throws IOException { final Authentication apiKeyAuthentication = mock(Authentication.class); when(apiKeyAuthentication.getAuthenticationType()).thenReturn(AuthenticationType.API_KEY); - when(apiKeyAuthentication.isAuthenticatedWithApiKey()).thenCallRealMethod(); + when(apiKeyAuthentication.getAuthenticatedBy()).thenReturn( + new RealmRef(AuthenticationField.API_KEY_REALM_NAME, AuthenticationField.API_KEY_REALM_TYPE, randomAlphaOfLengthBetween(3, 8)) + ); + when(apiKeyAuthentication.isAuthenticatedAsApiKey()).thenCallRealMethod(); final Map apiKeyMetadata = ApiKeyTests.randomMetadata(); if (apiKeyMetadata == null) { when(apiKeyAuthentication.getMetadata()).thenReturn(Map.of()); @@ -1481,14 +1484,14 @@ public void testGetApiKeyMetadata() throws IOException { } final Authentication authentication = mock(Authentication.class); - when(authentication.getAuthenticationType()).thenReturn( - randomValueOtherThan(AuthenticationType.API_KEY, () -> randomFrom(AuthenticationType.values())) + when(authentication.getAuthenticatedBy()).thenReturn( + new RealmRef(randomAlphaOfLengthBetween(5, 10), randomAlphaOfLengthBetween(5, 10), randomAlphaOfLengthBetween(3, 8)) ); final IllegalArgumentException e = expectThrows( IllegalArgumentException.class, () -> ApiKeyService.getApiKeyMetadata(authentication) ); - assertThat(e.getMessage(), containsString("authentication type must be [api_key]")); + assertThat(e.getMessage(), containsString("authentication realm must be [_es_api_key]")); } public static class Utils { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java index 0aa5aeabb8d36..82cc0ec14cc40 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java @@ -336,11 +336,14 @@ public void testSameUserPermissionAllowsSelfApiKeyInfoRetrievalWhenAuthenticated final TransportRequest request = GetApiKeyRequest.usingApiKeyId(apiKeyId, false); final Authentication authentication = mock(Authentication.class); final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class); + when(authenticatedBy.getName()).thenReturn(AuthenticationField.API_KEY_REALM_NAME); + when(authenticatedBy.getType()).thenReturn(AuthenticationField.API_KEY_REALM_TYPE); when(authentication.getUser()).thenReturn(user); when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy); when(authentication.getAuthenticationType()).thenReturn(AuthenticationType.API_KEY); + when(authentication.getSourceRealm()).thenReturn(authenticatedBy); when(authentication.getMetadata()).thenReturn(Map.of(AuthenticationField.API_KEY_ID_KEY, apiKeyId)); - when(authentication.isAuthenticatedWithApiKey()).thenCallRealMethod(); + when(authentication.isAuthenticatedAsApiKey()).thenCallRealMethod(); when(authentication.isApiKey()).thenCallRealMethod(); assertTrue(engine.checkSameUserPermissions(GetApiKeyAction.NAME, request, authentication)); @@ -354,9 +357,11 @@ public void testSameUserPermissionDeniesApiKeyInfoRetrievalWhenAuthenticatedByAD final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class); when(authentication.getUser()).thenReturn(user); when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy); + when(authenticatedBy.getName()).thenReturn(AuthenticationField.API_KEY_REALM_NAME); when(authenticatedBy.getType()).thenReturn(AuthenticationField.API_KEY_REALM_TYPE); + when(authentication.getSourceRealm()).thenReturn(authenticatedBy); when(authentication.getMetadata()).thenReturn(Map.of(AuthenticationField.API_KEY_ID_KEY, randomAlphaOfLengthBetween(4, 7))); - when(authentication.isAuthenticatedWithApiKey()).thenCallRealMethod(); + when(authentication.isAuthenticatedAsApiKey()).thenCallRealMethod(); when(authentication.isApiKey()).thenCallRealMethod(); assertFalse(engine.checkSameUserPermissions(GetApiKeyAction.NAME, request, authentication)); @@ -371,10 +376,15 @@ public void testSameUserPermissionDeniesApiKeyInfoRetrievalWhenLookedupByIsPrese final Authentication.RealmRef lookedupBy = mock(Authentication.RealmRef.class); when(authentication.getUser()).thenReturn(user); when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy); + when(authenticatedBy.getName()).thenReturn(AuthenticationField.API_KEY_REALM_NAME); + when(authenticatedBy.getType()).thenReturn(AuthenticationField.API_KEY_REALM_TYPE); when(authentication.getLookedUpBy()).thenReturn(lookedupBy); + when(lookedupBy.getName()).thenReturn("name"); + when(lookedupBy.getType()).thenReturn("type"); + when(authentication.getSourceRealm()).thenReturn(lookedupBy); when(authentication.getAuthenticationType()).thenReturn(AuthenticationType.API_KEY); when(authentication.getMetadata()).thenReturn(Map.of(AuthenticationField.API_KEY_ID_KEY, randomAlphaOfLengthBetween(4, 7))); - when(authentication.isAuthenticatedWithApiKey()).thenCallRealMethod(); + when(authentication.isAuthenticatedAsApiKey()).thenCallRealMethod(); when(authentication.isApiKey()).thenCallRealMethod(); assertFalse(engine.checkSameUserPermissions(GetApiKeyAction.NAME, request, authentication));