Skip to content

Commit 8f046db

Browse files
committed
Introduce OAuth2AuthorizedClientManager
- spring-projects#73 Introduce OAuth2AuthorizedClientManager - spring-projects#74 Integrate OAuth2AuthorizedClientManager with OAuth2AuthorizedClientProvider(s) - spring-projects#81 Add builder for OAuth2AuthorizedClientProvider
1 parent f9fc7d3 commit 8f046db

File tree

24 files changed

+1265
-1024
lines changed

24 files changed

+1265
-1024
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfiguration.java

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@
2020
import org.springframework.context.annotation.Import;
2121
import org.springframework.context.annotation.ImportSelector;
2222
import org.springframework.core.type.AnnotationMetadata;
23-
import org.springframework.security.oauth2.client.AuthorizationCodeOAuth2AuthorizedClientProvider;
24-
import org.springframework.security.oauth2.client.ClientCredentialsOAuth2AuthorizedClientProvider;
25-
import org.springframework.security.oauth2.client.DefaultOAuth2AuthorizedClientProvider;
26-
import org.springframework.security.oauth2.client.DelegatingOAuth2AuthorizedClientProvider;
27-
import org.springframework.security.oauth2.client.RefreshTokenOAuth2AuthorizedClientProvider;
23+
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
24+
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
2825
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
2926
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
3027
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
28+
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
3129
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
3230
import org.springframework.security.oauth2.client.web.method.annotation.OAuth2AuthorizedClientArgumentResolver;
3331
import org.springframework.util.ClassUtils;
@@ -77,21 +75,16 @@ public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentRes
7775
new OAuth2AuthorizedClientArgumentResolver(
7876
this.clientRegistrationRepository, this.authorizedClientRepository);
7977
if (this.accessTokenResponseClient != null) {
80-
ClientCredentialsOAuth2AuthorizedClientProvider clientCredentialsAuthorizedClientProvider =
81-
new ClientCredentialsOAuth2AuthorizedClientProvider(
82-
this.clientRegistrationRepository, this.authorizedClientRepository);
83-
clientCredentialsAuthorizedClientProvider.setAccessTokenResponseClient(this.accessTokenResponseClient);
84-
AuthorizationCodeOAuth2AuthorizedClientProvider authorizationCodeAuthorizedClientProvider =
85-
new AuthorizationCodeOAuth2AuthorizedClientProvider(
86-
this.clientRegistrationRepository, this.authorizedClientRepository);
87-
RefreshTokenOAuth2AuthorizedClientProvider refreshTokenAuthorizedClientProvider =
88-
new RefreshTokenOAuth2AuthorizedClientProvider(
89-
this.clientRegistrationRepository, this.authorizedClientRepository);
90-
DelegatingOAuth2AuthorizedClientProvider authorizedClientProvider = new DelegatingOAuth2AuthorizedClientProvider(
91-
authorizationCodeAuthorizedClientProvider, refreshTokenAuthorizedClientProvider, clientCredentialsAuthorizedClientProvider);
92-
authorizedClientProvider.setDefaultAuthorizedClientProvider(
93-
new DefaultOAuth2AuthorizedClientProvider(this.clientRegistrationRepository, this.authorizedClientRepository));
94-
authorizedClientArgumentResolver.setAuthorizedClientProvider(authorizedClientProvider);
78+
OAuth2AuthorizedClientProvider authorizedClientProvider =
79+
OAuth2AuthorizedClientProviderBuilder.withProvider()
80+
.authorizationCode()
81+
.refreshToken()
82+
.clientCredentials(configurer -> configurer.accessTokenResponseClient(this.accessTokenResponseClient))
83+
.build();
84+
DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
85+
this.clientRegistrationRepository, this.authorizedClientRepository);
86+
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
87+
authorizedClientArgumentResolver.setAuthorizedClientManager(authorizedClientManager);
9588
}
9689
argumentResolvers.add(authorizedClientArgumentResolver);
9790
}

config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public void requestWhenAuthorizedClientFoundThenMethodArgumentResolved() throws
7575

7676
OAuth2AuthorizedClientRepository authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
7777
OAuth2AuthorizedClient authorizedClient = mock(OAuth2AuthorizedClient.class);
78+
when(authorizedClient.getClientRegistration()).thenReturn(clientRegistration);
7879
when(authorizedClientRepository.loadAuthorizedClient(
7980
eq(clientRegistrationId), eq(authentication), any(HttpServletRequest.class)))
8081
.thenReturn(authorizedClient);

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/AuthorizationCodeOAuth2AuthorizedClientProvider.java

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,9 @@
1717

1818
import org.springframework.lang.Nullable;
1919
import org.springframework.security.oauth2.client.registration.ClientRegistration;
20-
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
21-
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
2220
import org.springframework.security.oauth2.core.AuthorizationGrantType;
2321
import org.springframework.util.Assert;
2422

25-
import javax.servlet.http.HttpServletRequest;
26-
import javax.servlet.http.HttpServletResponse;
27-
2823
/**
2924
* An implementation of an {@link OAuth2AuthorizedClientProvider}
3025
* for the {@link AuthorizationGrantType#AUTHORIZATION_CODE authorization_code} grant.
@@ -34,38 +29,16 @@
3429
* @see OAuth2AuthorizedClientProvider
3530
*/
3631
public final class AuthorizationCodeOAuth2AuthorizedClientProvider implements OAuth2AuthorizedClientProvider {
37-
private static final String HTTP_SERVLET_REQUEST_ATTRIBUTE_NAME = HttpServletRequest.class.getName();
38-
private static final String HTTP_SERVLET_RESPONSE_ATTRIBUTE_NAME = HttpServletResponse.class.getName();
39-
private final ClientRegistrationRepository clientRegistrationRepository;
40-
private final OAuth2AuthorizedClientRepository authorizedClientRepository;
4132

42-
/**
43-
* Constructs an {@code AuthorizationCodeOAuth2AuthorizedClientProvider} using the provided parameters.
44-
*
45-
* @param clientRegistrationRepository the repository of client registrations
46-
* @param authorizedClientRepository the repository of authorized clients
47-
*/
48-
public AuthorizationCodeOAuth2AuthorizedClientProvider(ClientRegistrationRepository clientRegistrationRepository,
49-
OAuth2AuthorizedClientRepository authorizedClientRepository) {
50-
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
51-
Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
52-
this.clientRegistrationRepository = clientRegistrationRepository;
53-
this.authorizedClientRepository = authorizedClientRepository;
33+
public AuthorizationCodeOAuth2AuthorizedClientProvider() {
5434
}
5535

5636
/**
57-
* Attempt to authorize the {@link OAuth2AuthorizationContext#getClientRegistrationId() client} in the provided {@code context}.
37+
* Attempt to authorize the {@link OAuth2AuthorizationContext#getClientRegistration() client} in the provided {@code context}.
5838
* Returns {@code null} if authorization is not supported,
5939
* e.g. the client's {@link ClientRegistration#getAuthorizationGrantType() authorization grant type}
6040
* is not {@link AuthorizationGrantType#AUTHORIZATION_CODE authorization_code} OR the client is already authorized.
6141
*
62-
* <p>
63-
* The following {@link OAuth2AuthorizationContext#getAttributes() context attributes} are supported:
64-
* <ol>
65-
* <li>{@code "javax.servlet.http.HttpServletRequest"} (required) - the {@code HttpServletRequest}</li>
66-
* <li>{@code "javax.servlet.http.HttpServletResponse"} (required) - the {@code HttpServletResponse}</li>
67-
* </ol>
68-
*
6942
* @param context the context that holds authorization-specific state for the client
7043
* @return the {@link OAuth2AuthorizedClient} or {@code null} if authorization is not supported
7144
*/
@@ -74,26 +47,11 @@ public AuthorizationCodeOAuth2AuthorizedClientProvider(ClientRegistrationReposit
7447
public OAuth2AuthorizedClient authorize(OAuth2AuthorizationContext context) {
7548
Assert.notNull(context, "context cannot be null");
7649

77-
HttpServletRequest request = context.getAttribute(HTTP_SERVLET_REQUEST_ATTRIBUTE_NAME);
78-
HttpServletResponse response = context.getAttribute(HTTP_SERVLET_RESPONSE_ATTRIBUTE_NAME);
79-
Assert.notNull(request, "The context attribute cannot be null '" + HTTP_SERVLET_REQUEST_ATTRIBUTE_NAME + "'");
80-
Assert.notNull(response, "The context attribute cannot be null '" + HTTP_SERVLET_RESPONSE_ATTRIBUTE_NAME + "'");
81-
82-
String clientRegistrationId = context.getClientRegistrationId();
83-
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId);
84-
Assert.notNull(clientRegistration, "Could not find ClientRegistration with id '" + clientRegistrationId + "'");
85-
86-
if (!AuthorizationGrantType.AUTHORIZATION_CODE.equals(clientRegistration.getAuthorizationGrantType())) {
87-
return null;
88-
}
89-
90-
OAuth2AuthorizedClient authorizedClient = this.authorizedClientRepository.loadAuthorizedClient(
91-
clientRegistrationId, context.getPrincipal(), request);
92-
if (authorizedClient == null) {
50+
if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(context.getClientRegistration().getAuthorizationGrantType()) &&
51+
context.getAuthorizedClient() == null) {
9352
// ClientAuthorizationRequiredException is caught by OAuth2AuthorizationRequestRedirectFilter which initiates authorization
94-
throw new ClientAuthorizationRequiredException(clientRegistrationId);
53+
throw new ClientAuthorizationRequiredException(context.getClientRegistration().getRegistrationId());
9554
}
96-
9755
return null;
9856
}
9957
}

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

Lines changed: 7 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,11 @@
2020
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
2121
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
2222
import org.springframework.security.oauth2.client.registration.ClientRegistration;
23-
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
24-
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
2523
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
2624
import org.springframework.security.oauth2.core.AuthorizationGrantType;
2725
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
2826
import org.springframework.util.Assert;
2927

30-
import javax.servlet.http.HttpServletRequest;
31-
import javax.servlet.http.HttpServletResponse;
3228
import java.time.Duration;
3329
import java.time.Instant;
3430

@@ -42,42 +38,20 @@
4238
* @see DefaultClientCredentialsTokenResponseClient
4339
*/
4440
public final class ClientCredentialsOAuth2AuthorizedClientProvider implements OAuth2AuthorizedClientProvider {
45-
private static final String HTTP_SERVLET_REQUEST_ATTRIBUTE_NAME = HttpServletRequest.class.getName();
46-
private static final String HTTP_SERVLET_RESPONSE_ATTRIBUTE_NAME = HttpServletResponse.class.getName();
47-
private final ClientRegistrationRepository clientRegistrationRepository;
48-
private final OAuth2AuthorizedClientRepository authorizedClientRepository;
4941
private OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient =
5042
new DefaultClientCredentialsTokenResponseClient();
5143
private Duration clockSkew = Duration.ofSeconds(60);
5244

53-
/**
54-
* Constructs a {@code ClientCredentialsOAuth2AuthorizedClientProvider} using the provided parameters.
55-
*
56-
* @param clientRegistrationRepository the repository of client registrations
57-
* @param authorizedClientRepository the repository of authorized clients
58-
*/
59-
public ClientCredentialsOAuth2AuthorizedClientProvider(ClientRegistrationRepository clientRegistrationRepository,
60-
OAuth2AuthorizedClientRepository authorizedClientRepository) {
61-
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
62-
Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
63-
this.clientRegistrationRepository = clientRegistrationRepository;
64-
this.authorizedClientRepository = authorizedClientRepository;
45+
public ClientCredentialsOAuth2AuthorizedClientProvider() {
6546
}
6647

6748
/**
68-
* Attempt to authorize (or re-authorize) the {@link OAuth2AuthorizationContext#getClientRegistrationId() client} in the provided {@code context}.
49+
* Attempt to authorize (or re-authorize) the {@link OAuth2AuthorizationContext#getClientRegistration() client} in the provided {@code context}.
6950
* Returns {@code null} if authorization (or re-authorization) is not supported,
7051
* e.g. the client's {@link ClientRegistration#getAuthorizationGrantType() authorization grant type}
7152
* is not {@link AuthorizationGrantType#CLIENT_CREDENTIALS client_credentials} OR
7253
* the {@link OAuth2AuthorizedClient#getAccessToken() access token} is not expired.
7354
*
74-
* <p>
75-
* The following {@link OAuth2AuthorizationContext#getAttributes() context attributes} are supported:
76-
* <ol>
77-
* <li>{@code "javax.servlet.http.HttpServletRequest"} (required) - the {@code HttpServletRequest}</li>
78-
* <li>{@code "javax.servlet.http.HttpServletResponse"} (required) - the {@code HttpServletResponse}</li>
79-
* </ol>
80-
*
8155
* @param context the context that holds authorization-specific state for the client
8256
* @return the {@link OAuth2AuthorizedClient} or {@code null} if authorization (or re-authorization) is not supported
8357
*/
@@ -86,22 +60,10 @@ public ClientCredentialsOAuth2AuthorizedClientProvider(ClientRegistrationReposit
8660
public OAuth2AuthorizedClient authorize(OAuth2AuthorizationContext context) {
8761
Assert.notNull(context, "context cannot be null");
8862

89-
HttpServletRequest request = context.getAttribute(HTTP_SERVLET_REQUEST_ATTRIBUTE_NAME);
90-
HttpServletResponse response = context.getAttribute(HTTP_SERVLET_RESPONSE_ATTRIBUTE_NAME);
91-
Assert.notNull(request, "The context attribute cannot be null '" + HTTP_SERVLET_REQUEST_ATTRIBUTE_NAME + "'");
92-
Assert.notNull(response, "The context attribute cannot be null '" + HTTP_SERVLET_RESPONSE_ATTRIBUTE_NAME + "'");
93-
94-
String clientRegistrationId = context.getClientRegistrationId();
95-
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId);
96-
Assert.notNull(clientRegistration, "Could not find ClientRegistration with id '" + clientRegistrationId + "'");
97-
98-
if (!AuthorizationGrantType.CLIENT_CREDENTIALS.equals(clientRegistration.getAuthorizationGrantType())) {
99-
return null;
100-
}
101-
102-
OAuth2AuthorizedClient authorizedClient = this.authorizedClientRepository.loadAuthorizedClient(
103-
clientRegistrationId, context.getPrincipal(), request);
104-
if (authorizedClient != null && !hasTokenExpired(authorizedClient.getAccessToken())) {
63+
ClientRegistration clientRegistration = context.getClientRegistration();
64+
OAuth2AuthorizedClient authorizedClient = context.getAuthorizedClient();
65+
if (!AuthorizationGrantType.CLIENT_CREDENTIALS.equals(clientRegistration.getAuthorizationGrantType()) ||
66+
(authorizedClient != null && !hasTokenExpired(authorizedClient.getAccessToken()))) {
10567
return null;
10668
}
10769

@@ -117,13 +79,7 @@ public OAuth2AuthorizedClient authorize(OAuth2AuthorizationContext context) {
11779
OAuth2AccessTokenResponse tokenResponse =
11880
this.accessTokenResponseClient.getTokenResponse(clientCredentialsGrantRequest);
11981

120-
authorizedClient = new OAuth2AuthorizedClient(
121-
clientRegistration, context.getPrincipal().getName(), tokenResponse.getAccessToken());
122-
123-
this.authorizedClientRepository.saveAuthorizedClient(
124-
authorizedClient, context.getPrincipal(), request, response);
125-
126-
return authorizedClient;
82+
return new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(), tokenResponse.getAccessToken());
12783
}
12884

12985
private boolean hasTokenExpired(AbstractOAuth2Token token) {

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/DefaultOAuth2AuthorizedClientProvider.java

Lines changed: 0 additions & 88 deletions
This file was deleted.

0 commit comments

Comments
 (0)