Selaa lähdekoodia

Polish token revocation

Issue gh-490
Joe Grandja 3 vuotta sitten
vanhempi
commit
4d5b288116

+ 6 - 6
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<AuthenticationProvider> authenticationProviders = new LinkedList<>();
+	private RequestMatcher requestMatcher;
 	private AuthenticationConverter revocationRequestConverter;
+	private final List<AuthenticationProvider> 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);
 	}

+ 22 - 23
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<OAuth2Error> 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);
 	}
 

+ 36 - 50
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<SecurityContext> 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,31 @@ 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())
+		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(revocationRequestConverter).convert(any());
-		verify(authenticationProvider).authenticate(eq(tokenRevocationAuthenticationResult));
-		verify(revocationResponseHandler).onAuthenticationSuccess(any(), any(), eq(tokenRevocationAuthenticationResult));
+		OAuth2Authorization updatedAuthorization = this.authorizationService.findById(authorization.getId());
+		OAuth2Authorization.Token<OAuth2AccessToken> accessToken = updatedAuthorization.getAccessToken();
+		assertThat(accessToken.isInvalidated()).isTrue();
+		OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken = updatedAuthorization.getRefreshToken();
+		assertThat(refreshToken.isInvalidated()).isFalse();
 	}
 
-	private void assertRevokeAccessTokenThenRevoked(String tokenRevocationEndpointUri) throws Exception {
+	@Test
+	public void requestWhenTokenRevocationEndpointCustomizedThenUsed() throws Exception {
+		this.spring.register(AuthorizationServerConfigurationCustomTokenRevocationEndpoint.class).autowire();
+
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
 		this.registeredClientRepository.save(registeredClient);
 
@@ -217,17 +202,24 @@ public class OAuth2TokenRevocationTests {
 		OAuth2TokenType tokenType = OAuth2TokenType.ACCESS_TOKEN;
 		this.authorizationService.save(authorization);
 
-		this.mvc.perform(post(tokenRevocationEndpointUri)
+		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());
 
-		OAuth2Authorization updatedAuthorization = this.authorizationService.findById(authorization.getId());
-		OAuth2Authorization.Token<OAuth2AccessToken> accessToken = updatedAuthorization.getAccessToken();
-		assertThat(accessToken.isInvalidated()).isTrue();
-		OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken = updatedAuthorization.getRefreshToken();
-		assertThat(refreshToken.isInvalidated()).isFalse();
+		verify(authenticationConverter).convert(any());
+		verify(authenticationProvider).authenticate(eq(tokenRevocationAuthentication));
+		verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), eq(tokenRevocationAuthentication));
 	}
 
 	private static MultiValueMap<String, String> getTokenRevocationRequestParameters(AbstractOAuth2Token token, OAuth2TokenType tokenType) {
@@ -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<HttpSecurity> 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;
-		}
 	}
 
 }

+ 17 - 17
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();