Skip to content

Allow customization of redirect strategy #11387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.util.Assert;

Expand Down Expand Up @@ -171,6 +172,8 @@ public final class AuthorizationCodeGrantConfigurer {

private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;

private RedirectStrategy authorizationRedirectStrategy;

private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;

private AuthorizationCodeGrantConfigurer() {
Expand Down Expand Up @@ -202,6 +205,17 @@ public AuthorizationCodeGrantConfigurer authorizationRequestRepository(
return this;
}

/**
* Sets the redirect strategy for Authorization Endpoint redirect URI.
* @param authorizationRedirectStrategy the redirect strategy
* @return the {@link AuthorizationCodeGrantConfigurer} for further configuration
*/
public AuthorizationCodeGrantConfigurer authorizationRedirectStrategy(
RedirectStrategy authorizationRedirectStrategy) {
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
return this;
}

/**
* Sets the client used for requesting the access token credential from the Token
* Endpoint.
Expand Down Expand Up @@ -247,6 +261,9 @@ private OAuth2AuthorizationRequestRedirectFilter createAuthorizationRequestRedir
authorizationRequestRedirectFilter
.setAuthorizationRequestRepository(this.authorizationRequestRepository);
}
if (this.authorizationRedirectStrategy != null) {
authorizationRequestRedirectFilter.setAuthorizationRedirectStrategy(this.authorizationRedirectStrategy);
}
RequestCache requestCache = builder.getSharedObject(RequestCache.class);
if (requestCache != null) {
authorizationRequestRedirectFilter.setRequestCache(requestCache);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
Expand Down Expand Up @@ -367,6 +368,10 @@ public void configure(B http) throws Exception {
authorizationRequestFilter
.setAuthorizationRequestRepository(this.authorizationEndpointConfig.authorizationRequestRepository);
}
if (this.authorizationEndpointConfig.authorizationRedirectStrategy != null) {
authorizationRequestFilter
.setAuthorizationRedirectStrategy(this.authorizationEndpointConfig.authorizationRedirectStrategy);
}
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if (requestCache != null) {
authorizationRequestFilter.setRequestCache(requestCache);
Expand Down Expand Up @@ -539,6 +544,8 @@ public final class AuthorizationEndpointConfig {

private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;

private RedirectStrategy authorizationRedirectStrategy;

private AuthorizationEndpointConfig() {
}

Expand Down Expand Up @@ -581,6 +588,17 @@ public AuthorizationEndpointConfig authorizationRequestRepository(
return this;
}

/**
* Sets the redirect strategy for Authorization Endpoint redirect URI.
* @param authorizationRedirectStrategy the redirect strategy
* @return the {@link AuthorizationEndpointConfig} for further configuration
*/
public AuthorizationEndpointConfig authorizationRedirectStrategy(
RedirectStrategy authorizationRedirectStrategy) {
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
return this;
}

/**
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
* @return the {@link OAuth2LoginConfigurer}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser {

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

private static final String ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF = "authorization-redirect-strategy-ref";

private static final String ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF = "access-token-response-client-ref";

private final BeanReference requestCache;
Expand Down Expand Up @@ -83,6 +85,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
}
BeanMetadataElement authorizationRequestRepository = getAuthorizationRequestRepository(
authorizationCodeGrantElt);
BeanMetadataElement authorizationRedirectStrategy = getAuthorizationRedirectStrategy(authorizationCodeGrantElt);
BeanDefinitionBuilder authorizationRequestRedirectFilterBuilder = BeanDefinitionBuilder
.rootBeanDefinition(OAuth2AuthorizationRequestRedirectFilter.class);
String authorizationRequestResolverRef = (authorizationCodeGrantElt != null)
Expand All @@ -95,6 +98,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
}
this.authorizationRequestRedirectFilter = authorizationRequestRedirectFilterBuilder
.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository)
.addPropertyValue("authorizationRedirectStrategy", authorizationRedirectStrategy)
.addPropertyValue("requestCache", this.requestCache).getBeanDefinition();
BeanDefinitionBuilder authorizationCodeGrantFilterBldr = BeanDefinitionBuilder
.rootBeanDefinition(OAuth2AuthorizationCodeGrantFilter.class)
Expand Down Expand Up @@ -126,6 +130,16 @@ private BeanMetadataElement getAuthorizationRequestRepository(Element element) {
.getBeanDefinition();
}

private BeanMetadataElement getAuthorizationRedirectStrategy(Element element) {
String authorizationRedirectStrategyRef = (element != null)
? element.getAttribute(ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF) : null;
if (StringUtils.hasText(authorizationRedirectStrategyRef)) {
return new RuntimeBeanReference(authorizationRedirectStrategyRef);
}
return BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.DefaultRedirectStrategy")
.getBeanDefinition();
}

private BeanMetadataElement getAccessTokenResponseClient(Element element) {
String accessTokenResponseClientRef = (element != null)
? element.getAttribute(ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {

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

private static final String ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF = "authorization-redirect-strategy-ref";

private static final String ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF = "access-token-response-client-ref";

private static final String ATT_USER_AUTHORITIES_MAPPER_REF = "user-authorities-mapper-ref";
Expand Down Expand Up @@ -199,6 +201,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
}
oauth2AuthorizationRequestRedirectFilterBuilder
.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository)
.addPropertyValue("authorizationRedirectStrategy", getAuthorizationRedirectStrategy(element))
.addPropertyValue("requestCache", this.requestCache);
this.oauth2AuthorizationRequestRedirectFilter = oauth2AuthorizationRequestRedirectFilterBuilder
.getBeanDefinition();
Expand Down Expand Up @@ -261,6 +264,15 @@ private BeanMetadataElement getAuthorizationRequestRepository(Element element) {
.getBeanDefinition();
}

private BeanMetadataElement getAuthorizationRedirectStrategy(Element element) {
String authorizationRedirectStrategyRef = element.getAttribute(ATT_AUTHORIZATION_REDIRECT_STRATEGY_REF);
if (StringUtils.hasText(authorizationRedirectStrategyRef)) {
return new RuntimeBeanReference(authorizationRedirectStrategyRef);
}
return BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.DefaultRedirectStrategy")
.getBeanDefinition();
}

private BeanDefinition getOidcAuthProvider(Element element, BeanMetadataElement accessTokenResponseClient,
String userAuthoritiesMapperRef) {
boolean oidcAuthenticationProviderEnabled = ClassUtils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,14 @@
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor;
import org.springframework.security.web.server.DefaultServerRedirectStrategy;
import org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint;
import org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
import org.springframework.security.web.server.ExchangeMatcherRedirectWebFilter;
import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.security.web.server.ServerRedirectStrategy;
import org.springframework.security.web.server.authentication.AnonymousAuthenticationWebFilter;
import org.springframework.security.web.server.authentication.AuthenticationConverterServerWebExchangeMatcher;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
Expand Down Expand Up @@ -3375,6 +3377,8 @@ public final class OAuth2LoginSpec {

private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver;

private ServerRedirectStrategy authorizationRedirectStrategy;

private ServerWebExchangeMatcher authenticationMatcher;

private ServerAuthenticationSuccessHandler authenticationSuccessHandler;
Expand Down Expand Up @@ -3547,6 +3551,16 @@ public OAuth2LoginSpec authorizationRequestResolver(
return this;
}

/**
* Sets the redirect strategy for Authorization Endpoint redirect URI.
* @param authorizationRedirectStrategy the redirect strategy
* @return the {@link OAuth2LoginSpec} for further configuration
*/
public OAuth2LoginSpec authorizationRedirectStrategy(ServerRedirectStrategy authorizationRedirectStrategy) {
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
return this;
}

/**
* Sets the {@link ServerWebExchangeMatcher matcher} used for determining if the
* request is an authentication request.
Expand Down Expand Up @@ -3581,7 +3595,9 @@ protected void configure(ServerHttpSecurity http) {
OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = getRedirectWebFilter();
ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = getAuthorizationRequestRepository();
oauthRedirectFilter.setAuthorizationRequestRepository(authorizationRequestRepository);
oauthRedirectFilter.setAuthorizationRedirectStrategy(getAuthorizationRedirectStrategy());
oauthRedirectFilter.setRequestCache(http.requestCache.requestCache);

ReactiveAuthenticationManager manager = getAuthenticationManager();
AuthenticationWebFilter authenticationFilter = new OAuth2LoginAuthenticationWebFilter(manager,
authorizedClientRepository);
Expand All @@ -3591,6 +3607,7 @@ protected void configure(ServerHttpSecurity http) {
authenticationFilter.setAuthenticationSuccessHandler(getAuthenticationSuccessHandler(http));
authenticationFilter.setAuthenticationFailureHandler(getAuthenticationFailureHandler());
authenticationFilter.setSecurityContextRepository(this.securityContextRepository);

setDefaultEntryPoints(http);
http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
Expand Down Expand Up @@ -3737,6 +3754,13 @@ private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> getAuth
return this.authorizationRequestRepository;
}

private ServerRedirectStrategy getAuthorizationRedirectStrategy() {
if (this.authorizationRedirectStrategy == null) {
this.authorizationRedirectStrategy = new DefaultServerRedirectStrategy();
}
return this.authorizationRedirectStrategy;
}

private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() {
ReactiveOAuth2AuthorizedClientService bean = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class);
if (bean != null) {
Expand All @@ -3759,6 +3783,8 @@ public final class OAuth2ClientSpec {

private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;

private ServerRedirectStrategy authorizationRedirectStrategy;

private OAuth2ClientSpec() {
}

Expand Down Expand Up @@ -3851,6 +3877,23 @@ private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> getAuth
return this.authorizationRequestRepository;
}

/**
* Sets the redirect strategy for Authorization Endpoint redirect URI.
* @param authorizationRedirectStrategy the redirect strategy
* @return the {@link OAuth2ClientSpec} for further configuration
*/
public OAuth2ClientSpec authorizationRedirectStrategy(ServerRedirectStrategy authorizationRedirectStrategy) {
this.authorizationRedirectStrategy = authorizationRedirectStrategy;
return this;
}

private ServerRedirectStrategy getAuthorizationRedirectStrategy() {
if (this.authorizationRedirectStrategy == null) {
this.authorizationRedirectStrategy = new DefaultServerRedirectStrategy();
}
return this.authorizationRedirectStrategy;
}

/**
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
* @return the {@link ServerHttpSecurity} to continue configuring
Expand All @@ -3870,12 +3913,15 @@ protected void configure(ServerHttpSecurity http) {
if (http.requestCache != null) {
codeGrantWebFilter.setRequestCache(http.requestCache.requestCache);
}

OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter(
clientRegistrationRepository);
oauthRedirectFilter.setAuthorizationRequestRepository(getAuthorizationRequestRepository());
oauthRedirectFilter.setAuthorizationRedirectStrategy(getAuthorizationRedirectStrategy());
if (http.requestCache != null) {
oauthRedirectFilter.setRequestCache(http.requestCache.requestCache);
}

http.addFilterAt(codeGrantWebFilter, SecurityWebFiltersOrder.OAUTH2_AUTHORIZATION_CODE);
http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCo
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
import org.springframework.security.web.RedirectStrategy

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

internal fun get(): (OAuth2ClientConfigurer<HttpSecurity>.AuthorizationCodeGrantConfigurer) -> Unit {
return { authorizationCodeGrant ->
authorizationRequestResolver?.also { authorizationCodeGrant.authorizationRequestResolver(authorizationRequestResolver) }
authorizationRequestRepository?.also { authorizationCodeGrant.authorizationRequestRepository(authorizationRequestRepository) }
authorizationRedirectStrategy?.also { authorizationCodeGrant.authorizationRedirectStrategy(authorizationRedirectStrategy) }
accessTokenResponseClient?.also { authorizationCodeGrant.accessTokenResponseClient(accessTokenResponseClient) }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import org.springframework.security.config.annotation.web.configurers.oauth2.cli
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
import org.springframework.security.web.RedirectStrategy

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

internal fun get(): (OAuth2LoginConfigurer<HttpSecurity>.AuthorizationEndpointConfig) -> Unit {
return { authorizationEndpoint ->
baseUri?.also { authorizationEndpoint.baseUri(baseUri) }
authorizationRequestResolver?.also { authorizationEndpoint.authorizationRequestResolver(authorizationRequestResolver) }
authorizationRequestRepository?.also { authorizationEndpoint.authorizationRequestRepository(authorizationRequestRepository) }
authorizationRedirectStrategy?.also { authorizationEndpoint.authorizationRedirectStrategy(authorizationRedirectStrategy) }
}
}
}
Loading