Fix package tangles

Issue #7699 #7840
This commit is contained in:
Joe Grandja 2020-02-21 16:47:24 -05:00
parent f2da2c56be
commit c8cc9717c9
28 changed files with 236 additions and 469 deletions

View File

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

View File

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

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.AbstractOAuth2Token; import org.springframework.security.oauth2.core.AbstractOAuth2Token;
import org.springframework.security.oauth2.core.AuthorizationGrantType; 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.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -79,8 +80,13 @@ public final class ClientCredentialsOAuth2AuthorizedClientProvider implements OA
OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest = OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest =
new OAuth2ClientCredentialsGrantRequest(clientRegistration); 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()); return new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(), tokenResponse.getAccessToken());
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.AbstractOAuth2Token; import org.springframework.security.oauth2.core.AbstractOAuth2Token;
import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -77,6 +78,8 @@ public final class ClientCredentialsReactiveOAuth2AuthorizedClientProvider imple
return Mono.just(new OAuth2ClientCredentialsGrantRequest(clientRegistration)) return Mono.just(new OAuth2ClientCredentialsGrantRequest(clientRegistration))
.flatMap(this.accessTokenResponseClient::getTokenResponse) .flatMap(this.accessTokenResponseClient::getTokenResponse)
.onErrorMap(OAuth2AuthorizationException.class,
e -> new ClientAuthorizationException(e.getError(), clientRegistration.getRegistrationId(), e))
.map(tokenResponse -> new OAuth2AuthorizedClient( .map(tokenResponse -> new OAuth2AuthorizedClient(
clientRegistration, context.getPrincipal().getName(), tokenResponse.getAccessToken())); clientRegistration, context.getPrincipal().getName(), tokenResponse.getAccessToken()));
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.AbstractOAuth2Token; import org.springframework.security.oauth2.core.AbstractOAuth2Token;
import org.springframework.security.oauth2.core.AuthorizationGrantType; 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.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -96,8 +97,13 @@ public final class PasswordOAuth2AuthorizedClientProvider implements OAuth2Autho
OAuth2PasswordGrantRequest passwordGrantRequest = OAuth2PasswordGrantRequest passwordGrantRequest =
new OAuth2PasswordGrantRequest(clientRegistration, username, password); 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(), return new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(),
tokenResponse.getAccessToken(), tokenResponse.getRefreshToken()); tokenResponse.getAccessToken(), tokenResponse.getRefreshToken());

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.AbstractOAuth2Token; import org.springframework.security.oauth2.core.AbstractOAuth2Token;
import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -97,6 +98,8 @@ public final class PasswordReactiveOAuth2AuthorizedClientProvider implements Rea
return Mono.just(passwordGrantRequest) return Mono.just(passwordGrantRequest)
.flatMap(this.accessTokenResponseClient::getTokenResponse) .flatMap(this.accessTokenResponseClient::getTokenResponse)
.onErrorMap(OAuth2AuthorizationException.class,
e -> new ClientAuthorizationException(e.getError(), clientRegistration.getRegistrationId(), e))
.map(tokenResponse -> new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(), .map(tokenResponse -> new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(),
tokenResponse.getAccessToken(), tokenResponse.getRefreshToken())); tokenResponse.getAccessToken(), tokenResponse.getRefreshToken()));
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.client.endpoint.OAuth2RefreshTokenGrantRequest;
import org.springframework.security.oauth2.core.AbstractOAuth2Token; import org.springframework.security.oauth2.core.AbstractOAuth2Token;
import org.springframework.security.oauth2.core.AuthorizationGrantType; 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.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -86,8 +87,13 @@ public final class RefreshTokenOAuth2AuthorizedClientProvider implements OAuth2A
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest( OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
authorizedClient.getClientRegistration(), authorizedClient.getAccessToken(), authorizedClient.getClientRegistration(), authorizedClient.getAccessToken(),
authorizedClient.getRefreshToken(), scopes); 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(), return new OAuth2AuthorizedClient(context.getAuthorizedClient().getClientRegistration(),
context.getPrincipal().getName(), tokenResponse.getAccessToken(), tokenResponse.getRefreshToken()); context.getPrincipal().getName(), tokenResponse.getAccessToken(), tokenResponse.getRefreshToken());

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.AbstractOAuth2Token; import org.springframework.security.oauth2.core.AbstractOAuth2Token;
import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -88,6 +89,8 @@ public final class RefreshTokenReactiveOAuth2AuthorizedClientProvider implements
return Mono.just(refreshTokenGrantRequest) return Mono.just(refreshTokenGrantRequest)
.flatMap(this.accessTokenResponseClient::getTokenResponse) .flatMap(this.accessTokenResponseClient::getTokenResponse)
.onErrorMap(OAuth2AuthorizationException.class,
e -> new ClientAuthorizationException(e.getError(), clientRegistration.getRegistrationId(), e))
.map(tokenResponse -> new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(), .map(tokenResponse -> new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(),
tokenResponse.getAccessToken(), tokenResponse.getRefreshToken())); tokenResponse.getAccessToken(), tokenResponse.getRefreshToken()));
} }

View File

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

View File

@ -13,17 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.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.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException; 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.OAuth2ErrorCodes;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.Arrays; import java.util.Arrays;
@ -33,10 +30,9 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* An authorization failure handler that removes authorized clients from a * A {@link ReactiveOAuth2AuthorizationFailureHandler} that removes an {@link OAuth2AuthorizedClient}
* {@link ServerOAuth2AuthorizedClientRepository} * when the {@link OAuth2Error#getErrorCode()} matches
* or a {@link ReactiveOAuth2AuthorizedClientService}. * one of the configured {@link OAuth2ErrorCodes OAuth 2.0 error codes}.
* for specific OAuth 2.0 error codes.
* *
* @author Phil Clay * @author Phil Clay
* @since 5.3 * @since 5.3
@ -64,10 +60,8 @@ public class RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler imp
OAuth2ErrorCodes.INVALID_GRANT))); OAuth2ErrorCodes.INVALID_GRANT)));
/** /**
* A delegate that removes clients from either a * A delegate that removes an {@link OAuth2AuthorizedClient} from a
* {@link ServerOAuth2AuthorizedClientRepository} * {@link ServerOAuth2AuthorizedClientRepository} or {@link ReactiveOAuth2AuthorizedClientService}
* or a
* {@link ReactiveOAuth2AuthorizedClientService}
* if the error code is one of the {@link #removeAuthorizedClientErrorCodes}. * if the error code is one of the {@link #removeAuthorizedClientErrorCodes}.
*/ */
private final OAuth2AuthorizedClientRemover delegate; private final OAuth2AuthorizedClientRemover delegate;
@ -78,81 +72,64 @@ public class RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler imp
*/ */
private final Set<String> removeAuthorizedClientErrorCodes; private final Set<String> removeAuthorizedClientErrorCodes;
/**
* Removes an {@link OAuth2AuthorizedClient} from a
* {@link ServerOAuth2AuthorizedClientRepository} or {@link ReactiveOAuth2AuthorizedClientService}.
*/
@FunctionalInterface @FunctionalInterface
private interface OAuth2AuthorizedClientRemover { public interface OAuth2AuthorizedClientRemover {
Mono<Void> removeAuthorizedClient(
String clientRegistrationId, /**
Authentication principal, * Removes the {@link OAuth2AuthorizedClient} associated to the
Map<String, Object> attributes); * 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 authorizedClientRepository The repository from which authorized clients will be removed * Constructs a {@code RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler} using the provided parameters.
* if the error code is one of the {@link #DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES}. *
* @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(ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(OAuth2AuthorizedClientRemover authorizedClientRemover) {
this(authorizedClientRepository, DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES); this(authorizedClientRemover, DEFAULT_REMOVE_AUTHORIZED_CLIENT_ERROR_CODES);
} }
/** /**
* @param authorizedClientRepository The repository from which authorized clients will be removed * Constructs a {@code RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler} using the provided parameters.
* 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. * @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 * @see OAuth2ErrorCodes
*/ */
public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler( public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
ServerOAuth2AuthorizedClientRepository authorizedClientRepository, OAuth2AuthorizedClientRemover authorizedClientRemover,
Set<String> removeAuthorizedClientErrorCodes) { Set<String> removeAuthorizedClientErrorCodes) {
Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null"); Assert.notNull(authorizedClientRemover, "authorizedClientRemover cannot be null");
Assert.notNull(removeAuthorizedClientErrorCodes, "removeAuthorizedClientErrorCodes cannot be null"); Assert.notNull(removeAuthorizedClientErrorCodes, "removeAuthorizedClientErrorCodes cannot be null");
this.removeAuthorizedClientErrorCodes = Collections.unmodifiableSet(new HashSet<>(removeAuthorizedClientErrorCodes)); this.removeAuthorizedClientErrorCodes = Collections.unmodifiableSet(new HashSet<>(removeAuthorizedClientErrorCodes));
this.delegate = (clientRegistrationId, principal, attributes) -> this.delegate = authorizedClientRemover;
authorizedClientRepository.removeAuthorizedClient(
clientRegistrationId,
principal,
(ServerWebExchange) attributes.get(ServerWebExchange.class.getName()));
}
/**
* @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}.
*/
public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(ReactiveOAuth2AuthorizedClientService authorizedClientService) {
this(authorizedClientService, 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.
* @see OAuth2ErrorCodes
*/
public RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
ReactiveOAuth2AuthorizedClientService authorizedClientService,
Set<String> removeAuthorizedClientErrorCodes) {
Assert.notNull(authorizedClientService, "authorizedClientService 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());
} }
@Override @Override
public Mono<Void> onAuthorizationFailure( public Mono<Void> onAuthorizationFailure(OAuth2AuthorizationException authorizationException,
OAuth2AuthorizationException authorizationException, Authentication principal, Map<String, Object> attributes) {
Authentication principal,
Map<String, Object> attributes) {
if (authorizationException instanceof ClientAuthorizationException if (authorizationException instanceof ClientAuthorizationException
&& hasRemovalErrorCode(authorizationException)) { && hasRemovalErrorCode(authorizationException)) {
ClientAuthorizationException clientAuthorizationException = (ClientAuthorizationException) authorizationException; ClientAuthorizationException clientAuthorizationException = (ClientAuthorizationException) authorizationException;
return this.delegate.removeAuthorizedClient( return this.delegate.removeAuthorizedClient(
clientAuthorizationException.getClientRegistrationId(), clientAuthorizationException.getClientRegistrationId(), principal, attributes);
principal,
attributes);
} else { } else {
return Mono.empty(); return Mono.empty();
} }

View File

@ -17,10 +17,8 @@ package org.springframework.security.oauth2.client.endpoint;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; 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.ClientRegistration;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod; 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.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -167,38 +165,9 @@ abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient<T extend
*/ */
private Mono<OAuth2AccessTokenResponse> readTokenResponse(T grantRequest, ClientResponse response) { private Mono<OAuth2AccessTokenResponse> readTokenResponse(T grantRequest, ClientResponse response) {
return response.body(oauth2AccessTokenResponse()) return response.body(oauth2AccessTokenResponse())
.onErrorMap(OAuth2AuthorizationException.class, e -> createClientAuthorizationException(
response,
clientRegistration(grantRequest).getRegistrationId(),
e))
.map(tokenResponse -> populateTokenResponse(grantRequest, tokenResponse)); .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 * Populates the given {@link OAuth2AccessTokenResponse} with additional details
* from the grant request. * from the grant request.

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.ResponseEntity;
import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter; 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.client.http.OAuth2ErrorResponseErrorHandler;
import org.springframework.security.oauth2.core.AuthorizationGrantType; 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.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; 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.util.CollectionUtils;
import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -75,22 +74,9 @@ public final class DefaultAuthorizationCodeTokenResponseClient implements OAuth2
try { try {
response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class); response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
} catch (RestClientException ex) { } catch (RestClientException ex) {
int statusCode = 500; OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
if (ex instanceof RestClientResponseException) { "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
statusCode = ((RestClientResponseException) ex).getRawStatusCode(); throw new OAuth2AuthorizationException(oauth2Error, 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);
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);
} }
OAuth2AccessTokenResponse tokenResponse = response.getBody(); OAuth2AccessTokenResponse tokenResponse = response.getBody();

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.ResponseEntity;
import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter; 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.client.http.OAuth2ErrorResponseErrorHandler;
import org.springframework.security.oauth2.core.AuthorizationGrantType; 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.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; 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.util.CollectionUtils;
import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -75,22 +74,9 @@ public final class DefaultClientCredentialsTokenResponseClient implements OAuth2
try { try {
response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class); response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
} catch (RestClientException ex) { } catch (RestClientException ex) {
int statusCode = 500; OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
if (ex instanceof RestClientResponseException) { "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
statusCode = ((RestClientResponseException) ex).getRawStatusCode(); throw new OAuth2AuthorizationException(oauth2Error, 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);
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);
} }
OAuth2AccessTokenResponse tokenResponse = response.getBody(); OAuth2AccessTokenResponse tokenResponse = response.getBody();

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.ResponseEntity;
import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter; 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.client.http.OAuth2ErrorResponseErrorHandler;
import org.springframework.security.oauth2.core.AuthorizationGrantType; 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.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; 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.util.CollectionUtils;
import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -75,22 +74,9 @@ public final class DefaultPasswordTokenResponseClient implements OAuth2AccessTok
try { try {
response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class); response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
} catch (RestClientException ex) { } catch (RestClientException ex) {
int statusCode = 500; OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
if (ex instanceof RestClientResponseException) { "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
statusCode = ((RestClientResponseException) ex).getRawStatusCode(); throw new OAuth2AuthorizationException(oauth2Error, 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);
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);
} }
OAuth2AccessTokenResponse tokenResponse = response.getBody(); OAuth2AccessTokenResponse tokenResponse = response.getBody();

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.ResponseEntity;
import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter; 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.client.http.OAuth2ErrorResponseErrorHandler;
import org.springframework.security.oauth2.core.AuthorizationGrantType; 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.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; 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.util.CollectionUtils;
import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -74,22 +73,9 @@ public final class DefaultRefreshTokenTokenResponseClient implements OAuth2Acces
try { try {
response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class); response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
} catch (RestClientException ex) { } catch (RestClientException ex) {
int statusCode = 500; OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
if (ex instanceof RestClientResponseException) { "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
statusCode = ((RestClientResponseException) ex).getRawStatusCode(); throw new OAuth2AuthorizationException(oauth2Error, 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);
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);
} }
OAuth2AccessTokenResponse tokenResponse = response.getBody(); OAuth2AccessTokenResponse tokenResponse = response.getBody();

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.id.ClientID; import com.nimbusds.oauth2.sdk.id.ClientID;
import org.springframework.http.MediaType; 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.ClientRegistration;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.OAuth2AccessToken; 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.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
@ -100,19 +100,9 @@ public class NimbusAuthorizationCodeTokenResponseClient implements OAuth2AccessT
httpRequest.setReadTimeout(30000); httpRequest.setReadTimeout(30000);
tokenResponse = com.nimbusds.oauth2.sdk.TokenResponse.parse(httpRequest.send()); tokenResponse = com.nimbusds.oauth2.sdk.TokenResponse.parse(httpRequest.send());
} catch (ParseException | IOException ex) { } catch (ParseException | IOException ex) {
int statusCode = 500; OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
OAuth2Error oauth2Error = new OAuth2Error( "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
INVALID_TOKEN_RESPONSE_ERROR_CODE, throw new OAuth2AuthorizationException(oauth2Error, ex);
"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);
} }
if (!tokenResponse.indicatesSuccess()) { if (!tokenResponse.indicatesSuccess()) {
@ -127,7 +117,7 @@ public class NimbusAuthorizationCodeTokenResponseClient implements OAuth2AccessT
errorObject.getDescription(), errorObject.getDescription(),
errorObject.getURI() != null ? errorObject.getURI().toString() : null); errorObject.getURI() != null ? errorObject.getURI().toString() : null);
} }
throw new ClientAuthorizationException(oauth2Error, clientRegistration.getRegistrationId()); throw new OAuth2AuthorizationException(oauth2Error);
} }
AccessTokenResponse accessTokenResponse = (AccessTokenResponse) tokenResponse; AccessTokenResponse accessTokenResponse = (AccessTokenResponse) tokenResponse;

View File

@ -25,6 +25,7 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; 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.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException; import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
@ -102,8 +103,15 @@ public final class DefaultOAuth2AuthorizedClientManager implements OAuth2Authori
this.clientRegistrationRepository = clientRegistrationRepository; this.clientRegistrationRepository = clientRegistrationRepository;
this.authorizedClientRepository = authorizedClientRepository; this.authorizedClientRepository = authorizedClientRepository;
this.contextAttributesMapper = new DefaultContextAttributesMapper(); this.contextAttributesMapper = new DefaultContextAttributesMapper();
this.authorizationSuccessHandler = new SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(authorizedClientRepository); this.authorizationSuccessHandler = (authorizedClient, principal, attributes) ->
this.authorizationFailureHandler = new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(authorizedClientRepository); 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 @Nullable
@ -221,10 +229,9 @@ public final class DefaultOAuth2AuthorizedClientManager implements OAuth2Authori
* Sets the {@link OAuth2AuthorizationSuccessHandler} that handles successful authorizations. * Sets the {@link OAuth2AuthorizationSuccessHandler} that handles successful authorizations.
* *
* <p> * <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 * @param authorizationSuccessHandler the {@link OAuth2AuthorizationSuccessHandler} that handles successful authorizations
* @see SaveAuthorizedClientOAuth2AuthorizationSuccessHandler
* @since 5.3 * @since 5.3
*/ */
public void setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler authorizationSuccessHandler) { public void setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler authorizationSuccessHandler) {

View File

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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

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

View File

@ -31,6 +31,7 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.RefreshTokenOAuth2AuthorizedClientProvider; 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.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest; 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.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; 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.OAuth2AuthorizationException;
import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
@ -212,8 +212,11 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
OAuth2AuthorizedClientRepository authorizedClientRepository) { OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizationFailureHandler authorizationFailureHandler = 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( this.authorizedClientManager = createDefaultAuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository, authorizationFailureHandler); clientRegistrationRepository, authorizedClientRepository, authorizationFailureHandler);
this.defaultAuthorizedClientManager = true; this.defaultAuthorizedClientManager = true;

View File

@ -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.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations; 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.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens; import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
import org.springframework.security.oauth2.core.TestOAuth2RefreshTokens; import org.springframework.security.oauth2.core.TestOAuth2RefreshTokens;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -70,8 +69,15 @@ public class AuthorizedClientServiceOAuth2AuthorizedClientManagerTests {
this.authorizedClientService = mock(OAuth2AuthorizedClientService.class); this.authorizedClientService = mock(OAuth2AuthorizedClientService.class);
this.authorizedClientProvider = mock(OAuth2AuthorizedClientProvider.class); this.authorizedClientProvider = mock(OAuth2AuthorizedClientProvider.class);
this.contextAttributesMapper = mock(Function.class); this.contextAttributesMapper = mock(Function.class);
this.authorizationSuccessHandler = spy(new SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(this.authorizedClientService)); this.authorizationSuccessHandler = spy(new OAuth2AuthorizationSuccessHandler() {
this.authorizationFailureHandler = spy(new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(this.authorizedClientService)); @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.authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(
this.clientRegistrationRepository, this.authorizedClientService); this.clientRegistrationRepository, this.authorizedClientService);
this.authorizedClientManager.setAuthorizedClientProvider(this.authorizedClientProvider); this.authorizedClientManager.setAuthorizedClientProvider(this.authorizedClientProvider);

View File

@ -24,10 +24,10 @@ import org.junit.Test;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; 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.ClientRegistration;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
import org.springframework.security.oauth2.core.OAuth2AccessToken; 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.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; 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 * @author Rob Winch
@ -178,7 +181,7 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value())); this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()));
assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block()) 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"); .hasMessageContaining("unauthorized_client");
} }
@ -189,7 +192,7 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value())); this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()));
assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block()) assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block())
.isInstanceOf(ClientAuthorizationException.class) .isInstanceOf(OAuth2AuthorizationException.class)
.hasMessageContaining("server_error"); .hasMessageContaining("server_error");
} }
@ -204,7 +207,7 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
this.server.enqueue(jsonResponse(accessTokenSuccessResponse)); this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block()) assertThatThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block())
.isInstanceOf(ClientAuthorizationException.class) .isInstanceOf(OAuth2AuthorizationException.class)
.hasMessageContaining("invalid_token_response"); .hasMessageContaining("invalid_token_response");
} }

View File

@ -24,17 +24,21 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; 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.ClientRegistration;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod; 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.OAuth2AccessTokenResponse;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException; import org.springframework.web.reactive.function.client.WebClientResponseException;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; 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 * @author Rob Winch
@ -157,10 +161,9 @@ public class WebClientReactiveClientCredentialsTokenResponseClientTests {
OAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(registration); OAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(registration);
assertThatThrownBy(() -> this.client.getTokenResponse(request).block()) 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("[invalid_token_response]")
.hasMessageContaining("Empty OAuth 2.0 Access Token Response") .hasMessageContaining("Empty OAuth 2.0 Access Token Response");
.hasMessageContaining("HTTP Status Code: 301");
} }

View File

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

View File

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

View File

@ -29,6 +29,7 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizationSuccessHand
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; 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.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
@ -84,8 +85,19 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
this.authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class); this.authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
this.authorizedClientProvider = mock(OAuth2AuthorizedClientProvider.class); this.authorizedClientProvider = mock(OAuth2AuthorizedClientProvider.class);
this.contextAttributesMapper = mock(Function.class); this.contextAttributesMapper = mock(Function.class);
this.authorizationSuccessHandler = spy(new SaveAuthorizedClientOAuth2AuthorizationSuccessHandler(this.authorizedClientRepository)); this.authorizationSuccessHandler = spy(new OAuth2AuthorizationSuccessHandler() {
this.authorizationFailureHandler = spy(new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(this.authorizedClientRepository)); @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.authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
this.clientRegistrationRepository, this.authorizedClientRepository); this.clientRegistrationRepository, this.authorizedClientRepository);
this.authorizedClientManager.setAuthorizedClientProvider(this.authorizedClientProvider); this.authorizedClientManager.setAuthorizedClientProvider(this.authorizedClientProvider);