From 4d5b2881164e3948524b402cbb8b2966a06afa95 Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Fri, 21 Jan 2022 11:41:36 -0500 Subject: [PATCH] Polish token revocation Issue gh-490 --- ...uth2TokenRevocationEndpointConfigurer.java | 12 +- .../OAuth2TokenRevocationEndpointFilter.java | 45 ++++---- .../OAuth2TokenRevocationTests.java | 106 ++++++++---------- ...th2TokenRevocationEndpointFilterTests.java | 34 +++--- 4 files changed, 91 insertions(+), 106 deletions(-) diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationEndpointConfigurer.java b/oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationEndpointConfigurer.java index 2999bc06..5d593550 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationEndpointConfigurer.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationEndpointConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,11 +48,11 @@ import org.springframework.security.web.util.matcher.RequestMatcher; * @see OAuth2TokenRevocationEndpointFilter */ public final class OAuth2TokenRevocationEndpointConfigurer extends AbstractOAuth2Configurer { - private final List authenticationProviders = new LinkedList<>(); + private RequestMatcher requestMatcher; private AuthenticationConverter revocationRequestConverter; + private final List authenticationProviders = new LinkedList<>(); private AuthenticationSuccessHandler revocationResponseHandler; private AuthenticationFailureHandler errorResponseHandler; - private RequestMatcher requestMatcher; /** * Restrict for internal use only. @@ -130,13 +130,13 @@ public final class OAuth2TokenRevocationEndpointConfigurer extends AbstractOAuth new OAuth2TokenRevocationEndpointFilter( authenticationManager, providerSettings.getTokenRevocationEndpoint()); if (this.revocationRequestConverter != null) { - revocationEndpointFilter.setRevocationRequestConverter(this.revocationRequestConverter); + revocationEndpointFilter.setAuthenticationConverter(this.revocationRequestConverter); } if (this.revocationResponseHandler != null) { - revocationEndpointFilter.setRevocationResponseHandler(this.revocationResponseHandler); + revocationEndpointFilter.setAuthenticationSuccessHandler(this.revocationResponseHandler); } if (this.errorResponseHandler != null) { - revocationEndpointFilter.setErrorResponseHandler(this.errorResponseHandler); + revocationEndpointFilter.setAuthenticationFailureHandler(this.errorResponseHandler); } builder.addFilterAfter(postProcess(revocationEndpointFilter), FilterSecurityInterceptor.class); } diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenRevocationEndpointFilter.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenRevocationEndpointFilter.java index 01649997..7a9c4be9 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenRevocationEndpointFilter.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenRevocationEndpointFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,13 +66,12 @@ public final class OAuth2TokenRevocationEndpointFilter extends OncePerRequestFil private final AuthenticationManager authenticationManager; private final RequestMatcher tokenRevocationEndpointMatcher; - private AuthenticationConverter revocationRequestConverter = + private AuthenticationConverter authenticationConverter = new DefaultTokenRevocationAuthenticationConverter(); private final HttpMessageConverter errorHttpResponseConverter = new OAuth2ErrorHttpMessageConverter(); - - private AuthenticationSuccessHandler revocationResponseHandler = this::sendRevocationSuccessResponse; - private AuthenticationFailureHandler errorResponseHandler = this::sendErrorResponse; + private AuthenticationSuccessHandler authenticationSuccessHandler = this::sendRevocationSuccessResponse; + private AuthenticationFailureHandler authenticationFailureHandler = this::sendErrorResponse; /** * Constructs an {@code OAuth2TokenRevocationEndpointFilter} using the provided parameters. @@ -108,13 +107,13 @@ public final class OAuth2TokenRevocationEndpointFilter extends OncePerRequestFil } try { - Authentication tokenRevocationAuthentication = this.revocationRequestConverter.convert(request); - - Authentication authentication = this.authenticationManager.authenticate(tokenRevocationAuthentication); - this.revocationResponseHandler.onAuthenticationSuccess(request, response, authentication); + Authentication tokenRevocationAuthentication = this.authenticationConverter.convert(request); + Authentication tokenRevocationAuthenticationResult = + this.authenticationManager.authenticate(tokenRevocationAuthentication); + this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, tokenRevocationAuthenticationResult); } catch (OAuth2AuthenticationException ex) { SecurityContextHolder.clearContext(); - this.errorResponseHandler.onAuthenticationFailure(request, response, ex); + this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex); } } @@ -122,35 +121,35 @@ public final class OAuth2TokenRevocationEndpointFilter extends OncePerRequestFil * Sets the {@link AuthenticationConverter} used when attempting to extract a Revoke Token Request from {@link HttpServletRequest} * to an instance of {@link OAuth2TokenRevocationAuthenticationToken} used for authenticating the client. * - * @param revocationRequestConverter the {@link AuthenticationConverter} used when attempting to extract client credentials from {@link HttpServletRequest} + * @param authenticationConverter the {@link AuthenticationConverter} used when attempting to extract client credentials from {@link HttpServletRequest} * @since 0.2.2 */ - public void setRevocationRequestConverter(AuthenticationConverter revocationRequestConverter) { - Assert.notNull(revocationRequestConverter, "revocationRequestConverter cannot be null"); - this.revocationRequestConverter = revocationRequestConverter; + public void setAuthenticationConverter(AuthenticationConverter authenticationConverter) { + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); + this.authenticationConverter = authenticationConverter; } /** * Sets the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenRevocationAuthenticationToken}. * - * @param revocationResponseHandler the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenRevocationAuthenticationToken} + * @param authenticationSuccessHandler the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenRevocationAuthenticationToken} * @since 0.2.2 */ - public void setRevocationResponseHandler(AuthenticationSuccessHandler revocationResponseHandler) { - Assert.notNull(revocationResponseHandler, "revocationResponseHandler cannot be null"); - this.revocationResponseHandler = revocationResponseHandler; + public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler authenticationSuccessHandler) { + Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null"); + this.authenticationSuccessHandler = authenticationSuccessHandler; } /** * Sets the {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException} * and returning the {@link OAuth2Error Error Response}. * - * @param errorResponseHandler the {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException} + * @param authenticationFailureHandler the {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException} * @since 0.2.2 */ - public void setErrorResponseHandler(AuthenticationFailureHandler errorResponseHandler) { - Assert.notNull(errorResponseHandler, "errorResponseHandler cannot be null"); - this.errorResponseHandler = errorResponseHandler; + public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) { + Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null"); + this.authenticationFailureHandler = authenticationFailureHandler; } private void sendRevocationSuccessResponse(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { @@ -167,7 +166,7 @@ public final class OAuth2TokenRevocationEndpointFilter extends OncePerRequestFil private static void throwError(String errorCode, String parameterName) { OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Token Revocation Parameter: " + parameterName, - "https://tools.ietf.org/html/rfc7009#section-2.1"); + "https://datatracker.ietf.org/doc/html/rfc7009#section-2.1"); throw new OAuth2AuthenticationException(error); } diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java index 89ff1d3c..48822e3c 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,8 +31,6 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; import org.springframework.http.HttpHeaders; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcTemplate; @@ -66,7 +64,6 @@ import org.springframework.security.oauth2.server.authorization.client.JdbcRegis import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; -import org.springframework.security.oauth2.server.authorization.config.ProviderSettings; import org.springframework.security.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationConverter; @@ -81,8 +78,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -95,11 +92,11 @@ public class OAuth2TokenRevocationTests { private static final String DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI = "/oauth2/revoke"; private static EmbeddedDatabase db; private static JWKSource jwkSource; - private static ProviderSettings providerSettings; - private static AuthenticationConverter revocationRequestConverter; + private static AuthenticationConverter authenticationConverter; private static AuthenticationProvider authenticationProvider; - private static AuthenticationSuccessHandler revocationResponseHandler; - private static AuthenticationFailureHandler errorResponseHandler; + private static AuthenticationSuccessHandler authenticationSuccessHandler; + private static AuthenticationFailureHandler authenticationFailureHandler; + @Rule public final SpringTestRule spring = new SpringTestRule(); @@ -119,11 +116,10 @@ public class OAuth2TokenRevocationTests { public static void init() { JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); - providerSettings = ProviderSettings.builder().tokenRevocationEndpoint("/test/revoke").build(); - revocationRequestConverter = mock(AuthenticationConverter.class); + authenticationConverter = mock(AuthenticationConverter.class); authenticationProvider = mock(AuthenticationProvider.class); - revocationResponseHandler = mock(AuthenticationSuccessHandler.class); - errorResponseHandler = mock(AuthenticationFailureHandler.class); + authenticationSuccessHandler = mock(AuthenticationSuccessHandler.class); + authenticationFailureHandler = mock(AuthenticationFailureHandler.class); db = new EmbeddedDatabaseBuilder() .generateUniqueName(true) .setType(EmbeddedDatabaseType.HSQL) @@ -173,42 +169,6 @@ public class OAuth2TokenRevocationTests { public void requestWhenRevokeAccessTokenThenRevoked() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire(); - assertRevokeAccessTokenThenRevoked(DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI); - } - - @Test - public void requestWhenRevokeAccessTokenEndpointCustomizedThenUsed() throws Exception { - this.spring.register(AuthorizationServerConfigurationCustomEndpoints.class).autowire(); - - RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - this.registeredClientRepository.save(registeredClient); - Authentication clientPrincipal = new OAuth2ClientAuthenticationToken( - registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret()); - - OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); - OAuth2AccessToken token = authorization.getAccessToken().getToken(); - OAuth2TokenType tokenType = OAuth2TokenType.ACCESS_TOKEN; - this.authorizationService.save(authorization); - - OAuth2TokenRevocationAuthenticationToken tokenRevocationAuthenticationResult = - new OAuth2TokenRevocationAuthenticationToken(token, clientPrincipal); - - when(revocationRequestConverter.convert(any())).thenReturn(tokenRevocationAuthenticationResult); - when(authenticationProvider.supports(eq(OAuth2TokenRevocationAuthenticationToken.class))).thenReturn(true); - when(authenticationProvider.authenticate(any())).thenReturn(tokenRevocationAuthenticationResult); - - this.mvc.perform(post(providerSettings.getTokenRevocationEndpoint()) - .params(getTokenRevocationRequestParameters(token, tokenType)) - .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth( - registeredClient.getClientId(), registeredClient.getClientSecret()))) - .andExpect(status().isOk()); - - verify(revocationRequestConverter).convert(any()); - verify(authenticationProvider).authenticate(eq(tokenRevocationAuthenticationResult)); - verify(revocationResponseHandler).onAuthenticationSuccess(any(), any(), eq(tokenRevocationAuthenticationResult)); - } - - private void assertRevokeAccessTokenThenRevoked(String tokenRevocationEndpointUri) throws Exception { RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); this.registeredClientRepository.save(registeredClient); @@ -217,7 +177,7 @@ public class OAuth2TokenRevocationTests { OAuth2TokenType tokenType = OAuth2TokenType.ACCESS_TOKEN; this.authorizationService.save(authorization); - this.mvc.perform(post(tokenRevocationEndpointUri) + this.mvc.perform(post(DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI) .params(getTokenRevocationRequestParameters(token, tokenType)) .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth( registeredClient.getClientId(), registeredClient.getClientSecret()))) @@ -230,6 +190,38 @@ public class OAuth2TokenRevocationTests { assertThat(refreshToken.isInvalidated()).isFalse(); } + @Test + public void requestWhenTokenRevocationEndpointCustomizedThenUsed() throws Exception { + this.spring.register(AuthorizationServerConfigurationCustomTokenRevocationEndpoint.class).autowire(); + + RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); + this.registeredClientRepository.save(registeredClient); + + OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); + OAuth2AccessToken token = authorization.getAccessToken().getToken(); + OAuth2TokenType tokenType = OAuth2TokenType.ACCESS_TOKEN; + this.authorizationService.save(authorization); + + Authentication clientPrincipal = new OAuth2ClientAuthenticationToken( + registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret()); + OAuth2TokenRevocationAuthenticationToken tokenRevocationAuthentication = + new OAuth2TokenRevocationAuthenticationToken(token, clientPrincipal); + + when(authenticationConverter.convert(any())).thenReturn(tokenRevocationAuthentication); + when(authenticationProvider.supports(eq(OAuth2TokenRevocationAuthenticationToken.class))).thenReturn(true); + when(authenticationProvider.authenticate(any())).thenReturn(tokenRevocationAuthentication); + + this.mvc.perform(post(DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI) + .params(getTokenRevocationRequestParameters(token, tokenType)) + .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth( + registeredClient.getClientId(), registeredClient.getClientSecret()))) + .andExpect(status().isOk()); + + verify(authenticationConverter).convert(any()); + verify(authenticationProvider).authenticate(eq(tokenRevocationAuthentication)); + verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), eq(tokenRevocationAuthentication)); + } + private static MultiValueMap getTokenRevocationRequestParameters(AbstractOAuth2Token token, OAuth2TokenType tokenType) { MultiValueMap parameters = new LinkedMultiValueMap<>(); parameters.set(OAuth2ParameterNames.TOKEN, token.getTokenValue()); @@ -302,22 +294,20 @@ public class OAuth2TokenRevocationTests { } @EnableWebSecurity - @Import(OAuth2AuthorizationServerConfiguration.class) - static class AuthorizationServerConfigurationCustomEndpoints extends AuthorizationServerConfiguration { + static class AuthorizationServerConfigurationCustomTokenRevocationEndpoint extends AuthorizationServerConfiguration { // @formatter:off @Bean - @Order(Ordered.HIGHEST_PRECEDENCE) public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer<>(); authorizationServerConfigurer .tokenRevocationEndpoint(tokenRevocationEndpoint -> tokenRevocationEndpoint - .revocationRequestConverter(revocationRequestConverter) + .revocationRequestConverter(authenticationConverter) .authenticationProvider(authenticationProvider) - .revocationResponseHandler(revocationResponseHandler) - .errorResponseHandler(errorResponseHandler)); + .revocationResponseHandler(authenticationSuccessHandler) + .errorResponseHandler(authenticationFailureHandler)); RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher(); http @@ -331,10 +321,6 @@ public class OAuth2TokenRevocationTests { } // @formatter:on - @Bean - ProviderSettings providerSettings() { - return providerSettings; - } } } diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenRevocationEndpointFilterTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenRevocationEndpointFilterTests.java index c5f71ee0..bc5cac08 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenRevocationEndpointFilterTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenRevocationEndpointFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -101,24 +101,24 @@ public class OAuth2TokenRevocationEndpointFilterTests { } @Test - public void setRevocationRequestConverterWhenNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> this.filter.setRevocationRequestConverter(null)) + public void setAuthenticationConverterWhenNullThenThrowIllegalArgumentException() { + assertThatThrownBy(() -> this.filter.setAuthenticationConverter(null)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("revocationRequestConverter cannot be null"); + .hasMessage("authenticationConverter cannot be null"); } @Test - public void setRevocationResponseHandlerWhenNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> this.filter.setRevocationResponseHandler(null)) + public void setAuthenticationSuccessHandlerWhenNullThenThrowIllegalArgumentException() { + assertThatThrownBy(() -> this.filter.setAuthenticationSuccessHandler(null)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("revocationResponseHandler cannot be null"); + .hasMessage("authenticationSuccessHandler cannot be null"); } @Test - public void setErrorResponseHandlerWhenNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> this.filter.setErrorResponseHandler(null)) + public void setAuthenticationFailureHandlerWhenNullThenThrowIllegalArgumentException() { + assertThatThrownBy(() -> this.filter.setAuthenticationFailureHandler(null)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("errorResponseHandler cannot be null"); + .hasMessage("authenticationFailureHandler cannot be null"); } @Test @@ -217,7 +217,7 @@ public class OAuth2TokenRevocationEndpointFilterTests { AuthenticationConverter authenticationConverter = mock(AuthenticationConverter.class); when(authenticationConverter.convert(any())).thenReturn(tokenRevocationAuthentication); - this.filter.setRevocationRequestConverter(authenticationConverter); + this.filter.setAuthenticationConverter(authenticationConverter); when(this.authenticationManager.authenticate(any())).thenReturn(tokenRevocationAuthentication); @@ -236,9 +236,6 @@ public class OAuth2TokenRevocationEndpointFilterTests { @Test public void doFilterWhenCustomAuthenticationSuccessHandlerThenUsed() throws Exception { - AuthenticationSuccessHandler authenticationSuccessHandler = mock(AuthenticationSuccessHandler.class); - this.filter.setRevocationResponseHandler(authenticationSuccessHandler); - RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); Authentication clientPrincipal = new OAuth2ClientAuthenticationToken( registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret()); @@ -250,6 +247,9 @@ public class OAuth2TokenRevocationEndpointFilterTests { new OAuth2TokenRevocationAuthenticationToken( accessToken, clientPrincipal); + AuthenticationSuccessHandler authenticationSuccessHandler = mock(AuthenticationSuccessHandler.class); + this.filter.setAuthenticationSuccessHandler(authenticationSuccessHandler); + when(this.authenticationManager.authenticate(any())).thenReturn(tokenRevocationAuthentication); SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); @@ -267,13 +267,13 @@ public class OAuth2TokenRevocationEndpointFilterTests { @Test public void doFilterWhenCustomAuthenticationFailureHandlerThenUsed() throws Exception { - AuthenticationFailureHandler authenticationFailureHandler = mock(AuthenticationFailureHandler.class); - this.filter.setErrorResponseHandler(authenticationFailureHandler); - RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); Authentication clientPrincipal = new OAuth2ClientAuthenticationToken( registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret()); + AuthenticationFailureHandler authenticationFailureHandler = mock(AuthenticationFailureHandler.class); + this.filter.setAuthenticationFailureHandler(authenticationFailureHandler); + when(this.authenticationManager.authenticate(any())).thenThrow(OAuth2AuthenticationException.class); SecurityContext securityContext = SecurityContextHolder.createEmptyContext();