1
1
/*
2
- * Copyright 2002-2022 the original author or authors.
2
+ * Copyright 2002-2023 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
18
18
19
19
import java .util .List ;
20
20
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 ;
21
27
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 ;
22
37
import org .springframework .context .annotation .Configuration ;
23
38
import org .springframework .context .annotation .Import ;
24
39
import org .springframework .context .annotation .ImportSelector ;
40
+ import org .springframework .core .ResolvableType ;
25
41
import org .springframework .core .type .AnnotationMetadata ;
26
42
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 ;
27
46
import org .springframework .security .oauth2 .client .OAuth2AuthorizedClientManager ;
28
47
import org .springframework .security .oauth2 .client .OAuth2AuthorizedClientProvider ;
29
48
import org .springframework .security .oauth2 .client .OAuth2AuthorizedClientProviderBuilder ;
49
+ import org .springframework .security .oauth2 .client .PasswordOAuth2AuthorizedClientProvider ;
50
+ import org .springframework .security .oauth2 .client .RefreshTokenOAuth2AuthorizedClientProvider ;
30
51
import org .springframework .security .oauth2 .client .endpoint .OAuth2AccessTokenResponseClient ;
31
52
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 ;
32
55
import org .springframework .security .oauth2 .client .registration .ClientRegistrationRepository ;
33
56
import org .springframework .security .oauth2 .client .web .DefaultOAuth2AuthorizedClientManager ;
34
57
import org .springframework .security .oauth2 .client .web .OAuth2AuthorizedClientRepository ;
48
71
* @since 5.1
49
72
* @see OAuth2ImportSelector
50
73
*/
51
- @ Import (OAuth2ClientConfiguration .OAuth2ClientWebMvcImportSelector .class )
74
+ @ Import ({ OAuth2ClientConfiguration .OAuth2ClientWebMvcImportSelector .class ,
75
+ OAuth2ClientConfiguration .OAuth2AuthorizedClientManagerConfiguration .class })
52
76
final class OAuth2ClientConfiguration {
53
77
54
78
private static final boolean webMvcPresent ;
@@ -65,8 +89,22 @@ public String[] selectImports(AnnotationMetadata importingClassMetadata) {
65
89
if (!webMvcPresent ) {
66
90
return new String [0 ];
67
91
}
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 ();
70
108
}
71
109
72
110
}
@@ -160,4 +198,136 @@ private OAuth2AuthorizedClientManager getAuthorizedClientManager() {
160
198
161
199
}
162
200
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
+
163
333
}
0 commit comments