Skip to content

Commit 7c30285

Browse files
committed
Allow customization of redirect strategy
The default redirect strategy will provide authorization redirect URI within HTTP 302 response Location header. Allowing the configuration of custom redirect strategy will provide an option for the clients to obtain the authorization URI from e.g. HTTP response body as JSON payload, without a need to handle automatic redirection initiated by the HTTP Location header. Closes gh-11373
1 parent 095f23d commit 7c30285

File tree

27 files changed

+710
-2
lines changed

27 files changed

+710
-2
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
3535
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
3636
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
37+
import org.springframework.security.web.RedirectStrategy;
3738
import org.springframework.security.web.savedrequest.RequestCache;
3839
import org.springframework.util.Assert;
3940

@@ -171,6 +172,8 @@ public final class AuthorizationCodeGrantConfigurer {
171172

172173
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
173174

175+
private RedirectStrategy authorizationRedirectStrategy;
176+
174177
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
175178

176179
private AuthorizationCodeGrantConfigurer() {
@@ -202,6 +205,17 @@ public AuthorizationCodeGrantConfigurer authorizationRequestRepository(
202205
return this;
203206
}
204207

208+
/**
209+
* Sets the redirect strategy for Authorization Endpoint redirect URI.
210+
* @param authorizationRedirectStrategy the redirect strategy
211+
* @return the {@link AuthorizationCodeGrantConfigurer} for further configuration
212+
*/
213+
public AuthorizationCodeGrantConfigurer authorizationRedirectStrategy(
214+
RedirectStrategy authorizationRedirectStrategy) {
215+
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
216+
return this;
217+
}
218+
205219
/**
206220
* Sets the client used for requesting the access token credential from the Token
207221
* Endpoint.
@@ -247,6 +261,9 @@ private OAuth2AuthorizationRequestRedirectFilter createAuthorizationRequestRedir
247261
authorizationRequestRedirectFilter
248262
.setAuthorizationRequestRepository(this.authorizationRequestRepository);
249263
}
264+
if (this.authorizationRedirectStrategy != null) {
265+
authorizationRequestRedirectFilter.setAuthorizationRedirectStrategy(this.authorizationRedirectStrategy);
266+
}
250267
RequestCache requestCache = builder.getSharedObject(RequestCache.class);
251268
if (requestCache != null) {
252269
authorizationRequestRedirectFilter.setRequestCache(requestCache);

config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import org.springframework.security.oauth2.core.user.OAuth2User;
6969
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
7070
import org.springframework.security.web.AuthenticationEntryPoint;
71+
import org.springframework.security.web.RedirectStrategy;
7172
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
7273
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
7374
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
@@ -367,6 +368,10 @@ public void configure(B http) throws Exception {
367368
authorizationRequestFilter
368369
.setAuthorizationRequestRepository(this.authorizationEndpointConfig.authorizationRequestRepository);
369370
}
371+
if (this.authorizationEndpointConfig.authorizationRedirectStrategy != null) {
372+
authorizationRequestFilter
373+
.setAuthorizationRedirectStrategy(this.authorizationEndpointConfig.authorizationRedirectStrategy);
374+
}
370375
RequestCache requestCache = http.getSharedObject(RequestCache.class);
371376
if (requestCache != null) {
372377
authorizationRequestFilter.setRequestCache(requestCache);
@@ -539,6 +544,8 @@ public final class AuthorizationEndpointConfig {
539544

540545
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
541546

547+
private RedirectStrategy authorizationRedirectStrategy;
548+
542549
private AuthorizationEndpointConfig() {
543550
}
544551

@@ -581,6 +588,17 @@ public AuthorizationEndpointConfig authorizationRequestRepository(
581588
return this;
582589
}
583590

591+
/**
592+
* Sets the redirect strategy for Authorization Endpoint redirect URI.
593+
* @param authorizationRedirectStrategy the redirect strategy
594+
* @return the {@link AuthorizationEndpointConfig} for further configuration
595+
*/
596+
public AuthorizationEndpointConfig authorizationRedirectStrategy(
597+
RedirectStrategy authorizationRedirectStrategy) {
598+
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
599+
return this;
600+
}
601+
584602
/**
585603
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
586604
* @return the {@link OAuth2LoginConfigurer}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {
4444

4545
private static final String ATT_AUTHORIZATION_REQUEST_RESOLVER_REF = "authorization-request-resolver-ref";
4646

47+
private static final String ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF = "authorization-redirect-strategy-ref";
48+
4749
private static final String ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF = "access-token-response-client-ref";
4850

4951
private final BeanReference requestCache;
@@ -83,6 +85,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
8385
}
8486
BeanMetadataElement authorizationRequestRepository = getAuthorizationRequestRepository(
8587
authorizationCodeGrantElt);
88+
BeanMetadataElement authorizationRedirectStrategy = getAuthorizationRedirectStrategy(authorizationCodeGrantElt);
8689
BeanDefinitionBuilder authorizationRequestRedirectFilterBuilder = BeanDefinitionBuilder
8790
.rootBeanDefinition(OAuth2AuthorizationRequestRedirectFilter.class);
8891
String authorizationRequestResolverRef = (authorizationCodeGrantElt != null)
@@ -95,6 +98,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
9598
}
9699
this.authorizationRequestRedirectFilter = authorizationRequestRedirectFilterBuilder
97100
.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository)
101+
.addPropertyValue("authorizationRedirectStrategy", authorizationRedirectStrategy)
98102
.addPropertyValue("requestCache", this.requestCache).getBeanDefinition();
99103
BeanDefinitionBuilder authorizationCodeGrantFilterBldr = BeanDefinitionBuilder
100104
.rootBeanDefinition(OAuth2AuthorizationCodeGrantFilter.class)
@@ -126,6 +130,16 @@ private BeanMetadataElement getAuthorizationRequestRepository(Element element) {
126130
.getBeanDefinition();
127131
}
128132

133+
private BeanMetadataElement getAuthorizationRedirectStrategy(Element element) {
134+
String authorizationRedirectStrategyRef = (element != null)
135+
? element.getAttribute(ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF) : null;
136+
if (StringUtils.hasText(authorizationRedirectStrategyRef)) {
137+
return new RuntimeBeanReference(authorizationRedirectStrategyRef);
138+
}
139+
return BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.DefaultRedirectStrategy")
140+
.getBeanDefinition();
141+
}
142+
129143
private BeanMetadataElement getAccessTokenResponseClient(Element element) {
130144
String accessTokenResponseClientRef = (element != null)
131145
? element.getAttribute(ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF) : null;

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
8787

8888
private static final String ATT_AUTHORIZATION_REQUEST_RESOLVER_REF = "authorization-request-resolver-ref";
8989

90+
private static final String ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF = "authorization-redirect-strategy-ref";
91+
9092
private static final String ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF = "access-token-response-client-ref";
9193

9294
private static final String ATT_USER_AUTHORITIES_MAPPER_REF = "user-authorities-mapper-ref";
@@ -199,6 +201,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
199201
}
200202
oauth2AuthorizationRequestRedirectFilterBuilder
201203
.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository)
204+
.addPropertyValue("authorizationRedirectStrategy", getAuthorizationRedirectStrategy(element))
202205
.addPropertyValue("requestCache", this.requestCache);
203206
this.oauth2AuthorizationRequestRedirectFilter = oauth2AuthorizationRequestRedirectFilterBuilder
204207
.getBeanDefinition();
@@ -261,6 +264,15 @@ private BeanMetadataElement getAuthorizationRequestRepository(Element element) {
261264
.getBeanDefinition();
262265
}
263266

267+
private BeanMetadataElement getAuthorizationRedirectStrategy(Element element) {
268+
String authorizationRedirectStrategyRef = element.getAttribute(ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF);
269+
if (StringUtils.hasText(authorizationRedirectStrategyRef)) {
270+
return new RuntimeBeanReference(authorizationRedirectStrategyRef);
271+
}
272+
return BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.DefaultRedirectStrategy")
273+
.getBeanDefinition();
274+
}
275+
264276
private BeanDefinition getOidcAuthProvider(Element element, BeanMetadataElement accessTokenResponseClient,
265277
String userAuthoritiesMapperRef) {
266278
boolean oidcAuthenticationProviderEnabled = ClassUtils

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,14 @@
102102
import org.springframework.security.web.PortMapper;
103103
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
104104
import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor;
105+
import org.springframework.security.web.server.DefaultServerRedirectStrategy;
105106
import org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint;
106107
import org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
107108
import org.springframework.security.web.server.ExchangeMatcherRedirectWebFilter;
108109
import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
109110
import org.springframework.security.web.server.SecurityWebFilterChain;
110111
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
112+
import org.springframework.security.web.server.ServerRedirectStrategy;
111113
import org.springframework.security.web.server.authentication.AnonymousAuthenticationWebFilter;
112114
import org.springframework.security.web.server.authentication.AuthenticationConverterServerWebExchangeMatcher;
113115
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
@@ -3375,6 +3377,8 @@ public final class OAuth2LoginSpec {
33753377

33763378
private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver;
33773379

3380+
private ServerRedirectStrategy authorizationRedirectStrategy;
3381+
33783382
private ServerWebExchangeMatcher authenticationMatcher;
33793383

33803384
private ServerAuthenticationSuccessHandler authenticationSuccessHandler;
@@ -3547,6 +3551,16 @@ public OAuth2LoginSpec authorizationRequestResolver(
35473551
return this;
35483552
}
35493553

3554+
/**
3555+
* Sets the redirect strategy for Authorization Endpoint redirect URI.
3556+
* @param authorizationRedirectStrategy the redirect strategy
3557+
* @return the {@link OAuth2LoginSpec} for further configuration
3558+
*/
3559+
public OAuth2LoginSpec authorizationRedirectStrategy(ServerRedirectStrategy authorizationRedirectStrategy) {
3560+
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
3561+
return this;
3562+
}
3563+
35503564
/**
35513565
* Sets the {@link ServerWebExchangeMatcher matcher} used for determining if the
35523566
* request is an authentication request.
@@ -3581,7 +3595,9 @@ protected void configure(ServerHttpSecurity http) {
35813595
OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = getRedirectWebFilter();
35823596
ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = getAuthorizationRequestRepository();
35833597
oauthRedirectFilter.setAuthorizationRequestRepository(authorizationRequestRepository);
3598+
oauthRedirectFilter.setAuthorizationRedirectStrategy(getAuthorizationRedirectStrategy());
35843599
oauthRedirectFilter.setRequestCache(http.requestCache.requestCache);
3600+
35853601
ReactiveAuthenticationManager manager = getAuthenticationManager();
35863602
AuthenticationWebFilter authenticationFilter = new OAuth2LoginAuthenticationWebFilter(manager,
35873603
authorizedClientRepository);
@@ -3591,6 +3607,7 @@ protected void configure(ServerHttpSecurity http) {
35913607
authenticationFilter.setAuthenticationSuccessHandler(getAuthenticationSuccessHandler(http));
35923608
authenticationFilter.setAuthenticationFailureHandler(getAuthenticationFailureHandler());
35933609
authenticationFilter.setSecurityContextRepository(this.securityContextRepository);
3610+
35943611
setDefaultEntryPoints(http);
35953612
http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
35963613
http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
@@ -3737,6 +3754,13 @@ private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> getAuth
37373754
return this.authorizationRequestRepository;
37383755
}
37393756

3757+
private ServerRedirectStrategy getAuthorizationRedirectStrategy() {
3758+
if (this.authorizationRedirectStrategy == null) {
3759+
this.authorizationRedirectStrategy = new DefaultServerRedirectStrategy();
3760+
}
3761+
return this.authorizationRedirectStrategy;
3762+
}
3763+
37403764
private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() {
37413765
ReactiveOAuth2AuthorizedClientService bean = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class);
37423766
if (bean != null) {
@@ -3759,6 +3783,8 @@ public final class OAuth2ClientSpec {
37593783

37603784
private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
37613785

3786+
private ServerRedirectStrategy authorizationRedirectStrategy;
3787+
37623788
private OAuth2ClientSpec() {
37633789
}
37643790

@@ -3851,6 +3877,23 @@ private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> getAuth
38513877
return this.authorizationRequestRepository;
38523878
}
38533879

3880+
/**
3881+
* Sets the redirect strategy for Authorization Endpoint redirect URI.
3882+
* @param authorizationRedirectStrategy the redirect strategy
3883+
* @return the {@link OAuth2ClientSpec} for further configuration
3884+
*/
3885+
public OAuth2ClientSpec authorizationRedirectStrategy(ServerRedirectStrategy authorizationRedirectStrategy) {
3886+
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
3887+
return this;
3888+
}
3889+
3890+
private ServerRedirectStrategy getAuthorizationRedirectStrategy() {
3891+
if (this.authorizationRedirectStrategy == null) {
3892+
this.authorizationRedirectStrategy = new DefaultServerRedirectStrategy();
3893+
}
3894+
return this.authorizationRedirectStrategy;
3895+
}
3896+
38543897
/**
38553898
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
38563899
* @return the {@link ServerHttpSecurity} to continue configuring
@@ -3870,12 +3913,15 @@ protected void configure(ServerHttpSecurity http) {
38703913
if (http.requestCache != null) {
38713914
codeGrantWebFilter.setRequestCache(http.requestCache.requestCache);
38723915
}
3916+
38733917
OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter(
38743918
clientRegistrationRepository);
38753919
oauthRedirectFilter.setAuthorizationRequestRepository(getAuthorizationRequestRepository());
3920+
oauthRedirectFilter.setAuthorizationRedirectStrategy(getAuthorizationRedirectStrategy());
38763921
if (http.requestCache != null) {
38773922
oauthRedirectFilter.setRequestCache(http.requestCache.requestCache);
38783923
}
3924+
38793925
http.addFilterAt(codeGrantWebFilter, SecurityWebFiltersOrder.OAUTH2_AUTHORIZATION_CODE);
38803926
http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
38813927
}

config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/client/AuthorizationCodeGrantDsl.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCo
2323
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
2424
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver
2525
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
26+
import org.springframework.security.web.RedirectStrategy
2627

2728
/**
2829
* A Kotlin DSL to configure OAuth 2.0 Authorization Code Grant.
@@ -31,19 +32,22 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequ
3132
* @since 5.3
3233
* @property authorizationRequestResolver the resolver used for resolving [OAuth2AuthorizationRequest]'s.
3334
* @property authorizationRequestRepository the repository used for storing [OAuth2AuthorizationRequest]'s.
35+
* @property authorizationRedirectStrategy the redirect strategy for Authorization Endpoint redirect URI.
3436
* @property accessTokenResponseClient the client used for requesting the access token credential
3537
* from the Token Endpoint.
3638
*/
3739
@OAuth2ClientSecurityMarker
3840
class AuthorizationCodeGrantDsl {
3941
var authorizationRequestResolver: OAuth2AuthorizationRequestResolver? = null
4042
var authorizationRequestRepository: AuthorizationRequestRepository<OAuth2AuthorizationRequest>? = null
43+
var authorizationRedirectStrategy: RedirectStrategy? = null
4144
var accessTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest>? = null
4245

4346
internal fun get(): (OAuth2ClientConfigurer<HttpSecurity>.AuthorizationCodeGrantConfigurer) -> Unit {
4447
return { authorizationCodeGrant ->
4548
authorizationRequestResolver?.also { authorizationCodeGrant.authorizationRequestResolver(authorizationRequestResolver) }
4649
authorizationRequestRepository?.also { authorizationCodeGrant.authorizationRequestRepository(authorizationRequestRepository) }
50+
authorizationRedirectStrategy?.also { authorizationCodeGrant.authorizationRedirectStrategy(authorizationRedirectStrategy) }
4751
accessTokenResponseClient?.also { authorizationCodeGrant.accessTokenResponseClient(accessTokenResponseClient) }
4852
}
4953
}

config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/login/AuthorizationEndpointDsl.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import org.springframework.security.config.annotation.web.configurers.oauth2.cli
2121
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
2222
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver
2323
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
24+
import org.springframework.security.web.RedirectStrategy
2425

2526
/**
2627
* A Kotlin DSL to configure the Authorization Server's Authorization Endpoint using
@@ -31,18 +32,21 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequ
3132
* @property baseUri the base URI used for authorization requests.
3233
* @property authorizationRequestResolver the resolver used for resolving [OAuth2AuthorizationRequest]'s.
3334
* @property authorizationRequestRepository the repository used for storing [OAuth2AuthorizationRequest]'s.
35+
* @property authorizationRedirectStrategy the redirect strategy for Authorization Endpoint redirect URI.
3436
*/
3537
@OAuth2LoginSecurityMarker
3638
class AuthorizationEndpointDsl {
3739
var baseUri: String? = null
3840
var authorizationRequestResolver: OAuth2AuthorizationRequestResolver? = null
3941
var authorizationRequestRepository: AuthorizationRequestRepository<OAuth2AuthorizationRequest>? = null
42+
var authorizationRedirectStrategy: RedirectStrategy? = null
4043

4144
internal fun get(): (OAuth2LoginConfigurer<HttpSecurity>.AuthorizationEndpointConfig) -> Unit {
4245
return { authorizationEndpoint ->
4346
baseUri?.also { authorizationEndpoint.baseUri(baseUri) }
4447
authorizationRequestResolver?.also { authorizationEndpoint.authorizationRequestResolver(authorizationRequestResolver) }
4548
authorizationRequestRepository?.also { authorizationEndpoint.authorizationRequestRepository(authorizationRequestRepository) }
49+
authorizationRedirectStrategy?.also { authorizationEndpoint.authorizationRedirectStrategy(authorizationRedirectStrategy) }
4650
}
4751
}
4852
}

0 commit comments

Comments
 (0)