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
This commit is contained in:
Igor Bolic
2022-06-17 09:42:50 +02:00
committed by Rob Winch
parent c9f8d2b111
commit efaee4e56b
27 changed files with 712 additions and 2 deletions

View File

@@ -59,6 +59,8 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@@ -69,6 +71,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -96,6 +99,8 @@ public class OAuth2ClientConfigurerTests {
private static OAuth2AuthorizationRequestResolver authorizationRequestResolver;
private static RedirectStrategy authorizationRedirectStrategy;
private static OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
private static RequestCache requestCache;
@@ -131,6 +136,7 @@ public class OAuth2ClientConfigurerTests {
authorizedClientService);
authorizationRequestResolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository,
"/oauth2/authorization");
authorizationRedirectStrategy = new DefaultRedirectStrategy();
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("access-token-1234")
.tokenType(OAuth2AccessToken.TokenType.BEARER).expiresIn(300).build();
accessTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class);
@@ -262,6 +268,19 @@ public class OAuth2ClientConfigurerTests {
verify(authorizationRequestResolver).resolve(any());
}
@Test
public void configureWhenCustomAuthorizationRedirectStrategySetThenAuthorizationRedirectStrategyUsed()
throws Exception {
authorizationRedirectStrategy = mock(RedirectStrategy.class);
this.spring.register(OAuth2ClientConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/oauth2/authorization/registration-1"))
.andExpect(status().isOk())
.andReturn();
// @formatter:on
verify(authorizationRedirectStrategy).sendRedirect(any(), any(), anyString());
}
@EnableWebSecurity
@EnableWebMvc
static class OAuth2ClientConfig extends WebSecurityConfigurerAdapter {
@@ -279,6 +298,7 @@ public class OAuth2ClientConfigurerTests {
.oauth2Client()
.authorizationCodeGrant()
.authorizationRequestResolver(authorizationRequestResolver)
.authorizationRedirectStrategy(authorizationRedirectStrategy)
.accessTokenResponseClient(accessTokenResponseClient);
// @formatter:on
}

View File

@@ -90,6 +90,7 @@ import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
import org.springframework.security.oauth2.jwt.TestJwts;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
@@ -101,7 +102,9 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -382,6 +385,32 @@ public class OAuth2LoginConfigurerTests {
"https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1");
}
@Test
public void oauth2LoginWithAuthorizationRedirectStrategyThenCustomAuthorizationRedirectStrategyUsed()
throws Exception {
loadConfig(OAuth2LoginConfigCustomAuthorizationRedirectStrategy.class);
RedirectStrategy redirectStrategy = this.context
.getBean(OAuth2LoginConfigCustomAuthorizationRedirectStrategy.class).redirectStrategy;
String requestUri = "/oauth2/authorization/google";
this.request = new MockHttpServletRequest("GET", requestUri);
this.request.setServletPath(requestUri);
this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
then(redirectStrategy).should().sendRedirect(any(), any(), anyString());
}
@Test
public void requestWhenOauth2LoginWithCustomAuthorizationRedirectStrategyThenCustomAuthorizationRedirectStrategyUsed()
throws Exception {
loadConfig(OAuth2LoginConfigCustomAuthorizationRedirectStrategyInLambda.class);
RedirectStrategy redirectStrategy = this.context
.getBean(OAuth2LoginConfigCustomAuthorizationRedirectStrategyInLambda.class).redirectStrategy;
String requestUri = "/oauth2/authorization/google";
this.request = new MockHttpServletRequest("GET", requestUri);
this.request.setServletPath(requestUri);
this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
then(redirectStrategy).should().sendRedirect(any(), any(), anyString());
}
// gh-5347
@Test
public void oauth2LoginWithOneClientConfiguredThenRedirectForAuthorization() throws Exception {
@@ -883,6 +912,59 @@ public class OAuth2LoginConfigurerTests {
}
@EnableWebSecurity
static class OAuth2LoginConfigCustomAuthorizationRedirectStrategy extends CommonWebSecurityConfigurerAdapter {
private final ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository(
GOOGLE_CLIENT_REGISTRATION);
RedirectStrategy redirectStrategy = mock(RedirectStrategy.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.oauth2Login((oauth2Login) ->
oauth2Login
.clientRegistrationRepository(this.clientRegistrationRepository)
.authorizationEndpoint((authorizationEndpoint) ->
authorizationEndpoint
.authorizationRedirectStrategy(this.redirectStrategy)
)
);
// @formatter:on
super.configure(http);
}
}
@EnableWebSecurity
static class OAuth2LoginConfigCustomAuthorizationRedirectStrategyInLambda
extends CommonLambdaWebSecurityConfigurerAdapter {
private final ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository(
GOOGLE_CLIENT_REGISTRATION);
RedirectStrategy redirectStrategy = mock(RedirectStrategy.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.oauth2Login((oauth2Login) ->
oauth2Login
.clientRegistrationRepository(this.clientRegistrationRepository)
.authorizationEndpoint((authorizationEndpoint) ->
authorizationEndpoint
.authorizationRedirectStrategy(this.redirectStrategy)
)
);
// @formatter:on
super.configure(http);
}
}
@EnableWebSecurity
static class OAuth2LoginConfigMultipleClients extends CommonWebSecurityConfigurerAdapter {

View File

@@ -44,6 +44,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses;
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@@ -55,6 +56,7 @@ import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -90,6 +92,9 @@ public class OAuth2ClientBeanDefinitionParserTests {
@Autowired(required = false)
private OAuth2AuthorizationRequestResolver authorizationRequestResolver;
@Autowired(required = false)
private RedirectStrategy authorizationRedirectStrategy;
@Autowired(required = false)
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
@@ -148,6 +153,16 @@ public class OAuth2ClientBeanDefinitionParserTests {
verify(this.authorizationRequestResolver).resolve(any());
}
@Test
public void requestWhenCustomAuthorizationRedirectStrategyThenCalled() throws Exception {
this.spring.configLocations(xml("CustomAuthorizationRedirectStrategy")).autowire();
// @formatter:off
this.mvc.perform(get("/oauth2/authorization/google"))
.andExpect(status().isOk());
// @formatter:on
verify(this.authorizationRedirectStrategy).sendRedirect(any(), any(), anyString());
}
@Test
public void requestWhenAuthorizationResponseMatchThenProcess() throws Exception {
this.spring.configLocations(xml("CustomConfiguration")).autowire();

View File

@@ -64,6 +64,7 @@ import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
import org.springframework.security.oauth2.jwt.TestJwts;
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.RequestCache;
@@ -78,6 +79,7 @@ import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.times;
@@ -118,6 +120,9 @@ public class OAuth2LoginBeanDefinitionParserTests {
@Autowired(required = false)
private OAuth2AuthorizationRequestResolver authorizationRequestResolver;
@Autowired(required = false)
private RedirectStrategy authorizationRedirectStrategy;
@Autowired(required = false)
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
@@ -378,6 +383,17 @@ public class OAuth2LoginBeanDefinitionParserTests {
verify(this.authorizationRequestResolver).resolve(any());
}
@Test
public void requestWhenCustomAuthorizationRedirectStrategyThenCalled() throws Exception {
this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomAuthorizationRedirectStrategy"))
.autowire();
// @formatter:off
this.mvc.perform(get("/oauth2/authorization/google-login"))
.andExpect(status().isOk());
// @formatter:on
verify(this.authorizationRedirectStrategy).sendRedirect(any(), any(), anyString());
}
// gh-5347
@Test
public void requestWhenMultiClientRegistrationThenRedirectDefaultLoginPage() throws Exception {

View File

@@ -39,14 +39,18 @@ import org.springframework.security.config.annotation.web.reactive.ServerHttpSec
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
import org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationRequestRedirectWebFilter;
import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository;
import org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests;
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor;
import org.springframework.security.web.server.DefaultServerRedirectStrategy;
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.WebFilterChainProxy;
import org.springframework.security.web.server.authentication.AnonymousAuthenticationWebFilterTests;
import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
@@ -76,6 +80,7 @@ import org.springframework.web.server.WebFilterChain;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -531,6 +536,90 @@ public class ServerHttpSecurityTests {
verify(authorizationRequestRepository).removeAuthorizationRequest(any());
}
@Test
public void shouldUseDefaultAuthorizationRedirectStrategyForOAuth2Login() {
ReactiveClientRegistrationRepository clientRegistrationRepository = mock(
ReactiveClientRegistrationRepository.class);
given(clientRegistrationRepository.findByRegistrationId(anyString()))
.willReturn(Mono.just(TestClientRegistrations.clientRegistration().build()));
SecurityWebFilterChain securityFilterChain = this.http.oauth2Login()
.clientRegistrationRepository(clientRegistrationRepository).and().build();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build();
client.get().uri("/oauth2/authorization/registration-id").exchange().expectStatus().is3xxRedirection();
OAuth2AuthorizationRequestRedirectWebFilter filter = getWebFilter(securityFilterChain,
OAuth2AuthorizationRequestRedirectWebFilter.class).get();
assertThat(ReflectionTestUtils.getField(filter, "authorizationRedirectStrategy"))
.isInstanceOf(DefaultServerRedirectStrategy.class);
}
@Test
public void shouldConfigureAuthorizationRedirectStrategyForOAuth2Login() {
ServerRedirectStrategy authorizationRedirectStrategy = mock(ServerRedirectStrategy.class);
ReactiveClientRegistrationRepository clientRegistrationRepository = mock(
ReactiveClientRegistrationRepository.class);
given(clientRegistrationRepository.findByRegistrationId(anyString()))
.willReturn(Mono.just(TestClientRegistrations.clientRegistration().build()));
given(authorizationRedirectStrategy.sendRedirect(any(), any())).willReturn(Mono.empty());
SecurityWebFilterChain securityFilterChain = this.http.oauth2Login()
.clientRegistrationRepository(clientRegistrationRepository)
.authorizationRedirectStrategy(authorizationRedirectStrategy).and().build();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build();
client.get().uri("/oauth2/authorization/registration-id").exchange();
verify(authorizationRedirectStrategy).sendRedirect(any(), any());
OAuth2AuthorizationRequestRedirectWebFilter filter = getWebFilter(securityFilterChain,
OAuth2AuthorizationRequestRedirectWebFilter.class).get();
assertThat(ReflectionTestUtils.getField(filter, "authorizationRedirectStrategy"))
.isSameAs(authorizationRedirectStrategy);
}
@Test
public void shouldUseDefaultAuthorizationRedirectStrategyForOAuth2Client() {
ReactiveClientRegistrationRepository clientRegistrationRepository = mock(
ReactiveClientRegistrationRepository.class);
given(clientRegistrationRepository.findByRegistrationId(anyString()))
.willReturn(Mono.just(TestClientRegistrations.clientRegistration().build()));
SecurityWebFilterChain securityFilterChain = this.http.oauth2Client()
.clientRegistrationRepository(clientRegistrationRepository).and().build();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build();
client.get().uri("/oauth2/authorization/registration-id").exchange().expectStatus().is3xxRedirection();
OAuth2AuthorizationRequestRedirectWebFilter filter = getWebFilter(securityFilterChain,
OAuth2AuthorizationRequestRedirectWebFilter.class).get();
assertThat(ReflectionTestUtils.getField(filter, "authorizationRedirectStrategy"))
.isInstanceOf(DefaultServerRedirectStrategy.class);
}
@Test
public void shouldConfigureAuthorizationRedirectStrategyForOAuth2Client() {
ServerRedirectStrategy authorizationRedirectStrategy = mock(ServerRedirectStrategy.class);
ReactiveClientRegistrationRepository clientRegistrationRepository = mock(
ReactiveClientRegistrationRepository.class);
given(clientRegistrationRepository.findByRegistrationId(anyString()))
.willReturn(Mono.just(TestClientRegistrations.clientRegistration().build()));
given(authorizationRedirectStrategy.sendRedirect(any(), any())).willReturn(Mono.empty());
SecurityWebFilterChain securityFilterChain = this.http.oauth2Client()
.clientRegistrationRepository(clientRegistrationRepository)
.authorizationRedirectStrategy(authorizationRedirectStrategy).and().build();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build();
client.get().uri("/oauth2/authorization/registration-id").exchange();
verify(authorizationRedirectStrategy).sendRedirect(any(), any());
OAuth2AuthorizationRequestRedirectWebFilter filter = getWebFilter(securityFilterChain,
OAuth2AuthorizationRequestRedirectWebFilter.class).get();
assertThat(ReflectionTestUtils.getField(filter, "authorizationRedirectStrategy"))
.isSameAs(authorizationRedirectStrategy);
}
private boolean isX509Filter(WebFilter filter) {
try {
Object converter = ReflectionTestUtils.getField(filter, "authenticationConverter");

View File

@@ -37,7 +37,9 @@ import org.springframework.security.oauth2.client.web.server.ServerAuthorization
import org.springframework.security.oauth2.client.web.server.WebSessionOAuth2ServerAuthorizationRequestRepository
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
import org.springframework.security.web.server.DefaultServerRedirectStrategy
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.ServerRedirectStrategy
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.web.reactive.config.EnableWebFlux
@@ -128,6 +130,41 @@ class ServerOAuth2ClientDslTests {
}
}
@Test
fun `OAuth2 client when authorization redirect strategy configured then custom redirect strategy used`() {
this.spring.register(AuthorizationRedirectStrategyConfig::class.java, ClientConfig::class.java).autowire()
mockkObject(AuthorizationRedirectStrategyConfig.AUTHORIZATION_REDIRECT_STRATEGY)
every {
AuthorizationRedirectStrategyConfig.AUTHORIZATION_REDIRECT_STRATEGY.sendRedirect(any(), any())
} returns Mono.empty()
this.client.get()
.uri("/oauth2/authorization/google")
.exchange()
verify(exactly = 1) {
AuthorizationRedirectStrategyConfig.AUTHORIZATION_REDIRECT_STRATEGY.sendRedirect(any(), any())
}
}
@EnableWebFluxSecurity
@EnableWebFlux
open class AuthorizationRedirectStrategyConfig {
companion object {
val AUTHORIZATION_REDIRECT_STRATEGY : ServerRedirectStrategy = DefaultServerRedirectStrategy()
}
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
oauth2Client {
authorizationRedirectStrategy = AUTHORIZATION_REDIRECT_STRATEGY
}
}
}
}
@Test
fun `OAuth2 client when authentication converter configured then custom converter used`() {
this.spring.register(AuthenticationConverterConfig::class.java, ClientConfig::class.java).autowire()

View File

@@ -34,7 +34,9 @@ import org.springframework.security.oauth2.client.registration.ReactiveClientReg
import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository
import org.springframework.security.oauth2.client.web.server.WebSessionOAuth2ServerAuthorizationRequestRepository
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
import org.springframework.security.web.server.DefaultServerRedirectStrategy
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.ServerRedirectStrategy
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher
import org.springframework.test.web.reactive.server.WebTestClient
@@ -139,6 +141,38 @@ class ServerOAuth2LoginDslTests {
}
}
@Test
fun `OAuth2 login when authorization redirect strategy configured then custom redirect strategy used`() {
this.spring.register(AuthorizationRedirectStrategyConfig::class.java, ClientConfig::class.java).autowire()
mockkObject(AuthorizationRedirectStrategyConfig.AUTHORIZATION_REDIRECT_STRATEGY)
every {
AuthorizationRedirectStrategyConfig.AUTHORIZATION_REDIRECT_STRATEGY.sendRedirect(any(), any())
} returns Mono.empty()
this.client.get()
.uri("/oauth2/authorization/google")
.exchange()
verify(exactly = 1) { AuthorizationRedirectStrategyConfig.AUTHORIZATION_REDIRECT_STRATEGY.sendRedirect(any(), any()) }
}
@EnableWebFluxSecurity
@EnableWebFlux
open class AuthorizationRedirectStrategyConfig {
companion object {
val AUTHORIZATION_REDIRECT_STRATEGY : ServerRedirectStrategy = DefaultServerRedirectStrategy()
}
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
oauth2Login {
authorizationRedirectStrategy = AUTHORIZATION_REDIRECT_STRATEGY
}
}
}
}
@Test
fun `OAuth2 login when authentication matcher configured then custom matcher used`() {
this.spring.register(AuthenticationMatcherConfig::class.java, ClientConfig::class.java).autowire()

View File

@@ -43,6 +43,9 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
import org.springframework.security.web.DefaultRedirectStrategy
import org.springframework.security.web.RedirectStrategy
import org.springframework.security.web.SecurityFilterChain
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
@@ -101,6 +104,40 @@ class AuthorizationCodeGrantDslTests {
}
}
@Test
fun `oauth2Client when custom authorization redirect strategy then redirect strategy used`() {
this.spring.register(RedirectStrategyConfig::class.java, ClientConfig::class.java).autowire()
mockkObject(RedirectStrategyConfig.REDIRECT_STRATEGY)
every { RedirectStrategyConfig.REDIRECT_STRATEGY.sendRedirect(any(), any(), any()) }
this.mockMvc.get("/oauth2/authorization/registrationId")
verify(exactly = 1) { RedirectStrategyConfig.REDIRECT_STRATEGY.sendRedirect(any(), any(), any()) }
}
@EnableWebSecurity
open class RedirectStrategyConfig {
companion object {
val REDIRECT_STRATEGY: RedirectStrategy = DefaultRedirectStrategy()
}
@Bean
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
oauth2Client {
authorizationCodeGrant {
authorizationRedirectStrategy = REDIRECT_STRATEGY
}
}
authorizeRequests {
authorize(anyRequest, authenticated)
}
}
return http.build()
}
}
@Test
fun `oauth2Client when custom access token response client then client used`() {
this.spring.register(AuthorizedClientConfig::class.java, ClientConfig::class.java).autowire()

View File

@@ -38,6 +38,9 @@ import org.springframework.security.oauth2.client.web.AuthorizationRequestReposi
import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
import org.springframework.security.web.DefaultRedirectStrategy
import org.springframework.security.web.RedirectStrategy
import org.springframework.security.web.SecurityFilterChain
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
@@ -121,6 +124,37 @@ class AuthorizationEndpointDslTests {
}
}
@Test
fun `oauth2Login when custom authorization redirect strategy then redirect strategy used`() {
this.spring.register(RedirectStrategyConfig::class.java, ClientConfig::class.java).autowire()
mockkObject(RedirectStrategyConfig.REDIRECT_STRATEGY)
every { RedirectStrategyConfig.REDIRECT_STRATEGY.sendRedirect(any(), any(), any()) }
this.mockMvc.get("/oauth2/authorization/google")
verify(exactly = 1) { RedirectStrategyConfig.REDIRECT_STRATEGY.sendRedirect(any(), any(), any()) }
}
@EnableWebSecurity
open class RedirectStrategyConfig {
companion object {
val REDIRECT_STRATEGY: RedirectStrategy = DefaultRedirectStrategy()
}
@Bean
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
oauth2Login {
authorizationEndpoint {
authorizationRedirectStrategy = REDIRECT_STRATEGY
}
}
}
return http.build()
}
}
@Test
fun `oauth2Login when custom authorization uri repository then uri used`() {
this.spring.register(AuthorizationUriConfig::class.java, ClientConfig::class.java).autowire()

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2022 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http auto-config="true">
<oauth2-client>
<authorization-code-grant
authorization-redirect-strategy-ref="authorizationRedirectStrategy"/>
</oauth2-client>
</http>
<b:bean id="authorizationRedirectStrategy" class="org.mockito.Mockito" factory-method="mock">
<b:constructor-arg value="org.springframework.security.web.RedirectStrategy"/>
</b:bean>
<client-registrations>
<client-registration registration-id="google"
client-id="google-client-id"
client-secret="google-client-secret"
redirect-uri="http://localhost/callback/google"
scope="scope1,scope2"
provider-id="google"/>
</client-registrations>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2022 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http auto-config="true">
<intercept-url pattern="/**" access="authenticated"/>
<oauth2-login authorization-redirect-strategy-ref="authorizationRedirectStrategy"/>
</http>
<b:bean id="authorizationRedirectStrategy" class="org.mockito.Mockito" factory-method="mock">
<b:constructor-arg value="org.springframework.security.web.RedirectStrategy"/>
</b:bean>
<b:import resource="../oauth2/client/google-registration.xml"/>
<b:import resource="userservice.xml"/>
</b:beans>