diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityExtension.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityExtension.java index f41b19de95272..449246fbb5c92 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityExtension.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityExtension.java @@ -16,7 +16,7 @@ import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.core.security.authc.AuthenticationFailureHandler; import org.elasticsearch.xpack.core.security.authc.Realm; -import org.elasticsearch.xpack.core.security.authc.apikey.CustomApiKeyAuthenticator; +import org.elasticsearch.xpack.core.security.authc.apikey.CustomAuthenticator; import org.elasticsearch.xpack.core.security.authc.service.NodeLocalServiceAccountTokenStore; import org.elasticsearch.xpack.core.security.authc.service.ServiceAccountTokenStore; import org.elasticsearch.xpack.core.security.authc.support.UserRoleMapper; @@ -129,7 +129,7 @@ default ServiceAccountTokenStore getServiceAccountTokenStore(SecurityComponents return null; } - default CustomApiKeyAuthenticator getCustomApiKeyAuthenticator(SecurityComponents components) { + default List getCustomAuthenticators(SecurityComponents components) { return null; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/apikey/CustomApiKeyAuthenticator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/apikey/CustomApiKeyAuthenticator.java deleted file mode 100644 index 4f5d05e720715..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/apikey/CustomApiKeyAuthenticator.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -package org.elasticsearch.xpack.core.security.authc.apikey; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.settings.SecureString; -import org.elasticsearch.core.Nullable; -import org.elasticsearch.xpack.core.security.authc.Authentication; -import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; -import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; - -/** - * An extension point to provide a custom API key authenticator implementation. - * The implementation is wrapped by a core `Authenticator` class and included in the authenticator chain _before_ the - * default API key authenticator. - */ -public interface CustomApiKeyAuthenticator { - String name(); - - AuthenticationToken extractCredentials(@Nullable SecureString apiKeyCredentials); - - void authenticate(@Nullable AuthenticationToken authenticationToken, ActionListener> listener); - - /** - * A no-op implementation of {@link CustomApiKeyAuthenticator} that is effectively skipped in the authenticator chain. - */ - class Noop implements CustomApiKeyAuthenticator { - @Override - public String name() { - return "noop"; - } - - @Override - public AuthenticationToken extractCredentials(@Nullable SecureString apiKeyCredentials) { - return null; - } - - @Override - public void authenticate( - @Nullable AuthenticationToken authenticationToken, - ActionListener> listener - ) { - listener.onResponse(AuthenticationResult.notHandled()); - } - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/apikey/CustomAuthenticator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/apikey/CustomAuthenticator.java new file mode 100644 index 0000000000000..5415714bb3114 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/apikey/CustomAuthenticator.java @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.core.security.authc.apikey; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.core.Nullable; +import org.elasticsearch.xpack.core.security.authc.Authentication; +import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; +import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; + +/** + * An extension point to provide a custom authenticator implementation. For example, a custom API key or a custom OAuth2 + * token implementation. The implementation is wrapped by a core `Authenticator` class and included in the authenticator chain + * _before_ the respective "standard" authenticator(s). + */ +public interface CustomAuthenticator { + + boolean supports(AuthenticationToken token); + + @Nullable + AuthenticationToken extractToken(ThreadContext context); + + void authenticate(@Nullable AuthenticationToken token, ActionListener> listener); + +} diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index 5fe15a857951a..73b3339a48b2c 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -201,7 +201,7 @@ import org.elasticsearch.xpack.core.security.authc.RealmConfig; import org.elasticsearch.xpack.core.security.authc.RealmSettings; import org.elasticsearch.xpack.core.security.authc.Subject; -import org.elasticsearch.xpack.core.security.authc.apikey.CustomApiKeyAuthenticator; +import org.elasticsearch.xpack.core.security.authc.apikey.CustomAuthenticator; import org.elasticsearch.xpack.core.security.authc.service.NodeLocalServiceAccountTokenStore; import org.elasticsearch.xpack.core.security.authc.service.ServiceAccountTokenStore; import org.elasticsearch.xpack.core.security.authc.support.UserRoleMapper; @@ -1079,9 +1079,7 @@ Collection createComponents( operatorPrivilegesService.set(OperatorPrivileges.NOOP_OPERATOR_PRIVILEGES_SERVICE); } - final CustomApiKeyAuthenticator customApiKeyAuthenticator = createCustomApiKeyAuthenticator(extensionComponents); - - components.add(customApiKeyAuthenticator); + final List customAuthenticators = getCustomAuthenticatorFromExtensions(extensionComponents); authcService.set( new AuthenticationService( @@ -1095,7 +1093,7 @@ Collection createComponents( apiKeyService, serviceAccountService, operatorPrivilegesService.get(), - customApiKeyAuthenticator, + customAuthenticators, telemetryProvider.getMeterRegistry() ) ); @@ -1231,45 +1229,48 @@ Collection createComponents( return components; } - private CustomApiKeyAuthenticator createCustomApiKeyAuthenticator(SecurityExtension.SecurityComponents extensionComponents) { - final Map customApiKeyAuthenticatorByExtension = new HashMap<>(); - for (final SecurityExtension extension : securityExtensions) { - final CustomApiKeyAuthenticator customApiKeyAuthenticator = extension.getCustomApiKeyAuthenticator(extensionComponents); - if (customApiKeyAuthenticator != null) { - if (false == isInternalExtension(extension)) { + private List getCustomAuthenticatorFromExtensions(SecurityExtension.SecurityComponents extensionComponents) { + final Map> customAuthenticatorsByExtension = new HashMap<>(); + for (final SecurityExtension securityExtension : securityExtensions) { + final List customAuthenticators = securityExtension.getCustomAuthenticators(extensionComponents); + if (customAuthenticators != null) { + if (false == isInternalExtension(securityExtension)) { throw new IllegalStateException( "The [" - + extension.extensionName() - + "] extension tried to install a custom CustomApiKeyAuthenticator. " + + securityExtension.extensionName() + + "] extension tried to install a " + + CustomAuthenticator.class.getSimpleName() + + ". " + "This functionality is not available to external extensions." ); } - customApiKeyAuthenticatorByExtension.put(extension.extensionName(), customApiKeyAuthenticator); + customAuthenticatorsByExtension.put(securityExtension.extensionName(), customAuthenticators); } } - if (customApiKeyAuthenticatorByExtension.isEmpty()) { + if (customAuthenticatorsByExtension.isEmpty()) { logger.debug( - "No custom implementation for [{}]. Falling-back to noop implementation.", - CustomApiKeyAuthenticator.class.getCanonicalName() + "No custom implementations for [{}] provided by security extensions.", + CustomAuthenticator.class.getCanonicalName() ); - return new CustomApiKeyAuthenticator.Noop(); - - } else if (customApiKeyAuthenticatorByExtension.size() > 1) { + return List.of(); + } else if (customAuthenticatorsByExtension.size() > 1) { throw new IllegalStateException( - "Multiple extensions tried to install a custom CustomApiKeyAuthenticator: " + customApiKeyAuthenticatorByExtension.keySet() + "Multiple extensions tried to install custom authenticators: " + customAuthenticatorsByExtension.keySet() ); - } else { - final var authenticatorByExtensionEntry = customApiKeyAuthenticatorByExtension.entrySet().iterator().next(); - final CustomApiKeyAuthenticator customApiKeyAuthenticator = authenticatorByExtensionEntry.getValue(); + final var authenticatorByExtensionEntry = customAuthenticatorsByExtension.entrySet().iterator().next(); + final List customAuthenticators = authenticatorByExtensionEntry.getValue(); final String extensionName = authenticatorByExtensionEntry.getKey(); - logger.debug( - "CustomApiKeyAuthenticator implementation [{}] provided by extension [{}]", - customApiKeyAuthenticator.getClass().getCanonicalName(), - extensionName - ); - return customApiKeyAuthenticator; + for (CustomAuthenticator authenticator : customAuthenticators) { + logger.debug( + "{} implementation [{}] provided by extension [{}]", + CustomAuthenticator.class.getSimpleName(), + authenticator.getClass().getCanonicalName(), + extensionName + ); + } + return customAuthenticators; } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java index a9c513a605fe8..5fb930ceb3324 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java @@ -30,7 +30,7 @@ import org.elasticsearch.xpack.core.security.authc.AuthenticationServiceField; import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; import org.elasticsearch.xpack.core.security.authc.Realm; -import org.elasticsearch.xpack.core.security.authc.apikey.CustomApiKeyAuthenticator; +import org.elasticsearch.xpack.core.security.authc.apikey.CustomAuthenticator; import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer; import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.EmptyAuthorizationInfo; import org.elasticsearch.xpack.core.security.user.AnonymousUser; @@ -93,7 +93,7 @@ public AuthenticationService( ApiKeyService apiKeyService, ServiceAccountService serviceAccountService, OperatorPrivilegesService operatorPrivilegesService, - CustomApiKeyAuthenticator customApiKeyAuthenticator, + List customAuthenticators, MeterRegistry meterRegistry ) { this.realms = realms; @@ -110,14 +110,15 @@ public AuthenticationService( } final String nodeName = Node.NODE_NAME_SETTING.get(settings); + this.authenticatorChain = new AuthenticatorChain( settings, operatorPrivilegesService, anonymousUser, new AuthenticationContextSerializer(), + new PluggableAuthenticatorChain(customAuthenticators), new ServiceAccountAuthenticator(serviceAccountService, nodeName, meterRegistry), new OAuth2TokenAuthenticator(tokenService, meterRegistry), - new PluggableApiKeyAuthenticator(customApiKeyAuthenticator), new ApiKeyAuthenticator(apiKeyService, nodeName, meterRegistry), new RealmsAuthenticator(numInvalidation, lastSuccessfulAuthCache, meterRegistry) ); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Authenticator.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Authenticator.java index ed218c3eba58d..6433cfacc77bb 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Authenticator.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Authenticator.java @@ -37,7 +37,7 @@ public interface Authenticator { /** * Attempt to Extract an {@link AuthenticationToken} from the given {@link Context}. * @param context The context object encapsulating current request and other information relevant for authentication. - * + * @return An {@link AuthenticationToken} if one can be extracted or null if this Authenticator cannot * extract one. */ diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticatorChain.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticatorChain.java index f3532dc4c6270..a87225c9f7682 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticatorChain.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticatorChain.java @@ -26,6 +26,8 @@ import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.security.operator.OperatorPrivileges.OperatorPrivilegesService; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; @@ -52,9 +54,9 @@ class AuthenticatorChain { OperatorPrivilegesService operatorPrivilegesService, AnonymousUser anonymousUser, AuthenticationContextSerializer authenticationSerializer, + PluggableAuthenticatorChain pluggableAuthenticatorChain, ServiceAccountAuthenticator serviceAccountAuthenticator, OAuth2TokenAuthenticator oAuth2TokenAuthenticator, - PluggableApiKeyAuthenticator pluggableApiKeyAuthenticator, ApiKeyAuthenticator apiKeyAuthenticator, RealmsAuthenticator realmsAuthenticator ) { @@ -65,13 +67,16 @@ class AuthenticatorChain { this.isAnonymousUserEnabled = AnonymousUser.isAnonymousEnabled(settings); this.authenticationSerializer = authenticationSerializer; this.realmsAuthenticator = realmsAuthenticator; - this.allAuthenticators = List.of( - serviceAccountAuthenticator, - oAuth2TokenAuthenticator, - pluggableApiKeyAuthenticator, - apiKeyAuthenticator, - realmsAuthenticator - ); + + List authenticators = new ArrayList<>(); + if (pluggableAuthenticatorChain.hasCustomAuthenticators()) { + authenticators.add(pluggableAuthenticatorChain); + } + authenticators.add(serviceAccountAuthenticator); + authenticators.add(oAuth2TokenAuthenticator); + authenticators.add(apiKeyAuthenticator); + authenticators.add(realmsAuthenticator); + this.allAuthenticators = Collections.unmodifiableList(authenticators); } void authenticate(Authenticator.Context context, ActionListener originalListener) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/PluggableApiKeyAuthenticator.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/PluggableApiKeyAuthenticator.java deleted file mode 100644 index 0637efbc5e89a..0000000000000 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/PluggableApiKeyAuthenticator.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -package org.elasticsearch.xpack.security.authc; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.xpack.core.security.authc.Authentication; -import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; -import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; -import org.elasticsearch.xpack.core.security.authc.apikey.CustomApiKeyAuthenticator; - -/** - * An adapter for {@link CustomApiKeyAuthenticator} that implements the {@link Authenticator} interface, so the custom API key authenticator - * can be plugged into the authenticator chain. Module dependencies prevent us from introducing a direct extension point for - * an {@link Authenticator}. - */ -public class PluggableApiKeyAuthenticator implements Authenticator { - private final CustomApiKeyAuthenticator authenticator; - - public PluggableApiKeyAuthenticator(CustomApiKeyAuthenticator authenticator) { - this.authenticator = authenticator; - } - - @Override - public String name() { - return authenticator.name(); - } - - @Override - public AuthenticationToken extractCredentials(Context context) { - return authenticator.extractCredentials(context.getApiKeyString()); - } - - @Override - public void authenticate(Context context, ActionListener> listener) { - final AuthenticationToken authenticationToken = context.getMostRecentAuthenticationToken(); - authenticator.authenticate(authenticationToken, ActionListener.wrap(response -> { - if (response.isAuthenticated()) { - listener.onResponse(response); - } else if (response.getStatus() == AuthenticationResult.Status.TERMINATE) { - final Exception ex = response.getException(); - if (ex == null) { - listener.onFailure(context.getRequest().authenticationFailed(authenticationToken)); - } else { - listener.onFailure(context.getRequest().exceptionProcessingRequest(ex, authenticationToken)); - } - } else if (response.getStatus() == AuthenticationResult.Status.CONTINUE) { - listener.onResponse(AuthenticationResult.notHandled()); - } - }, ex -> listener.onFailure(context.getRequest().exceptionProcessingRequest(ex, authenticationToken)))); - } -} diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/PluggableAuthenticatorChain.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/PluggableAuthenticatorChain.java new file mode 100644 index 0000000000000..9780b4ae43f93 --- /dev/null +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/PluggableAuthenticatorChain.java @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.security.authc; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.xpack.core.security.authc.Authentication; +import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; +import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; +import org.elasticsearch.xpack.core.security.authc.apikey.CustomAuthenticator; + +import java.util.List; + +public class PluggableAuthenticatorChain implements Authenticator { + + public static final PluggableAuthenticatorChain EMPTY = new PluggableAuthenticatorChain(List.of()); + + private final List customAuthenticators; + + public PluggableAuthenticatorChain(List customAuthenticators) { + this.customAuthenticators = customAuthenticators; + } + + @Override + public String name() { + return "pluggable custom authenticator chain"; + } + + public boolean hasCustomAuthenticators() { + return customAuthenticators.size() > 0; + } + + @Override + public AuthenticationToken extractCredentials(Context context) { + if (false == hasCustomAuthenticators()) { + return null; + } + for (CustomAuthenticator customAuthenticator : customAuthenticators) { + AuthenticationToken token = customAuthenticator.extractToken(context.getThreadContext()); + if (token != null) { + return token; + } + } + return null; + } + + @Override + public void authenticate(Context context, ActionListener> listener) { + if (false == hasCustomAuthenticators()) { + listener.onResponse(AuthenticationResult.notHandled()); + return; + } + AuthenticationToken token = context.getMostRecentAuthenticationToken(); + if (token != null) { + for (CustomAuthenticator customAuthenticator : customAuthenticators) { + if (customAuthenticator.supports(token)) { + customAuthenticator.authenticate(token, ActionListener.wrap(response -> { + if (response.isAuthenticated()) { + listener.onResponse(response); + } else if (response.getStatus() == AuthenticationResult.Status.TERMINATE) { + final Exception ex = response.getException(); + if (ex == null) { + listener.onFailure(context.getRequest().authenticationFailed(token)); + } else { + listener.onFailure(context.getRequest().exceptionProcessingRequest(ex, token)); + } + } else if (response.getStatus() == AuthenticationResult.Status.CONTINUE) { + listener.onResponse(AuthenticationResult.notHandled()); + } + }, ex -> listener.onFailure(context.getRequest().exceptionProcessingRequest(ex, token)))); + return; + } + } + } + listener.onResponse(AuthenticationResult.notHandled()); + } + +} diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticatorChainTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticatorChainTests.java index bfd122655768b..ce5ca298a9d75 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticatorChainTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticatorChainTests.java @@ -67,7 +67,6 @@ public class AuthenticatorChainTests extends ESTestCase { private ServiceAccountAuthenticator serviceAccountAuthenticator; private OAuth2TokenAuthenticator oAuth2TokenAuthenticator; private ApiKeyAuthenticator apiKeyAuthenticator; - private PluggableApiKeyAuthenticator pluggableApiKeyAuthenticator; private RealmsAuthenticator realmsAuthenticator; private Authentication authentication; private User fallbackUser; @@ -92,7 +91,8 @@ public void init() { oAuth2TokenAuthenticator = mock(OAuth2TokenAuthenticator.class); apiKeyAuthenticator = mock(ApiKeyAuthenticator.class); realmsAuthenticator = mock(RealmsAuthenticator.class); - pluggableApiKeyAuthenticator = mock(PluggableApiKeyAuthenticator.class); + PluggableAuthenticatorChain pluggableAuthenticatorChain = PluggableAuthenticatorChain.EMPTY; + when(realms.getActiveRealms()).thenReturn(List.of(mock(Realm.class))); when(realms.getUnlicensedRealms()).thenReturn(List.of()); final User user = new User(randomAlphaOfLength(8)); @@ -103,9 +103,9 @@ public void init() { operatorPrivilegesService, anonymousUser, authenticationContextSerializer, + pluggableAuthenticatorChain, serviceAccountAuthenticator, oAuth2TokenAuthenticator, - pluggableApiKeyAuthenticator, apiKeyAuthenticator, realmsAuthenticator ); @@ -220,13 +220,6 @@ public void testAuthenticateWithApiKey() throws IOException { new ApiKeyCredentials(randomAlphaOfLength(20), apiKeySecret, randomFrom(ApiKey.Type.values())) ); doCallRealMethod().when(serviceAccountAuthenticator).authenticate(eq(context), anyActionListener()); - doAnswer(invocationOnMock -> { - @SuppressWarnings("unchecked") - final ActionListener> listener = (ActionListener< - AuthenticationResult>) invocationOnMock.getArguments()[1]; - listener.onResponse(AuthenticationResult.notHandled()); - return null; - }).when(pluggableApiKeyAuthenticator).authenticate(eq(context), any()); doCallRealMethod().when(oAuth2TokenAuthenticator).authenticate(eq(context), anyActionListener()); } doAnswer(invocationOnMock -> { @@ -269,13 +262,6 @@ public void testAuthenticateWithRealms() throws IOException { doCallRealMethod().when(serviceAccountAuthenticator).authenticate(eq(context), anyActionListener()); doCallRealMethod().when(oAuth2TokenAuthenticator).authenticate(eq(context), anyActionListener()); doCallRealMethod().when(apiKeyAuthenticator).authenticate(eq(context), anyActionListener()); - doAnswer(invocationOnMock -> { - @SuppressWarnings("unchecked") - final ActionListener> listener = (ActionListener< - AuthenticationResult>) invocationOnMock.getArguments()[1]; - listener.onResponse(AuthenticationResult.notHandled()); - return null; - }).when(pluggableApiKeyAuthenticator).authenticate(eq(context), any()); } doAnswer(invocationOnMock -> { @SuppressWarnings("unchecked") @@ -338,13 +324,6 @@ public void testContextWithDirectWrongTokenFailsAuthn() { doCallRealMethod().when(serviceAccountAuthenticator).authenticate(eq(context), anyActionListener()); doCallRealMethod().when(oAuth2TokenAuthenticator).authenticate(eq(context), anyActionListener()); doCallRealMethod().when(apiKeyAuthenticator).authenticate(eq(context), anyActionListener()); - doAnswer(invocationOnMock -> { - @SuppressWarnings("unchecked") - final ActionListener> listener = (ActionListener< - AuthenticationResult>) invocationOnMock.getArguments()[1]; - listener.onResponse(AuthenticationResult.notHandled()); - return null; - }).when(pluggableApiKeyAuthenticator).authenticate(eq(context), any()); // 1. realms do not consume the token doAnswer(invocationOnMock -> {