Skip to content

Commit af14d76

Browse files
jgrandjaSteve Riesenberg
authored and
Steve Riesenberg
committed
Add OAuth2AuthorizedClientManager Registrar
1 parent 779d472 commit af14d76

File tree

2 files changed

+392
-4
lines changed

2 files changed

+392
-4
lines changed

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

+174-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,17 +18,40 @@
1818

1919
import java.util.List;
2020

21+
import org.springframework.beans.BeanMetadataElement;
22+
import org.springframework.beans.BeansException;
23+
import org.springframework.beans.factory.BeanFactory;
24+
import org.springframework.beans.factory.BeanFactoryAware;
25+
import org.springframework.beans.factory.BeanFactoryUtils;
26+
import org.springframework.beans.factory.ListableBeanFactory;
2127
import org.springframework.beans.factory.annotation.Autowired;
28+
import org.springframework.beans.factory.config.BeanDefinition;
29+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
30+
import org.springframework.beans.factory.config.RuntimeBeanReference;
31+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
32+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
33+
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
34+
import org.springframework.beans.factory.support.ManagedList;
35+
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
36+
import org.springframework.context.annotation.Bean;
2237
import org.springframework.context.annotation.Configuration;
2338
import org.springframework.context.annotation.Import;
2439
import org.springframework.context.annotation.ImportSelector;
40+
import org.springframework.core.ResolvableType;
2541
import org.springframework.core.type.AnnotationMetadata;
2642
import org.springframework.security.core.context.SecurityContextHolderStrategy;
43+
import org.springframework.security.oauth2.client.AuthorizationCodeOAuth2AuthorizedClientProvider;
44+
import org.springframework.security.oauth2.client.ClientCredentialsOAuth2AuthorizedClientProvider;
45+
import org.springframework.security.oauth2.client.DelegatingOAuth2AuthorizedClientProvider;
2746
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
2847
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
2948
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
49+
import org.springframework.security.oauth2.client.PasswordOAuth2AuthorizedClientProvider;
50+
import org.springframework.security.oauth2.client.RefreshTokenOAuth2AuthorizedClientProvider;
3051
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
3152
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
53+
import org.springframework.security.oauth2.client.endpoint.OAuth2PasswordGrantRequest;
54+
import org.springframework.security.oauth2.client.endpoint.OAuth2RefreshTokenGrantRequest;
3255
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
3356
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
3457
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
@@ -48,7 +71,8 @@
4871
* @since 5.1
4972
* @see OAuth2ImportSelector
5073
*/
51-
@Import(OAuth2ClientConfiguration.OAuth2ClientWebMvcImportSelector.class)
74+
@Import({ OAuth2ClientConfiguration.OAuth2ClientWebMvcImportSelector.class,
75+
OAuth2ClientConfiguration.OAuth2AuthorizedClientManagerConfiguration.class })
5276
final class OAuth2ClientConfiguration {
5377

5478
private static final boolean webMvcPresent;
@@ -65,8 +89,22 @@ public String[] selectImports(AnnotationMetadata importingClassMetadata) {
6589
if (!webMvcPresent) {
6690
return new String[0];
6791
}
68-
return new String[] { "org.springframework.security.config.annotation.web.configuration."
69-
+ "OAuth2ClientConfiguration.OAuth2ClientWebMvcSecurityConfiguration" };
92+
return new String[] {
93+
OAuth2ClientConfiguration.class.getName() + ".OAuth2ClientWebMvcSecurityConfiguration" };
94+
}
95+
96+
}
97+
98+
/**
99+
* @author Joe Grandja
100+
* @since 6.2.0
101+
*/
102+
@Configuration(proxyBeanMethods = false)
103+
static class OAuth2AuthorizedClientManagerConfiguration {
104+
105+
@Bean
106+
OAuth2AuthorizedClientManagerRegistrar authorizedClientManagerRegistrar() {
107+
return new OAuth2AuthorizedClientManagerRegistrar();
70108
}
71109

72110
}
@@ -160,4 +198,136 @@ private OAuth2AuthorizedClientManager getAuthorizedClientManager() {
160198

161199
}
162200

201+
/**
202+
* A registrar for registering the default {@link OAuth2AuthorizedClientManager} bean
203+
* definition, if not already present.
204+
*
205+
* @author Joe Grandja
206+
* @since 6.2.0
207+
*/
208+
static class OAuth2AuthorizedClientManagerRegistrar
209+
implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware {
210+
211+
private final AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
212+
213+
private BeanFactory beanFactory;
214+
215+
@Override
216+
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
217+
String[] authorizedClientManagerBeanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
218+
(ListableBeanFactory) this.beanFactory, OAuth2AuthorizedClientManager.class, true, true);
219+
if (authorizedClientManagerBeanNames.length != 0) {
220+
return;
221+
}
222+
223+
String[] clientRegistrationRepositoryBeanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
224+
(ListableBeanFactory) this.beanFactory, ClientRegistrationRepository.class, true, true);
225+
String[] authorizedClientRepositoryBeanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
226+
(ListableBeanFactory) this.beanFactory, OAuth2AuthorizedClientRepository.class, true, true);
227+
if (clientRegistrationRepositoryBeanNames.length != 1 || authorizedClientRepositoryBeanNames.length != 1) {
228+
return;
229+
}
230+
231+
BeanDefinition beanDefinition = BeanDefinitionBuilder
232+
.genericBeanDefinition(DefaultOAuth2AuthorizedClientManager.class)
233+
.addConstructorArgReference(clientRegistrationRepositoryBeanNames[0])
234+
.addConstructorArgReference(authorizedClientRepositoryBeanNames[0])
235+
.addPropertyValue("authorizedClientProvider", getAuthorizedClientProvider()).getBeanDefinition();
236+
237+
registry.registerBeanDefinition(this.beanNameGenerator.generateBeanName(beanDefinition, registry),
238+
beanDefinition);
239+
}
240+
241+
@Override
242+
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
243+
}
244+
245+
private BeanDefinition getAuthorizedClientProvider() {
246+
ManagedList<Object> authorizedClientProviders = new ManagedList<>();
247+
authorizedClientProviders.add(getAuthorizationCodeAuthorizedClientProvider());
248+
authorizedClientProviders.add(getRefreshTokenAuthorizedClientProvider());
249+
authorizedClientProviders.add(getClientCredentialsAuthorizedClientProvider());
250+
authorizedClientProviders.add(getPasswordAuthorizedClientProvider());
251+
return BeanDefinitionBuilder.genericBeanDefinition(DelegatingOAuth2AuthorizedClientProvider.class)
252+
.addConstructorArgValue(authorizedClientProviders).getBeanDefinition();
253+
}
254+
255+
private BeanMetadataElement getAuthorizationCodeAuthorizedClientProvider() {
256+
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
257+
(ListableBeanFactory) this.beanFactory, AuthorizationCodeOAuth2AuthorizedClientProvider.class, true,
258+
true);
259+
if (beanNames.length == 1) {
260+
return new RuntimeBeanReference(beanNames[0]);
261+
}
262+
263+
return BeanDefinitionBuilder.genericBeanDefinition(AuthorizationCodeOAuth2AuthorizedClientProvider.class)
264+
.getBeanDefinition();
265+
}
266+
267+
private BeanMetadataElement getRefreshTokenAuthorizedClientProvider() {
268+
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
269+
(ListableBeanFactory) this.beanFactory, RefreshTokenOAuth2AuthorizedClientProvider.class, true,
270+
true);
271+
if (beanNames.length == 1) {
272+
return new RuntimeBeanReference(beanNames[0]);
273+
}
274+
275+
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
276+
.genericBeanDefinition(RefreshTokenOAuth2AuthorizedClientProvider.class);
277+
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(OAuth2AccessTokenResponseClient.class,
278+
OAuth2RefreshTokenGrantRequest.class);
279+
beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors((ListableBeanFactory) this.beanFactory,
280+
resolvableType, true, true);
281+
if (beanNames.length == 1) {
282+
beanDefinitionBuilder.addPropertyReference("accessTokenResponseClient", beanNames[0]);
283+
}
284+
return beanDefinitionBuilder.getBeanDefinition();
285+
}
286+
287+
private BeanMetadataElement getClientCredentialsAuthorizedClientProvider() {
288+
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
289+
(ListableBeanFactory) this.beanFactory, ClientCredentialsOAuth2AuthorizedClientProvider.class, true,
290+
true);
291+
if (beanNames.length == 1) {
292+
return new RuntimeBeanReference(beanNames[0]);
293+
}
294+
295+
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
296+
.genericBeanDefinition(ClientCredentialsOAuth2AuthorizedClientProvider.class);
297+
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(OAuth2AccessTokenResponseClient.class,
298+
OAuth2ClientCredentialsGrantRequest.class);
299+
beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors((ListableBeanFactory) this.beanFactory,
300+
resolvableType, true, true);
301+
if (beanNames.length == 1) {
302+
beanDefinitionBuilder.addPropertyReference("accessTokenResponseClient", beanNames[0]);
303+
}
304+
return beanDefinitionBuilder.getBeanDefinition();
305+
}
306+
307+
private BeanMetadataElement getPasswordAuthorizedClientProvider() {
308+
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
309+
(ListableBeanFactory) this.beanFactory, PasswordOAuth2AuthorizedClientProvider.class, true, true);
310+
if (beanNames.length == 1) {
311+
return new RuntimeBeanReference(beanNames[0]);
312+
}
313+
314+
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
315+
.genericBeanDefinition(PasswordOAuth2AuthorizedClientProvider.class);
316+
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(OAuth2AccessTokenResponseClient.class,
317+
OAuth2PasswordGrantRequest.class);
318+
beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors((ListableBeanFactory) this.beanFactory,
319+
resolvableType, true, true);
320+
if (beanNames.length == 1) {
321+
beanDefinitionBuilder.addPropertyReference("accessTokenResponseClient", beanNames[0]);
322+
}
323+
return beanDefinitionBuilder.getBeanDefinition();
324+
}
325+
326+
@Override
327+
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
328+
this.beanFactory = beanFactory;
329+
}
330+
331+
}
332+
163333
}

0 commit comments

Comments
 (0)