Skip to content

Commit 2431dd1

Browse files
author
Steve Riesenberg
committed
Merge branch '5.8.x'
2 parents b65b59d + 355ef21 commit 2431dd1

File tree

19 files changed

+552
-45
lines changed

19 files changed

+552
-45
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
4545
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
4646
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
47+
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter;
4748
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
4849
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
4950
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
@@ -105,8 +106,8 @@
105106
* </ul>
106107
*
107108
* <p>
108-
* When using {@link #opaqueToken(Customizer)}, supply an introspection endpoint and its
109-
* authentication configuration
109+
* When using {@link #opaqueToken(Customizer)}, supply an introspection endpoint with its
110+
* client credentials and an OpaqueTokenAuthenticationConverter
110111
* </p>
111112
*
112113
* <h2>Security Filters</h2>
@@ -136,6 +137,7 @@
136137
*
137138
* @author Josh Cummings
138139
* @author Evgeniy Cheban
140+
* @author Jerome Wacongne &lt;[email protected]&gt;
139141
* @since 5.1
140142
* @see BearerTokenAuthenticationFilter
141143
* @see JwtAuthenticationProvider
@@ -448,6 +450,8 @@ public class OpaqueTokenConfigurer {
448450

449451
private Supplier<OpaqueTokenIntrospector> introspector;
450452

453+
private OpaqueTokenAuthenticationConverter authenticationConverter;
454+
451455
OpaqueTokenConfigurer(ApplicationContext context) {
452456
this.context = context;
453457
}
@@ -482,19 +486,42 @@ public OpaqueTokenConfigurer introspector(OpaqueTokenIntrospector introspector)
482486
return this;
483487
}
484488

489+
public OpaqueTokenConfigurer authenticationConverter(
490+
OpaqueTokenAuthenticationConverter authenticationConverter) {
491+
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
492+
this.authenticationConverter = authenticationConverter;
493+
return this;
494+
}
495+
485496
OpaqueTokenIntrospector getIntrospector() {
486497
if (this.introspector != null) {
487498
return this.introspector.get();
488499
}
489500
return this.context.getBean(OpaqueTokenIntrospector.class);
490501
}
491502

503+
OpaqueTokenAuthenticationConverter getAuthenticationConverter() {
504+
if (this.authenticationConverter != null) {
505+
return this.authenticationConverter;
506+
}
507+
if (this.context.getBeanNamesForType(OpaqueTokenAuthenticationConverter.class).length > 0) {
508+
return this.context.getBean(OpaqueTokenAuthenticationConverter.class);
509+
}
510+
return null;
511+
}
512+
492513
AuthenticationProvider getAuthenticationProvider() {
493514
if (this.authenticationManager != null) {
494515
return null;
495516
}
496517
OpaqueTokenIntrospector introspector = getIntrospector();
497-
return new OpaqueTokenAuthenticationProvider(introspector);
518+
OpaqueTokenAuthenticationProvider opaqueTokenAuthenticationProvider = new OpaqueTokenAuthenticationProvider(
519+
introspector);
520+
OpaqueTokenAuthenticationConverter authenticationConverter = getAuthenticationConverter();
521+
if (authenticationConverter != null) {
522+
opaqueTokenAuthenticationProvider.setAuthenticationConverter(authenticationConverter);
523+
}
524+
return opaqueTokenAuthenticationProvider;
498525
}
499526

500527
AuthenticationManager getAuthenticationManager(H http) {

config/src/main/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParser.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,24 @@ static final class OpaqueTokenBeanDefinitionParser implements BeanDefinitionPars
244244

245245
static final String CLIENT_SECRET = "client-secret";
246246

247+
static final String AUTHENTICATION_CONVERTER_REF = "authentication-converter-ref";
248+
249+
static final String AUTHENTICATION_CONVERTER = "authenticationConverter";
250+
247251
OpaqueTokenBeanDefinitionParser() {
248252
}
249253

250254
@Override
251255
public BeanDefinition parse(Element element, ParserContext pc) {
252256
validateConfiguration(element, pc);
253257
BeanMetadataElement introspector = getIntrospector(element);
258+
String authenticationConverterRef = element.getAttribute(AUTHENTICATION_CONVERTER_REF);
254259
BeanDefinitionBuilder opaqueTokenProviderBuilder = BeanDefinitionBuilder
255260
.rootBeanDefinition(OpaqueTokenAuthenticationProvider.class);
256261
opaqueTokenProviderBuilder.addConstructorArgValue(introspector);
262+
if (StringUtils.hasText(authenticationConverterRef)) {
263+
opaqueTokenProviderBuilder.addPropertyReference(AUTHENTICATION_CONVERTER, authenticationConverterRef);
264+
}
257265
return opaqueTokenProviderBuilder.getBeanDefinition();
258266
}
259267

config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -95,6 +95,7 @@
9595
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenReactiveAuthenticationManager;
9696
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter;
9797
import org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOpaqueTokenIntrospector;
98+
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenAuthenticationConverter;
9899
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
99100
import org.springframework.security.oauth2.server.resource.web.access.server.BearerTokenServerAccessDeniedHandler;
100101
import org.springframework.security.oauth2.server.resource.web.server.BearerTokenServerAuthenticationEntryPoint;
@@ -4285,6 +4286,8 @@ public final class OpaqueTokenSpec {
42854286

42864287
private Supplier<ReactiveOpaqueTokenIntrospector> introspector;
42874288

4289+
private ReactiveOpaqueTokenAuthenticationConverter authenticationConverter;
4290+
42884291
private OpaqueTokenSpec() {
42894292
}
42904293

@@ -4323,6 +4326,13 @@ public OpaqueTokenSpec introspector(ReactiveOpaqueTokenIntrospector introspector
43234326
return this;
43244327
}
43254328

4329+
public OpaqueTokenSpec authenticationConverter(
4330+
ReactiveOpaqueTokenAuthenticationConverter authenticationConverter) {
4331+
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
4332+
this.authenticationConverter = authenticationConverter;
4333+
return this;
4334+
}
4335+
43264336
/**
43274337
* Allows method chaining to continue configuring the
43284338
* {@link ServerHttpSecurity}
@@ -4333,7 +4343,13 @@ public OAuth2ResourceServerSpec and() {
43334343
}
43344344

43354345
protected ReactiveAuthenticationManager getAuthenticationManager() {
4336-
return new OpaqueTokenReactiveAuthenticationManager(getIntrospector());
4346+
OpaqueTokenReactiveAuthenticationManager authenticationManager = new OpaqueTokenReactiveAuthenticationManager(
4347+
getIntrospector());
4348+
ReactiveOpaqueTokenAuthenticationConverter authenticationConverter = getAuthenticationConverter();
4349+
if (authenticationConverter != null) {
4350+
authenticationManager.setAuthenticationConverter(authenticationConverter);
4351+
}
4352+
return authenticationManager;
43374353
}
43384354

43394355
protected ReactiveOpaqueTokenIntrospector getIntrospector() {
@@ -4343,6 +4359,13 @@ protected ReactiveOpaqueTokenIntrospector getIntrospector() {
43434359
return getBean(ReactiveOpaqueTokenIntrospector.class);
43444360
}
43454361

4362+
protected ReactiveOpaqueTokenAuthenticationConverter getAuthenticationConverter() {
4363+
if (this.authenticationConverter != null) {
4364+
return this.authenticationConverter;
4365+
}
4366+
return getBeanOrNull(ReactiveOpaqueTokenAuthenticationConverter.class);
4367+
}
4368+
43464369
protected void configure(ServerHttpSecurity http) {
43474370
ReactiveAuthenticationManager authenticationManager = getAuthenticationManager();
43484371
AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager);

config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/resourceserver/OpaqueTokenDsl.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -20,6 +20,7 @@ import org.springframework.security.authentication.AuthenticationManager
2020
import org.springframework.security.config.annotation.web.builders.HttpSecurity
2121
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer
2222
import org.springframework.security.core.Authentication
23+
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter
2324
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector
2425

2526
/**
@@ -54,6 +55,7 @@ class OpaqueTokenDsl {
5455
clientCredentials = null
5556
}
5657

58+
var authenticationConverter: OpaqueTokenAuthenticationConverter? = null
5759

5860
/**
5961
* Configures the credentials for Introspection endpoint.
@@ -70,6 +72,7 @@ class OpaqueTokenDsl {
7072
return { opaqueToken ->
7173
introspectionUri?.also { opaqueToken.introspectionUri(introspectionUri) }
7274
introspector?.also { opaqueToken.introspector(introspector) }
75+
authenticationConverter?.also { opaqueToken.authenticationConverter(authenticationConverter) }
7376
clientCredentials?.also { opaqueToken.introspectionClientCredentials(clientCredentials!!.first, clientCredentials!!.second) }
7477
authenticationManager?.also { opaqueToken.authenticationManager(authenticationManager) }
7578
}

config/src/main/kotlin/org/springframework/security/config/web/server/ServerOpaqueTokenDsl.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.security.config.web.server
1818

19+
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenAuthenticationConverter
1920
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector
2021

2122
/**
@@ -45,6 +46,7 @@ class ServerOpaqueTokenDsl {
4546
_introspectionUri = null
4647
clientCredentials = null
4748
}
49+
var authenticationConverter: ReactiveOpaqueTokenAuthenticationConverter? = null
4850

4951
/**
5052
* Configures the credentials for Introspection endpoint.
@@ -62,6 +64,7 @@ class ServerOpaqueTokenDsl {
6264
introspectionUri?.also { opaqueToken.introspectionUri(introspectionUri) }
6365
clientCredentials?.also { opaqueToken.introspectionClientCredentials(clientCredentials!!.first, clientCredentials!!.second) }
6466
introspector?.also { opaqueToken.introspector(introspector) }
67+
authenticationConverter?.also { opaqueToken.authenticationConverter(authenticationConverter) }
6568
}
6669
}
6770
}

config/src/main/resources/org/springframework/security/config/spring-security-5.8.rnc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,9 @@ opaque-token.attlist &=
667667
opaque-token.attlist &=
668668
## Reference to an OpaqueTokenIntrospector
669669
attribute introspector-ref {xsd:token}?
670+
opaque-token.attlist &=
671+
## Reference to an OpaqueTokenAuthenticationConverter responsible for converting successful introspection result into an Authentication.
672+
attribute authentication-converter-ref {xsd:token}?
670673

671674
openid-login =
672675
## Sets up form login for authentication with an Open ID identity. NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated and users are <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is supported by <code>spring-security-oauth2</code>.

config/src/main/resources/org/springframework/security/config/spring-security-5.8.xsd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,13 @@
20602060
</xs:documentation>
20612061
</xs:annotation>
20622062
</xs:attribute>
2063+
<xs:attribute name="authentication-converter-ref" type="xs:token">
2064+
<xs:annotation>
2065+
<xs:documentation>Reference to an OpaqueTokenAuthenticationConverter responsible for converting successful
2066+
introspection result into an Authentication.
2067+
</xs:documentation>
2068+
</xs:annotation>
2069+
</xs:attribute>
20632070
</xs:attributeGroup>
20642071

20652072
<xs:element name="attribute-exchange">

config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
import org.springframework.security.authentication.AuthenticationManagerResolver;
8181
import org.springframework.security.authentication.AuthenticationProvider;
8282
import org.springframework.security.authentication.AuthenticationServiceException;
83+
import org.springframework.security.authentication.TestingAuthenticationToken;
8384
import org.springframework.security.config.annotation.ObjectPostProcessor;
8485
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
8586
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
@@ -98,6 +99,7 @@
9899
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
99100
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
100101
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
102+
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
101103
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
102104
import org.springframework.security.oauth2.core.OAuth2Error;
103105
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
@@ -116,6 +118,7 @@
116118
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
117119
import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver;
118120
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
121+
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter;
119122
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
120123
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
121124
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
@@ -1353,6 +1356,22 @@ public void getJwtAuthenticationConverterWhenDuplicateConverterBeansThenThrowsEx
13531356
.isThrownBy(jwtConfigurer::getJwtAuthenticationConverter);
13541357
}
13551358

1359+
@Test
1360+
public void getWhenCustomAuthenticationConverterThenConverts() throws Exception {
1361+
this.spring.register(RestOperationsConfig.class, OpaqueTokenAuthenticationConverterConfig.class,
1362+
BasicController.class).autowire();
1363+
OpaqueTokenAuthenticationConverter authenticationConverter = this.spring.getContext()
1364+
.getBean(OpaqueTokenAuthenticationConverter.class);
1365+
given(authenticationConverter.convert(anyString(), any(OAuth2AuthenticatedPrincipal.class)))
1366+
.willReturn(new TestingAuthenticationToken("jdoe", null, Collections.emptyList()));
1367+
mockRestOperations(json("Active"));
1368+
// @formatter:off
1369+
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
1370+
.andExpect(status().isOk())
1371+
.andExpect(content().string("jdoe"));
1372+
// @formatter:on
1373+
}
1374+
13561375
private static <T> void registerMockBean(GenericApplicationContext context, String name, Class<T> clazz) {
13571376
context.registerBean(name, clazz, () -> mock(clazz));
13581377
}
@@ -2444,6 +2463,30 @@ protected void configure(HttpSecurity http) throws Exception {
24442463

24452464
}
24462465

2466+
@EnableWebSecurity
2467+
static class OpaqueTokenAuthenticationConverterConfig extends WebSecurityConfigurerAdapter {
2468+
2469+
@Override
2470+
protected void configure(HttpSecurity http) throws Exception {
2471+
// @formatter:off
2472+
http
2473+
.authorizeRequests()
2474+
.antMatchers("/requires-read-scope").hasAuthority("SCOPE_message:read")
2475+
.anyRequest().authenticated()
2476+
.and()
2477+
.oauth2ResourceServer()
2478+
.opaqueToken()
2479+
.authenticationConverter(authenticationConverter());
2480+
// @formatter:on
2481+
}
2482+
2483+
@Bean
2484+
OpaqueTokenAuthenticationConverter authenticationConverter() {
2485+
return mock(OpaqueTokenAuthenticationConverter.class);
2486+
}
2487+
2488+
}
2489+
24472490
@Configuration
24482491
static class JwtDecoderConfig {
24492492

0 commit comments

Comments
 (0)