Joe Grandja пре 5 година
родитељ
комит
c8cc9717c9
28 измењених фајлова са 233 додато и 466 уклоњено
  1. 6 6
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/AuthorizedClientServiceOAuth2AuthorizedClientManager.java
  2. 6 7
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager.java
  3. 9 3
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ClientCredentialsOAuth2AuthorizedClientProvider.java
  4. 4 1
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ClientCredentialsReactiveOAuth2AuthorizedClientProvider.java
  5. 9 3
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordOAuth2AuthorizedClientProvider.java
  6. 4 1
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordReactiveOAuth2AuthorizedClientProvider.java
  7. 9 3
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RefreshTokenOAuth2AuthorizedClientProvider.java
  8. 4 1
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RefreshTokenReactiveOAuth2AuthorizedClientProvider.java
  9. 30 48
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientOAuth2AuthorizationFailureHandler.java
  10. 40 63
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler.java
  11. 0 31
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/AbstractWebClientReactiveOAuth2AccessTokenResponseClient.java
  12. 5 19
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClient.java
  13. 5 19
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClient.java
  14. 5 19
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClient.java
  15. 5 19
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClient.java
  16. 6 16
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClient.java
  17. 11 4
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizedClientManager.java
  18. 9 5
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultReactiveOAuth2AuthorizedClientManager.java
  19. 0 77
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/SaveAuthorizedClientOAuth2AuthorizationSuccessHandler.java
  20. 0 80
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler.java
  21. 8 4
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java
  22. 6 3
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java
  23. 10 4
      oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/AuthorizedClientServiceOAuth2AuthorizedClientManagerTests.java
  24. 8 5
      oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveAuthorizationCodeTokenResponseClientTests.java
  25. 8 5
      oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClientTests.java
  26. 6 10
      oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactivePasswordTokenResponseClientTests.java
  27. 6 8
      oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveRefreshTokenTokenResponseClientTests.java
  28. 14 2
      oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizedClientManagerTests.java

+ 6 - 6
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/AuthorizedClientServiceOAuth2AuthorizedClientManager.java

@@ -20,8 +20,6 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
 import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
-import org.springframework.security.oauth2.client.web.RemoveAuthorizedClientOAuth2AuthorizationFailureHandler;
-import org.springframework.security.oauth2.client.web.SaveAuthorizedClientOAuth2AuthorizationSuccessHandler;
 import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
@@ -94,8 +92,11 @@ public final class AuthorizedClientServiceOAuth2AuthorizedClientManager implemen
 		this.clientRegistrationRepository = clientRegistrationRepository;
 		this.authorizedClientService = authorizedClientService;
 		this.contextAttributesMapper = new DefaultContextAttributesMapper();
-		this.authorizationSuccessHandler = new SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(authorizedClientService);
-		this.authorizationFailureHandler = new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(authorizedClientService);
+		this.authorizationSuccessHandler = (authorizedClient, principal, attributes) ->
+				authorizedClientService.saveAuthorizedClient(authorizedClient, principal);
+		this.authorizationFailureHandler = new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
+				(clientRegistrationId, principal, attributes) ->
+						authorizedClientService.removeAuthorizedClient(clientRegistrationId, principal.getName()));
 	}
 
 	@Nullable
@@ -177,10 +178,9 @@ public final class AuthorizedClientServiceOAuth2AuthorizedClientManager implemen
 	 * Sets the {@link OAuth2AuthorizationSuccessHandler} that handles successful authorizations.
 	 *
 	 * <p>
-	 * A {@link SaveAuthorizedClientOAuth2AuthorizationSuccessHandler} is used by default.
+	 * The default saves {@link OAuth2AuthorizedClient}s in the {@link OAuth2AuthorizedClientService}.
 	 *
 	 * @param authorizationSuccessHandler the {@link OAuth2AuthorizationSuccessHandler} that handles successful authorizations
-	 * @see SaveAuthorizedClientOAuth2AuthorizationSuccessHandler
 	 * @since 5.3
 	 */
 	public void setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler authorizationSuccessHandler) {

+ 6 - 7
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager.java

@@ -18,8 +18,6 @@ package org.springframework.security.oauth2.client;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
 import org.springframework.security.oauth2.client.web.DefaultReactiveOAuth2AuthorizedClientManager;
-import org.springframework.security.oauth2.client.web.RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler;
-import org.springframework.security.oauth2.client.web.SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler;
 import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.util.Assert;
 import org.springframework.web.server.ServerWebExchange;
@@ -91,8 +89,11 @@ public final class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
 		Assert.notNull(authorizedClientService, "authorizedClientService cannot be null");
 		this.clientRegistrationRepository = clientRegistrationRepository;
 		this.authorizedClientService = authorizedClientService;
-		this.authorizationSuccessHandler = new SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler(authorizedClientService);
-		this.authorizationFailureHandler = new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(authorizedClientService);
+		this.authorizationSuccessHandler = (authorizedClient, principal, attributes) ->
+				authorizedClientService.saveAuthorizedClient(authorizedClient, principal);
+		this.authorizationFailureHandler = new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
+				(clientRegistrationId, principal, attributes) ->
+						this.authorizedClientService.removeAuthorizedClient(clientRegistrationId, principal.getName()));
 	}
 
 	@Override
@@ -179,11 +180,9 @@ public final class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
 	/**
 	 * Sets the handler that handles successful authorizations.
 	 *
-	 * <p>A {@link SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler}
-	 * is used by default.</p>
+	 * The default saves {@link OAuth2AuthorizedClient}s in the {@link ReactiveOAuth2AuthorizedClientService}.
 	 *
 	 * @param authorizationSuccessHandler the handler that handles successful authorizations.
-	 * @see SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler
 	 * @since 5.3
 	 */
 	public void setAuthorizationSuccessHandler(ReactiveOAuth2AuthorizationSuccessHandler authorizationSuccessHandler) {

+ 9 - 3
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ClientCredentialsOAuth2AuthorizedClientProvider.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -22,6 +22,7 @@ import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentia
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.AbstractOAuth2Token;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.util.Assert;
 
@@ -79,8 +80,13 @@ public final class ClientCredentialsOAuth2AuthorizedClientProvider implements OA
 
 		OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest =
 				new OAuth2ClientCredentialsGrantRequest(clientRegistration);
-		OAuth2AccessTokenResponse tokenResponse =
-				this.accessTokenResponseClient.getTokenResponse(clientCredentialsGrantRequest);
+
+		OAuth2AccessTokenResponse tokenResponse;
+		try {
+			tokenResponse = this.accessTokenResponseClient.getTokenResponse(clientCredentialsGrantRequest);
+		} catch (OAuth2AuthorizationException ex) {
+			throw new ClientAuthorizationException(ex.getError(), clientRegistration.getRegistrationId(), ex);
+		}
 
 		return new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(), tokenResponse.getAccessToken());
 	}

+ 4 - 1
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ClientCredentialsReactiveOAuth2AuthorizedClientProvider.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -21,6 +21,7 @@ import org.springframework.security.oauth2.client.endpoint.WebClientReactiveClie
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.AbstractOAuth2Token;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.util.Assert;
 import reactor.core.publisher.Mono;
 
@@ -77,6 +78,8 @@ public final class ClientCredentialsReactiveOAuth2AuthorizedClientProvider imple
 
 		return Mono.just(new OAuth2ClientCredentialsGrantRequest(clientRegistration))
 				.flatMap(this.accessTokenResponseClient::getTokenResponse)
+				.onErrorMap(OAuth2AuthorizationException.class,
+						e -> new ClientAuthorizationException(e.getError(), clientRegistration.getRegistrationId(), e))
 				.map(tokenResponse -> new OAuth2AuthorizedClient(
 						clientRegistration, context.getPrincipal().getName(), tokenResponse.getAccessToken()));
 	}

+ 9 - 3
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordOAuth2AuthorizedClientProvider.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -22,6 +22,7 @@ import org.springframework.security.oauth2.client.endpoint.OAuth2PasswordGrantRe
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.AbstractOAuth2Token;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
@@ -96,8 +97,13 @@ public final class PasswordOAuth2AuthorizedClientProvider implements OAuth2Autho
 
 		OAuth2PasswordGrantRequest passwordGrantRequest =
 				new OAuth2PasswordGrantRequest(clientRegistration, username, password);
-		OAuth2AccessTokenResponse tokenResponse =
-				this.accessTokenResponseClient.getTokenResponse(passwordGrantRequest);
+
+		OAuth2AccessTokenResponse tokenResponse;
+		try {
+			tokenResponse = this.accessTokenResponseClient.getTokenResponse(passwordGrantRequest);
+		} catch (OAuth2AuthorizationException ex) {
+			throw new ClientAuthorizationException(ex.getError(), clientRegistration.getRegistrationId(), ex);
+		}
 
 		return new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(),
 				tokenResponse.getAccessToken(), tokenResponse.getRefreshToken());

+ 4 - 1
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordReactiveOAuth2AuthorizedClientProvider.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -21,6 +21,7 @@ import org.springframework.security.oauth2.client.endpoint.WebClientReactivePass
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.AbstractOAuth2Token;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 import reactor.core.publisher.Mono;
@@ -97,6 +98,8 @@ public final class PasswordReactiveOAuth2AuthorizedClientProvider implements Rea
 
 		return Mono.just(passwordGrantRequest)
 				.flatMap(this.accessTokenResponseClient::getTokenResponse)
+				.onErrorMap(OAuth2AuthorizationException.class,
+						e -> new ClientAuthorizationException(e.getError(), clientRegistration.getRegistrationId(), e))
 				.map(tokenResponse -> new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(),
 						tokenResponse.getAccessToken(), tokenResponse.getRefreshToken()));
 	}

+ 9 - 3
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RefreshTokenOAuth2AuthorizedClientProvider.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -21,6 +21,7 @@ import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResp
 import org.springframework.security.oauth2.client.endpoint.OAuth2RefreshTokenGrantRequest;
 import org.springframework.security.oauth2.core.AbstractOAuth2Token;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.util.Assert;
 
@@ -86,8 +87,13 @@ public final class RefreshTokenOAuth2AuthorizedClientProvider implements OAuth2A
 		OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
 				authorizedClient.getClientRegistration(), authorizedClient.getAccessToken(),
 				authorizedClient.getRefreshToken(), scopes);
-		OAuth2AccessTokenResponse tokenResponse =
-				this.accessTokenResponseClient.getTokenResponse(refreshTokenGrantRequest);
+
+		OAuth2AccessTokenResponse tokenResponse;
+		try {
+			tokenResponse = this.accessTokenResponseClient.getTokenResponse(refreshTokenGrantRequest);
+		} catch (OAuth2AuthorizationException ex) {
+			throw new ClientAuthorizationException(ex.getError(), authorizedClient.getClientRegistration().getRegistrationId(), ex);
+		}
 
 		return new OAuth2AuthorizedClient(context.getAuthorizedClient().getClientRegistration(),
 				context.getPrincipal().getName(), tokenResponse.getAccessToken(), tokenResponse.getRefreshToken());

+ 4 - 1
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RefreshTokenReactiveOAuth2AuthorizedClientProvider.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -21,6 +21,7 @@ import org.springframework.security.oauth2.client.endpoint.WebClientReactiveRefr
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.AbstractOAuth2Token;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.util.Assert;
 import reactor.core.publisher.Mono;
 
@@ -88,6 +89,8 @@ public final class RefreshTokenReactiveOAuth2AuthorizedClientProvider implements
 
 		return Mono.just(refreshTokenGrantRequest)
 				.flatMap(this.accessTokenResponseClient::getTokenResponse)
+				.onErrorMap(OAuth2AuthorizationException.class,
+						e -> new ClientAuthorizationException(e.getError(), clientRegistration.getRegistrationId(), e))
 				.map(tokenResponse -> new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(),
 						tokenResponse.getAccessToken(), tokenResponse.getRefreshToken()));
 	}

+ 30 - 48
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/RemoveAuthorizedClientOAuth2AuthorizationFailureHandler.java → oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientOAuth2AuthorizationFailureHandler.java

@@ -13,19 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springframework.security.oauth2.client.web;
+package org.springframework.security.oauth2.client;
 
 import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
-import org.springframework.security.oauth2.client.OAuth2AuthorizationFailureHandler;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
 import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 import org.springframework.util.Assert;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
@@ -34,8 +30,8 @@ import java.util.Set;
 
 /**
  * An {@link OAuth2AuthorizationFailureHandler} that removes an {@link OAuth2AuthorizedClient}
- * from an {@link OAuth2AuthorizedClientRepository} or {@link OAuth2AuthorizedClientService}
- * for a specific set of OAuth 2.0 error codes.
+ * when the {@link OAuth2Error#getErrorCode()} matches
+ * one of the configured {@link OAuth2ErrorCodes OAuth 2.0 error codes}.
  *
  * @author Joe Grandja
  * @since 5.3
@@ -74,73 +70,58 @@ public class RemoveAuthorizedClientOAuth2AuthorizationFailureHandler implements
 	private final Set<String> removeAuthorizedClientErrorCodes;
 
 	/**
-	 * A delegate that removes an {@link OAuth2AuthorizedClient} from a
+	 * A delegate that removes an {@link OAuth2AuthorizedClient} from an
 	 * {@link OAuth2AuthorizedClientRepository} or {@link OAuth2AuthorizedClientService}
 	 * if the error code is one of the {@link #removeAuthorizedClientErrorCodes}.
 	 */
 	private final OAuth2AuthorizedClientRemover delegate;
 
-	@FunctionalInterface
-	private interface OAuth2AuthorizedClientRemover {
-		void removeAuthorizedClient(String clientRegistrationId, Authentication principal, Map<String, Object> attributes);
-	}
-
 	/**
-	 * Constructs a {@code RemoveAuthorizedClientOAuth2AuthorizationFailureHandler} using the provided parameters.
-	 *
-	 * @param authorizedClientRepository the repository from which authorized clients will be removed
-	 *                                   if the error code is one of the {@link #DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES}.
+	 * Removes an {@link OAuth2AuthorizedClient} from an
+	 * {@link OAuth2AuthorizedClientRepository} or {@link OAuth2AuthorizedClientService}.
 	 */
-	public RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(OAuth2AuthorizedClientRepository authorizedClientRepository) {
-		this(authorizedClientRepository, DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES);
-	}
+	@FunctionalInterface
+	public interface OAuth2AuthorizedClientRemover {
 
-	/**
-	 * Constructs a {@code RemoveAuthorizedClientOAuth2AuthorizationFailureHandler} using the provided parameters.
-	 *
-	 * @param authorizedClientRepository the repository from which authorized clients will be removed
-	 *                                   if the error code is one of the {@link #removeAuthorizedClientErrorCodes}.
-	 * @param removeAuthorizedClientErrorCodes the OAuth 2.0 error codes which will trigger removal of an authorized client.
-	 * @see OAuth2ErrorCodes
-	 */
-	public RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
-			OAuth2AuthorizedClientRepository authorizedClientRepository,
-			Set<String> removeAuthorizedClientErrorCodes) {
-		Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
-		Assert.notNull(removeAuthorizedClientErrorCodes, "removeAuthorizedClientErrorCodes cannot be null");
-		this.removeAuthorizedClientErrorCodes = Collections.unmodifiableSet(new HashSet<>(removeAuthorizedClientErrorCodes));
-		this.delegate = (clientRegistrationId, principal, attributes) ->
-				authorizedClientRepository.removeAuthorizedClient(clientRegistrationId, principal,
-						(HttpServletRequest) attributes.get(HttpServletRequest.class.getName()),
-						(HttpServletResponse) attributes.get(HttpServletResponse.class.getName()));
+		/**
+		 * Removes the {@link OAuth2AuthorizedClient} associated to the
+		 * provided client registration identifier and End-User {@link Authentication} (Resource Owner).
+		 *
+		 * @param clientRegistrationId the identifier for the client's registration
+		 * @param principal the End-User {@link Authentication} (Resource Owner)
+		 * @param attributes an immutable {@code Map} of (optional) attributes present under certain conditions.
+		 *                   For example, this might contain a {@code javax.servlet.http.HttpServletRequest}
+		 *                   and {@code javax.servlet.http.HttpServletResponse} if the authorization was performed
+		 *                   within the context of a {@code javax.servlet.ServletContext}.
+		 */
+		void removeAuthorizedClient(String clientRegistrationId, Authentication principal, Map<String, Object> attributes);
 	}
 
 	/**
 	 * Constructs a {@code RemoveAuthorizedClientOAuth2AuthorizationFailureHandler} using the provided parameters.
 	 *
-	 * @param authorizedClientService the service from which authorized clients will be removed
+	 * @param authorizedClientRemover the {@link OAuth2AuthorizedClientRemover} used for removing an {@link OAuth2AuthorizedClient}
 	 *                                if the error code is one of the {@link #DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES}.
 	 */
-	public RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(OAuth2AuthorizedClientService authorizedClientService) {
-		this(authorizedClientService, DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES);
+	public RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(OAuth2AuthorizedClientRemover authorizedClientRemover) {
+		this(authorizedClientRemover, DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES);
 	}
 
 	/**
 	 * Constructs a {@code RemoveAuthorizedClientOAuth2AuthorizationFailureHandler} using the provided parameters.
 	 *
-	 * @param authorizedClientService the service from which authorized clients will be removed
+	 * @param authorizedClientRemover the {@link OAuth2AuthorizedClientRemover} used for removing an {@link OAuth2AuthorizedClient}
 	 *                                if the error code is one of the {@link #removeAuthorizedClientErrorCodes}.
 	 * @param removeAuthorizedClientErrorCodes the OAuth 2.0 error codes which will trigger removal of an authorized client.
 	 * @see OAuth2ErrorCodes
 	 */
 	public RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
-			OAuth2AuthorizedClientService authorizedClientService,
+			OAuth2AuthorizedClientRemover authorizedClientRemover,
 			Set<String> removeAuthorizedClientErrorCodes) {
-		Assert.notNull(authorizedClientService, "authorizedClientService cannot be null");
+		Assert.notNull(authorizedClientRemover, "authorizedClientRemover cannot be null");
 		Assert.notNull(removeAuthorizedClientErrorCodes, "removeAuthorizedClientErrorCodes cannot be null");
 		this.removeAuthorizedClientErrorCodes = Collections.unmodifiableSet(new HashSet<>(removeAuthorizedClientErrorCodes));
-		this.delegate = (clientRegistrationId, principal, attributes) ->
-				authorizedClientService.removeAuthorizedClient(clientRegistrationId, principal.getName());
+		this.delegate = authorizedClientRemover;
 	}
 
 	@Override
@@ -149,6 +130,7 @@ public class RemoveAuthorizedClientOAuth2AuthorizationFailureHandler implements
 
 		if (authorizationException instanceof ClientAuthorizationException &&
 				hasRemovalErrorCode(authorizationException)) {
+
 			ClientAuthorizationException clientAuthorizationException = (ClientAuthorizationException) authorizationException;
 			this.delegate.removeAuthorizedClient(
 					clientAuthorizationException.getClientRegistrationId(), principal, attributes);

+ 40 - 63
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler.java → oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler.java

@@ -13,17 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springframework.security.oauth2.client.web;
+package org.springframework.security.oauth2.client;
 
 import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
-import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizationFailureHandler;
-import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
 import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
 import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 import org.springframework.util.Assert;
-import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 
 import java.util.Arrays;
@@ -33,10 +30,9 @@ import java.util.Map;
 import java.util.Set;
 
 /**
- * An authorization failure handler that removes authorized clients from a
- * {@link ServerOAuth2AuthorizedClientRepository}
- * or a {@link ReactiveOAuth2AuthorizedClientService}.
- * for specific OAuth 2.0 error codes.
+ * A {@link ReactiveOAuth2AuthorizationFailureHandler} that removes an {@link OAuth2AuthorizedClient}
+ * when the {@link OAuth2Error#getErrorCode()} matches
+ * one of the configured {@link OAuth2ErrorCodes OAuth 2.0 error codes}.
  *
  * @author Phil Clay
  * @since 5.3
@@ -64,10 +60,8 @@ public class RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler imp
 			OAuth2ErrorCodes.INVALID_GRANT)));
 
 	/**
-	 * A delegate that removes clients from either a
-	 * {@link ServerOAuth2AuthorizedClientRepository}
-	 * or a
-	 * {@link ReactiveOAuth2AuthorizedClientService}
+	 * A delegate that removes an {@link OAuth2AuthorizedClient} from a
+	 * {@link ServerOAuth2AuthorizedClientRepository} or {@link ReactiveOAuth2AuthorizedClientService}
 	 * if the error code is one of the {@link #removeAuthorizedClientErrorCodes}.
 	 */
 	private final OAuth2AuthorizedClientRemover delegate;
@@ -78,81 +72,64 @@ public class RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler imp
 	 */
 	private final Set<String> removeAuthorizedClientErrorCodes;
 
-	@FunctionalInterface
-	private interface OAuth2AuthorizedClientRemover {
-		Mono<Void> removeAuthorizedClient(
-				String clientRegistrationId,
-				Authentication principal,
-				Map<String, Object> attributes);
-	}
-
 	/**
-	 * @param authorizedClientRepository The repository from which authorized clients will be removed
-	 * 		  if the error code is one of the {@link #DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES}.
+	 * Removes an {@link OAuth2AuthorizedClient} from a
+	 * {@link ServerOAuth2AuthorizedClientRepository} or {@link ReactiveOAuth2AuthorizedClientService}.
 	 */
-	public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
-		this(authorizedClientRepository, DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES);
-	}
+	@FunctionalInterface
+	public interface OAuth2AuthorizedClientRemover {
 
-	/**
-	 * @param authorizedClientRepository The repository from which authorized clients will be removed
-	 * 		 if the error code is one of the {@code removeAuthorizedClientErrorCodes}.
-	 * @param removeAuthorizedClientErrorCodes the OAuth 2.0 Error Codes which will trigger removal of an authorized client.
-	 * @see OAuth2ErrorCodes
-	 */
-	public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
-			ServerOAuth2AuthorizedClientRepository authorizedClientRepository,
-			Set<String> removeAuthorizedClientErrorCodes) {
-		Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
-		Assert.notNull(removeAuthorizedClientErrorCodes, "removeAuthorizedClientErrorCodes cannot be null");
-		this.removeAuthorizedClientErrorCodes = Collections.unmodifiableSet(new HashSet<>(removeAuthorizedClientErrorCodes));
-		this.delegate = (clientRegistrationId, principal, attributes) ->
-				authorizedClientRepository.removeAuthorizedClient(
-						clientRegistrationId,
-						principal,
-						(ServerWebExchange) attributes.get(ServerWebExchange.class.getName()));
+		/**
+		 * Removes the {@link OAuth2AuthorizedClient} associated to the
+		 * provided client registration identifier and End-User {@link Authentication} (Resource Owner).
+		 *
+		 * @param clientRegistrationId the identifier for the client's registration
+		 * @param principal the End-User {@link Authentication} (Resource Owner)
+		 * @param attributes an immutable {@code Map} of extra optional attributes present under certain conditions.
+		 *                   For example, this might contain a {@link org.springframework.web.server.ServerWebExchange ServerWebExchange}
+		 *                   if the authorization was performed within the context of a {@code ServerWebExchange}.
+		 * @return an empty {@link Mono} that completes after this handler has finished handling the event.
+		 */
+		Mono<Void> removeAuthorizedClient(String clientRegistrationId, Authentication principal, Map<String, Object> attributes);
 	}
 
 	/**
-	 * @param authorizedClientService the service from which authorized clients will be removed
-	 * 		  if the error code is one of the {@link #DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES}.
+	 * Constructs a {@code RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler} using the provided parameters.
+	 *
+	 * @param authorizedClientRemover the {@link OAuth2AuthorizedClientRemover} used for removing an {@link OAuth2AuthorizedClient}
+	 *                                if the error code is one of the {@link #DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES}.
 	 */
-	public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(ReactiveOAuth2AuthorizedClientService authorizedClientService) {
-		this(authorizedClientService, DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES);
+	public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(OAuth2AuthorizedClientRemover authorizedClientRemover) {
+		this(authorizedClientRemover, DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES);
 	}
 
 	/**
-	 * @param authorizedClientService the service from which authorized clients will be removed
-	 * 		  if the error code is one of the {@code removeAuthorizedClientErrorCodes}.
-	 * @param removeAuthorizedClientErrorCodes the OAuth 2.0 Error Codes which will trigger removal of an authorized client.
+	 * Constructs a {@code RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler} using the provided parameters.
+	 *
+	 * @param authorizedClientRemover the {@link OAuth2AuthorizedClientRemover} used for removing an {@link OAuth2AuthorizedClient}
+	 *                                if the error code is one of the {@link #removeAuthorizedClientErrorCodes}.
+	 * @param removeAuthorizedClientErrorCodes the OAuth 2.0 error codes which will trigger removal of an authorized client.
 	 * @see OAuth2ErrorCodes
 	 */
 	public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
-			ReactiveOAuth2AuthorizedClientService authorizedClientService,
+			OAuth2AuthorizedClientRemover authorizedClientRemover,
 			Set<String> removeAuthorizedClientErrorCodes) {
-		Assert.notNull(authorizedClientService, "authorizedClientService cannot be null");
+		Assert.notNull(authorizedClientRemover, "authorizedClientRemover cannot be null");
 		Assert.notNull(removeAuthorizedClientErrorCodes, "removeAuthorizedClientErrorCodes cannot be null");
 		this.removeAuthorizedClientErrorCodes = Collections.unmodifiableSet(new HashSet<>(removeAuthorizedClientErrorCodes));
-		this.delegate = (clientRegistrationId, principal, attributes) ->
-				authorizedClientService.removeAuthorizedClient(
-						clientRegistrationId,
-						principal.getName());
+		this.delegate = authorizedClientRemover;
 	}
 
 	@Override
-	public Mono<Void> onAuthorizationFailure(
-			OAuth2AuthorizationException authorizationException,
-			Authentication principal,
-			Map<String, Object> attributes) {
+	public Mono<Void> onAuthorizationFailure(OAuth2AuthorizationException authorizationException,
+			Authentication principal, Map<String, Object> attributes) {
 
 		if (authorizationException instanceof ClientAuthorizationException
 				&& hasRemovalErrorCode(authorizationException)) {
 
 			ClientAuthorizationException clientAuthorizationException = (ClientAuthorizationException) authorizationException;
 			return this.delegate.removeAuthorizedClient(
-					clientAuthorizationException.getClientRegistrationId(),
-					principal,
-					attributes);
+					clientAuthorizationException.getClientRegistrationId(), principal, attributes);
 		} else {
 			return Mono.empty();
 		}

+ 0 - 31
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/AbstractWebClientReactiveOAuth2AccessTokenResponseClient.java

@@ -17,10 +17,8 @@ package org.springframework.security.oauth2.client.endpoint;
 
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
-import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 import org.springframework.util.Assert;
@@ -167,38 +165,9 @@ abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient<T extend
 	 */
 	private Mono<OAuth2AccessTokenResponse> readTokenResponse(T grantRequest, ClientResponse response) {
 		return response.body(oauth2AccessTokenResponse())
-				.onErrorMap(OAuth2AuthorizationException.class, e -> createClientAuthorizationException(
-						response,
-						clientRegistration(grantRequest).getRegistrationId(),
-						e))
 				.map(tokenResponse -> populateTokenResponse(grantRequest, tokenResponse));
 	}
 
-	/**
-	 * Wraps the given {@link OAuth2AuthorizationException} in a {@link ClientAuthorizationException}
-	 * that provides response details, and a more descriptive exception message.
-	 *
-	 * @param response the token response
-	 * @param clientRegistrationId the id of the {@link ClientRegistration} for which a token is being requested
-	 * @param authorizationException the {@link OAuth2AuthorizationException} to wrap
-	 * @return the {@link ClientAuthorizationException} that wraps the given {@link OAuth2AuthorizationException}
-	 */
-	private OAuth2AuthorizationException createClientAuthorizationException(
-			ClientResponse response,
-			String clientRegistrationId,
-			OAuth2AuthorizationException authorizationException) {
-
-		String message = String.format("Error retrieving OAuth 2.0 Access Token (HTTP Status Code: %s) %s",
-				response.rawStatusCode(),
-				authorizationException.getError());
-
-		return new ClientAuthorizationException(
-				authorizationException.getError(),
-				clientRegistrationId,
-				message,
-				authorizationException);
-	}
-
 	/**
 	 * Populates the given {@link OAuth2AccessTokenResponse} with additional details
 	 * from the grant request.

+ 5 - 19
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClient.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2018 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.
@@ -20,9 +20,9 @@ import org.springframework.http.RequestEntity;
 import org.springframework.http.ResponseEntity;
 import org.springframework.http.converter.FormHttpMessageConverter;
 import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
@@ -30,7 +30,6 @@ import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.client.ResponseErrorHandler;
 import org.springframework.web.client.RestClientException;
-import org.springframework.web.client.RestClientResponseException;
 import org.springframework.web.client.RestOperations;
 import org.springframework.web.client.RestTemplate;
 
@@ -75,22 +74,9 @@ public final class DefaultAuthorizationCodeTokenResponseClient implements OAuth2
 		try {
 			response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
 		} catch (RestClientException ex) {
-			int statusCode = 500;
-			if (ex instanceof RestClientResponseException) {
-				statusCode = ((RestClientResponseException) ex).getRawStatusCode();
-			}
-			OAuth2Error oauth2Error = new OAuth2Error(
-					INVALID_TOKEN_RESPONSE_ERROR_CODE,
-					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(),
-					null);
-			String message = String.format("Error retrieving OAuth 2.0 Access Token (HTTP Status Code: %s) %s",
-					statusCode,
-					oauth2Error);
-			throw new ClientAuthorizationException(
-					oauth2Error,
-					authorizationCodeGrantRequest.getClientRegistration().getRegistrationId(),
-					message,
-					ex);
+			OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
+					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
+			throw new OAuth2AuthorizationException(oauth2Error, ex);
 		}
 
 		OAuth2AccessTokenResponse tokenResponse = response.getBody();

+ 5 - 19
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClient.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2018 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.
@@ -20,9 +20,9 @@ import org.springframework.http.RequestEntity;
 import org.springframework.http.ResponseEntity;
 import org.springframework.http.converter.FormHttpMessageConverter;
 import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
@@ -30,7 +30,6 @@ import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.client.ResponseErrorHandler;
 import org.springframework.web.client.RestClientException;
-import org.springframework.web.client.RestClientResponseException;
 import org.springframework.web.client.RestOperations;
 import org.springframework.web.client.RestTemplate;
 
@@ -75,22 +74,9 @@ public final class DefaultClientCredentialsTokenResponseClient implements OAuth2
 		try {
 			response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
 		} catch (RestClientException ex) {
-			int statusCode = 500;
-			if (ex instanceof RestClientResponseException) {
-				statusCode = ((RestClientResponseException) ex).getRawStatusCode();
-			}
-			OAuth2Error oauth2Error = new OAuth2Error(
-					INVALID_TOKEN_RESPONSE_ERROR_CODE,
-					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(),
-					null);
-			String message = String.format("Error retrieving OAuth 2.0 Access Token (HTTP Status Code: %s) %s",
-					statusCode,
-					oauth2Error);
-			throw new ClientAuthorizationException(
-					oauth2Error,
-					clientCredentialsGrantRequest.getClientRegistration().getRegistrationId(),
-					message,
-					ex);
+			OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
+					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
+			throw new OAuth2AuthorizationException(oauth2Error, ex);
 		}
 
 		OAuth2AccessTokenResponse tokenResponse = response.getBody();

+ 5 - 19
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClient.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2019 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.
@@ -20,9 +20,9 @@ import org.springframework.http.RequestEntity;
 import org.springframework.http.ResponseEntity;
 import org.springframework.http.converter.FormHttpMessageConverter;
 import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
@@ -30,7 +30,6 @@ import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.client.ResponseErrorHandler;
 import org.springframework.web.client.RestClientException;
-import org.springframework.web.client.RestClientResponseException;
 import org.springframework.web.client.RestOperations;
 import org.springframework.web.client.RestTemplate;
 
@@ -75,22 +74,9 @@ public final class DefaultPasswordTokenResponseClient implements OAuth2AccessTok
 		try {
 			response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
 		} catch (RestClientException ex) {
-			int statusCode = 500;
-			if (ex instanceof RestClientResponseException) {
-				statusCode = ((RestClientResponseException) ex).getRawStatusCode();
-			}
-			OAuth2Error oauth2Error = new OAuth2Error(
-					INVALID_TOKEN_RESPONSE_ERROR_CODE,
-					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(),
-					null);
-			String message = String.format("Error retrieving OAuth 2.0 Access Token (HTTP Status Code: %s) %s",
-					statusCode,
-					oauth2Error);
-			throw new ClientAuthorizationException(
-					oauth2Error,
-					passwordGrantRequest.getClientRegistration().getRegistrationId(),
-					message,
-					ex);
+			OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
+					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
+			throw new OAuth2AuthorizationException(oauth2Error, ex);
 		}
 
 		OAuth2AccessTokenResponse tokenResponse = response.getBody();

+ 5 - 19
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClient.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2019 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.
@@ -20,9 +20,9 @@ import org.springframework.http.RequestEntity;
 import org.springframework.http.ResponseEntity;
 import org.springframework.http.converter.FormHttpMessageConverter;
 import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
@@ -30,7 +30,6 @@ import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.client.ResponseErrorHandler;
 import org.springframework.web.client.RestClientException;
-import org.springframework.web.client.RestClientResponseException;
 import org.springframework.web.client.RestOperations;
 import org.springframework.web.client.RestTemplate;
 
@@ -74,22 +73,9 @@ public final class DefaultRefreshTokenTokenResponseClient implements OAuth2Acces
 		try {
 			response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
 		} catch (RestClientException ex) {
-			int statusCode = 500;
-			if (ex instanceof RestClientResponseException) {
-				statusCode = ((RestClientResponseException) ex).getRawStatusCode();
-			}
-			OAuth2Error oauth2Error = new OAuth2Error(
-					INVALID_TOKEN_RESPONSE_ERROR_CODE,
-					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(),
-					null);
-			String message = String.format("Error retrieving OAuth 2.0 Access Token (HTTP Status Code: %s) %s",
-					statusCode,
-					oauth2Error);
-			throw new ClientAuthorizationException(
-					oauth2Error,
-					refreshTokenGrantRequest.getClientRegistration().getRegistrationId(),
-					message,
-					ex);
+			OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
+					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
+			throw new OAuth2AuthorizationException(oauth2Error, ex);
 		}
 
 		OAuth2AccessTokenResponse tokenResponse = response.getBody();

+ 6 - 16
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClient.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2018 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,10 +31,10 @@ import com.nimbusds.oauth2.sdk.auth.Secret;
 import com.nimbusds.oauth2.sdk.http.HTTPRequest;
 import com.nimbusds.oauth2.sdk.id.ClientID;
 import org.springframework.http.MediaType;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
 import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
@@ -100,19 +100,9 @@ public class NimbusAuthorizationCodeTokenResponseClient implements OAuth2AccessT
 			httpRequest.setReadTimeout(30000);
 			tokenResponse = com.nimbusds.oauth2.sdk.TokenResponse.parse(httpRequest.send());
 		} catch (ParseException | IOException ex) {
-			int statusCode = 500;
-			OAuth2Error oauth2Error = new OAuth2Error(
-					INVALID_TOKEN_RESPONSE_ERROR_CODE,
-					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(),
-					null);
-			String message = String.format("Error retrieving OAuth 2.0 Access Token (HTTP Status Code: %s) %s",
-					statusCode,
-					oauth2Error);
-			throw new ClientAuthorizationException(
-					oauth2Error,
-					clientRegistration.getRegistrationId(),
-					message,
-					ex);
+			OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
+					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
+			throw new OAuth2AuthorizationException(oauth2Error, ex);
 		}
 
 		if (!tokenResponse.indicatesSuccess()) {
@@ -127,7 +117,7 @@ public class NimbusAuthorizationCodeTokenResponseClient implements OAuth2AccessT
 						errorObject.getDescription(),
 						errorObject.getURI() != null ? errorObject.getURI().toString() : null);
 			}
-			throw new ClientAuthorizationException(oauth2Error, clientRegistration.getRegistrationId());
+			throw new OAuth2AuthorizationException(oauth2Error);
 		}
 
 		AccessTokenResponse accessTokenResponse = (AccessTokenResponse) tokenResponse;

+ 11 - 4
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizedClientManager.java

@@ -25,6 +25,7 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
+import org.springframework.security.oauth2.client.RemoveAuthorizedClientOAuth2AuthorizationFailureHandler;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
 import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
@@ -102,8 +103,15 @@ public final class DefaultOAuth2AuthorizedClientManager implements OAuth2Authori
 		this.clientRegistrationRepository = clientRegistrationRepository;
 		this.authorizedClientRepository = authorizedClientRepository;
 		this.contextAttributesMapper = new DefaultContextAttributesMapper();
-		this.authorizationSuccessHandler = new SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(authorizedClientRepository);
-		this.authorizationFailureHandler = new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(authorizedClientRepository);
+		this.authorizationSuccessHandler = (authorizedClient, principal, attributes) ->
+				authorizedClientRepository.saveAuthorizedClient(authorizedClient, principal,
+						(HttpServletRequest) attributes.get(HttpServletRequest.class.getName()),
+						(HttpServletResponse) attributes.get(HttpServletResponse.class.getName()));
+		this.authorizationFailureHandler = new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
+				(clientRegistrationId, principal, attributes) ->
+						authorizedClientRepository.removeAuthorizedClient(clientRegistrationId, principal,
+								(HttpServletRequest) attributes.get(HttpServletRequest.class.getName()),
+								(HttpServletResponse) attributes.get(HttpServletResponse.class.getName())));
 	}
 
 	@Nullable
@@ -221,10 +229,9 @@ public final class DefaultOAuth2AuthorizedClientManager implements OAuth2Authori
 	 * Sets the {@link OAuth2AuthorizationSuccessHandler} that handles successful authorizations.
 	 *
 	 * <p>
-	 * A {@link SaveAuthorizedClientOAuth2AuthorizationSuccessHandler} is used by default.
+	 * The default saves {@link OAuth2AuthorizedClient}s in the {@link OAuth2AuthorizedClientRepository}.
 	 *
 	 * @param authorizationSuccessHandler the {@link OAuth2AuthorizationSuccessHandler} that handles successful authorizations
-	 * @see SaveAuthorizedClientOAuth2AuthorizationSuccessHandler
 	 * @since 5.3
 	 */
 	public void setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler authorizationSuccessHandler) {

+ 9 - 5
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultReactiveOAuth2AuthorizedClientManager.java

@@ -23,6 +23,7 @@ import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizationFai
 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizationSuccessHandler;
 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider;
+import org.springframework.security.oauth2.client.RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
 import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
@@ -101,8 +102,13 @@ public final class DefaultReactiveOAuth2AuthorizedClientManager implements React
 		Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
 		this.clientRegistrationRepository = clientRegistrationRepository;
 		this.authorizedClientRepository = authorizedClientRepository;
-		this.authorizationSuccessHandler = new SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler(authorizedClientRepository);
-		this.authorizationFailureHandler = new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(authorizedClientRepository);
+		this.authorizationSuccessHandler = (authorizedClient, principal, attributes) ->
+				authorizedClientRepository.saveAuthorizedClient(authorizedClient, principal,
+						(ServerWebExchange) attributes.get(ServerWebExchange.class.getName()));
+		this.authorizationFailureHandler = new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
+				(clientRegistrationId, principal, attributes) ->
+						authorizedClientRepository.removeAuthorizedClient(clientRegistrationId, principal,
+								(ServerWebExchange) attributes.get(ServerWebExchange.class.getName())));
 	}
 
 	@Override
@@ -230,11 +236,9 @@ public final class DefaultReactiveOAuth2AuthorizedClientManager implements React
 	/**
 	 * Sets the handler that handles successful authorizations.
 	 *
-	 * <p>A {@link SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler}
-	 * is used by default.</p>
+	 * The default saves {@link OAuth2AuthorizedClient}s in the {@link ServerOAuth2AuthorizedClientRepository}.
 	 *
 	 * @param authorizationSuccessHandler the handler that handles successful authorizations.
-	 * @see SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler
 	 * @since 5.3
 	 */
 	public void setAuthorizationSuccessHandler(ReactiveOAuth2AuthorizationSuccessHandler authorizationSuccessHandler) {

+ 0 - 77
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/SaveAuthorizedClientOAuth2AuthorizationSuccessHandler.java

@@ -1,77 +0,0 @@
-/*
- * Copyright 2002-2020 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.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.security.oauth2.client.web;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.client.OAuth2AuthorizationSuccessHandler;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
-import org.springframework.util.Assert;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.Map;
-
-/**
- * An {@link OAuth2AuthorizationSuccessHandler} that saves an {@link OAuth2AuthorizedClient}
- * in an {@link OAuth2AuthorizedClientRepository} or {@link OAuth2AuthorizedClientService}.
- *
- * @author Joe Grandja
- * @since 5.3
- * @see OAuth2AuthorizedClient
- * @see OAuth2AuthorizedClientRepository
- * @see OAuth2AuthorizedClientService
- */
-public class SaveAuthorizedClientOAuth2AuthorizationSuccessHandler implements OAuth2AuthorizationSuccessHandler {
-
-	/**
-	 * A delegate that saves an {@link OAuth2AuthorizedClient} in an
-	 * {@link OAuth2AuthorizedClientRepository} or {@link OAuth2AuthorizedClientService}.
-	 */
-	private final OAuth2AuthorizationSuccessHandler delegate;
-
-	/**
-	 * Constructs a {@code SaveAuthorizedClientOAuth2AuthorizationSuccessHandler} using the provided parameters.
-	 *
-	 * @param authorizedClientRepository The repository in which authorized clients will be saved.
-	 */
-	public SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(
-			OAuth2AuthorizedClientRepository authorizedClientRepository) {
-		Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
-		this.delegate = (authorizedClient, principal, attributes) ->
-				authorizedClientRepository.saveAuthorizedClient(authorizedClient, principal,
-						(HttpServletRequest) attributes.get(HttpServletRequest.class.getName()),
-						(HttpServletResponse) attributes.get(HttpServletResponse.class.getName()));
-	}
-
-	/**
-	 * Constructs a {@code SaveAuthorizedClientOAuth2AuthorizationSuccessHandler} using the provided parameters.
-	 *
-	 * @param authorizedClientService The service in which authorized clients will be saved.
-	 */
-	public SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(
-			OAuth2AuthorizedClientService authorizedClientService) {
-		Assert.notNull(authorizedClientService, "authorizedClientService cannot be null");
-		this.delegate = (authorizedClient, principal, attributes) ->
-				authorizedClientService.saveAuthorizedClient(authorizedClient, principal);
-	}
-
-	@Override
-	public void onAuthorizationSuccess(OAuth2AuthorizedClient authorizedClient,
-			Authentication principal, Map<String, Object> attributes) {
-		this.delegate.onAuthorizationSuccess(authorizedClient, principal, attributes);
-	}
-}

+ 0 - 80
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler.java

@@ -1,80 +0,0 @@
-/*
- * Copyright 2002-2020 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.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.security.oauth2.client.web;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
-import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizationSuccessHandler;
-import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
-import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
-import org.springframework.util.Assert;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-
-import java.util.Map;
-
-/**
- * An authorization success handler that saves authorized clients in a
- * {@link ServerOAuth2AuthorizedClientRepository}
- * or a {@link ReactiveOAuth2AuthorizedClientService}.
- *
- * @author Phil Clay
- * @since 5.3
- */
-public class SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler implements ReactiveOAuth2AuthorizationSuccessHandler {
-
-	/**
-	 * A delegate that saves clients in either a
-	 * {@link ServerOAuth2AuthorizedClientRepository}
-	 * or a
-	 * {@link ReactiveOAuth2AuthorizedClientService}.
-	 */
-	private final ReactiveOAuth2AuthorizationSuccessHandler delegate;
-
-	/**
-	 * @param authorizedClientRepository The repository in which authorized clients will be saved.
-	 */
-	public SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler(final ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
-		Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
-		this.delegate = (authorizedClient, principal, attributes) ->
-				authorizedClientRepository.saveAuthorizedClient(
-						authorizedClient,
-						principal,
-						(ServerWebExchange) attributes.get(ServerWebExchange.class.getName()));
-	}
-
-	/**
-	 * @param authorizedClientService The service in which authorized clients will be saved.
-	 */
-	public SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler(final ReactiveOAuth2AuthorizedClientService authorizedClientService) {
-		Assert.notNull(authorizedClientService, "authorizedClientService cannot be null");
-		this.delegate = (authorizedClient, principal, attributes) ->
-				authorizedClientService.saveAuthorizedClient(
-						authorizedClient,
-						principal);
-	}
-
-	@Override
-	public Mono<Void> onAuthorizationSuccess(
-			OAuth2AuthorizedClient authorizedClient,
-			Authentication principal,
-			Map<String, Object> attributes) {
-		return this.delegate.onAuthorizationSuccess(
-				authorizedClient,
-				principal,
-				attributes);
-	}
-}

+ 8 - 4
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java

@@ -34,14 +34,13 @@ import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClient
 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider;
 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder;
 import org.springframework.security.oauth2.client.RefreshTokenReactiveOAuth2AuthorizedClientProvider;
+import org.springframework.security.oauth2.client.RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
 import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
 import org.springframework.security.oauth2.client.endpoint.ReactiveOAuth2AccessTokenResponseClient;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
 import org.springframework.security.oauth2.client.web.DefaultReactiveOAuth2AuthorizedClientManager;
-import org.springframework.security.oauth2.client.web.RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler;
-import org.springframework.security.oauth2.client.web.SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler;
 import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
 import org.springframework.security.oauth2.client.web.server.UnAuthenticatedServerOAuth2AuthorizedClientRepository;
 import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
@@ -191,7 +190,10 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
 																ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
 
 		ReactiveOAuth2AuthorizationFailureHandler authorizationFailureHandler =
-				new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(authorizedClientRepository);
+				new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
+						(clientRegistrationId, principal, attributes) ->
+								authorizedClientRepository.removeAuthorizedClient(clientRegistrationId, principal,
+										(ServerWebExchange) attributes.get(ServerWebExchange.class.getName())));
 
 		this.authorizedClientManager = createDefaultAuthorizedClientManager(
 				clientRegistrationRepository,
@@ -518,7 +520,9 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
 				ReactiveOAuth2AuthorizationFailureHandler authorizationFailureHandler) {
 			this.clientRegistrationRepository = clientRegistrationRepository;
 			this.authorizedClientRepository = authorizedClientRepository;
-			this.authorizationSuccessHandler = new SaveAuthorizedClientReactiveOAuth2AuthorizationSuccessHandler(authorizedClientRepository);
+			this.authorizationSuccessHandler = (authorizedClient, principal, attributes) ->
+					authorizedClientRepository.saveAuthorizedClient(authorizedClient, principal,
+							(ServerWebExchange) attributes.get(ServerWebExchange.class.getName()));
 			this.authorizationFailureHandler = authorizationFailureHandler;
 		}
 

+ 6 - 3
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java

@@ -31,6 +31,7 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
 import org.springframework.security.oauth2.client.RefreshTokenOAuth2AuthorizedClientProvider;
+import org.springframework.security.oauth2.client.RemoveAuthorizedClientOAuth2AuthorizationFailureHandler;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
 import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
 import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
@@ -38,7 +39,6 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
 import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
 import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
-import org.springframework.security.oauth2.client.web.RemoveAuthorizedClientOAuth2AuthorizationFailureHandler;
 import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
@@ -212,8 +212,11 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
 			OAuth2AuthorizedClientRepository authorizedClientRepository) {
 
 		OAuth2AuthorizationFailureHandler authorizationFailureHandler =
-				new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(authorizedClientRepository);
-
+				new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
+						(clientRegistrationId, principal, attributes) ->
+								authorizedClientRepository.removeAuthorizedClient(clientRegistrationId, principal,
+										(HttpServletRequest) attributes.get(HttpServletRequest.class.getName()),
+										(HttpServletResponse) attributes.get(HttpServletResponse.class.getName())));
 		this.authorizedClientManager = createDefaultAuthorizedClientManager(
 				clientRegistrationRepository, authorizedClientRepository, authorizationFailureHandler);
 		this.defaultAuthorizedClientManager = true;

+ 10 - 4
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/AuthorizedClientServiceOAuth2AuthorizedClientManagerTests.java

@@ -23,14 +23,13 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
 import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
-import org.springframework.security.oauth2.client.web.RemoveAuthorizedClientOAuth2AuthorizationFailureHandler;
-import org.springframework.security.oauth2.client.web.SaveAuthorizedClientOAuth2AuthorizationSuccessHandler;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
 import org.springframework.security.oauth2.core.TestOAuth2RefreshTokens;
 import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 
+import java.util.Map;
 import java.util.function.Function;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -70,8 +69,15 @@ public class AuthorizedClientServiceOAuth2AuthorizedClientManagerTests {
 		this.authorizedClientService = mock(OAuth2AuthorizedClientService.class);
 		this.authorizedClientProvider = mock(OAuth2AuthorizedClientProvider.class);
 		this.contextAttributesMapper = mock(Function.class);
-		this.authorizationSuccessHandler = spy(new SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(this.authorizedClientService));
-		this.authorizationFailureHandler = spy(new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(this.authorizedClientService));
+		this.authorizationSuccessHandler = spy(new OAuth2AuthorizationSuccessHandler() {
+			@Override
+			public void onAuthorizationSuccess(OAuth2AuthorizedClient authorizedClient, Authentication principal, Map<String, Object> attributes) {
+				authorizedClientService.saveAuthorizedClient(authorizedClient, principal);
+			}
+		});
+		this.authorizationFailureHandler = spy(new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
+				(clientRegistrationId, principal, attributes) ->
+						this.authorizedClientService.removeAuthorizedClient(clientRegistrationId, principal.getName())));
 		this.authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(
 				this.clientRegistrationRepository, this.authorizedClientService);
 		this.authorizedClientManager.setAuthorizedClientProvider(this.authorizedClientProvider);

+ 8 - 5
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveAuthorizationCodeTokenResponseClientTests.java

@@ -24,10 +24,10 @@ import org.junit.Test;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
 import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
@@ -41,7 +41,10 @@ import java.util.Map;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 /**
  * @author Rob Winch
@@ -178,7 +181,7 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
 		this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()));
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block())
-			.isInstanceOfSatisfying(ClientAuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("unauthorized_client"))
+			.isInstanceOfSatisfying(OAuth2AuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("unauthorized_client"))
 			.hasMessageContaining("unauthorized_client");
 	}
 
@@ -189,7 +192,7 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
 		this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()));
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block())
-				.isInstanceOf(ClientAuthorizationException.class)
+				.isInstanceOf(OAuth2AuthorizationException.class)
 				.hasMessageContaining("server_error");
 	}
 
@@ -204,7 +207,7 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
 		this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block())
-				.isInstanceOf(ClientAuthorizationException.class)
+				.isInstanceOf(OAuth2AuthorizationException.class)
 				.hasMessageContaining("invalid_token_response");
 	}
 

+ 8 - 5
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClientTests.java

@@ -24,17 +24,21 @@ import org.junit.Before;
 import org.junit.Test;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.web.reactive.function.client.WebClient;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.validateMockitoUsage;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 /**
  * @author Rob Winch
@@ -157,10 +161,9 @@ public class WebClientReactiveClientCredentialsTokenResponseClientTests {
 		OAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(registration);
 
 		assertThatThrownBy(() -> this.client.getTokenResponse(request).block())
-				.isInstanceOfSatisfying(ClientAuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("invalid_token_response"))
+				.isInstanceOfSatisfying(OAuth2AuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("invalid_token_response"))
 				.hasMessageContaining("[invalid_token_response]")
-				.hasMessageContaining("Empty OAuth 2.0 Access Token Response")
-				.hasMessageContaining("HTTP Status Code: 301");
+				.hasMessageContaining("Empty OAuth 2.0 Access Token Response");
 
 	}
 

+ 6 - 10
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactivePasswordTokenResponseClientTests.java

@@ -24,11 +24,11 @@ import org.junit.Test;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
 import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 
 import java.time.Instant;
@@ -148,10 +148,9 @@ public class WebClientReactivePasswordTokenResponseClientTests {
 				this.clientRegistrationBuilder.build(), this.username, this.password);
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(passwordGrantRequest).block())
-				.isInstanceOfSatisfying(ClientAuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("invalid_token_response"))
+				.isInstanceOfSatisfying(OAuth2AuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("invalid_token_response"))
 				.hasMessageContaining("[invalid_token_response]")
 				.hasMessageContaining("An error occurred parsing the Access Token response")
-				.hasMessageContaining("HTTP Status Code: 200")
 				.hasCauseInstanceOf(Throwable.class);
 	}
 
@@ -188,10 +187,8 @@ public class WebClientReactivePasswordTokenResponseClientTests {
 				this.clientRegistrationBuilder.build(), this.username, this.password);
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(passwordGrantRequest).block())
-				.isInstanceOfSatisfying(ClientAuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("unauthorized_client"))
-				.hasMessageContaining("[unauthorized_client]")
-				.hasMessageContaining("Error retrieving OAuth 2.0 Access Token")
-				.hasMessageContaining("HTTP Status Code: 400");
+				.isInstanceOfSatisfying(OAuth2AuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("unauthorized_client"))
+				.hasMessageContaining("[unauthorized_client]");
 	}
 
 	@Test
@@ -202,10 +199,9 @@ public class WebClientReactivePasswordTokenResponseClientTests {
 				this.clientRegistrationBuilder.build(), this.username, this.password);
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(passwordGrantRequest).block())
-				.isInstanceOfSatisfying(ClientAuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("invalid_token_response"))
+				.isInstanceOfSatisfying(OAuth2AuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("invalid_token_response"))
 				.hasMessageContaining("[invalid_token_response]")
-				.hasMessageContaining("Empty OAuth 2.0 Access Token Response")
-				.hasMessageContaining("HTTP Status Code: 500");
+				.hasMessageContaining("Empty OAuth 2.0 Access Token Response");
 	}
 
 	private MockResponse jsonResponse(String json) {

+ 6 - 8
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveRefreshTokenTokenResponseClientTests.java

@@ -24,11 +24,11 @@ import org.junit.Test;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
-import org.springframework.security.oauth2.client.ClientAuthorizationException;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
 import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
 import org.springframework.security.oauth2.core.OAuth2RefreshToken;
 import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
 import org.springframework.security.oauth2.core.TestOAuth2RefreshTokens;
@@ -153,7 +153,7 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
 				this.clientRegistrationBuilder.build(), this.accessToken, this.refreshToken);
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(refreshTokenGrantRequest).block())
-				.isInstanceOf(ClientAuthorizationException.class)
+				.isInstanceOf(OAuth2AuthorizationException.class)
 				.hasMessageContaining("[invalid_token_response]")
 				.hasMessageContaining("An error occurred parsing the Access Token response")
 				.hasCauseInstanceOf(Throwable.class);
@@ -192,9 +192,8 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
 				this.clientRegistrationBuilder.build(), this.accessToken, this.refreshToken);
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(refreshTokenGrantRequest).block())
-				.isInstanceOfSatisfying(ClientAuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("unauthorized_client"))
-				.hasMessageContaining("[unauthorized_client]")
-				.hasMessageContaining("HTTP Status Code: 400");
+				.isInstanceOfSatisfying(OAuth2AuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("unauthorized_client"))
+				.hasMessageContaining("[unauthorized_client]");
 	}
 
 	@Test
@@ -205,10 +204,9 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
 				this.clientRegistrationBuilder.build(), this.accessToken, this.refreshToken);
 
 		assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(refreshTokenGrantRequest).block())
-				.isInstanceOfSatisfying(ClientAuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("invalid_token_response"))
+				.isInstanceOfSatisfying(OAuth2AuthorizationException.class, e -> assertThat(e.getError().getErrorCode()).isEqualTo("invalid_token_response"))
 				.hasMessageContaining("[invalid_token_response]")
-				.hasMessageContaining("Empty OAuth 2.0 Access Token Response")
-				.hasMessageContaining("HTTP Status Code: 500");
+				.hasMessageContaining("Empty OAuth 2.0 Access Token Response");
 	}
 
 	private MockResponse jsonResponse(String json) {

+ 14 - 2
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizedClientManagerTests.java

@@ -29,6 +29,7 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizationSuccessHand
 import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
+import org.springframework.security.oauth2.client.RemoveAuthorizedClientOAuth2AuthorizationFailureHandler;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
 import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
@@ -84,8 +85,19 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
 		this.authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
 		this.authorizedClientProvider = mock(OAuth2AuthorizedClientProvider.class);
 		this.contextAttributesMapper = mock(Function.class);
-		this.authorizationSuccessHandler = spy(new SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(this.authorizedClientRepository));
-		this.authorizationFailureHandler = spy(new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(this.authorizedClientRepository));
+		this.authorizationSuccessHandler = spy(new OAuth2AuthorizationSuccessHandler() {
+			@Override
+			public void onAuthorizationSuccess(OAuth2AuthorizedClient authorizedClient, Authentication principal, Map<String, Object> attributes) {
+				authorizedClientRepository.saveAuthorizedClient(authorizedClient, principal,
+						(HttpServletRequest) attributes.get(HttpServletRequest.class.getName()),
+						(HttpServletResponse) attributes.get(HttpServletResponse.class.getName()));
+			}
+		});
+		this.authorizationFailureHandler = spy(new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
+				(clientRegistrationId, principal, attributes) ->
+						authorizedClientRepository.removeAuthorizedClient(clientRegistrationId, principal,
+								(HttpServletRequest) attributes.get(HttpServletRequest.class.getName()),
+								(HttpServletResponse) attributes.get(HttpServletResponse.class.getName()))));
 		this.authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
 				this.clientRegistrationRepository, this.authorizedClientRepository);
 		this.authorizedClientManager.setAuthorizedClientProvider(this.authorizedClientProvider);