Add support configuring OAuth2AuthorizationRequestResolver as bean
Closes gh-15236
This commit is contained in:
parent
60a6b3845d
commit
4e52eda0f5
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -58,7 +58,7 @@ import org.springframework.util.Assert;
|
||||||
* {@link ClientRegistrationRepository} {@code @Bean} may be registered instead.
|
* {@link ClientRegistrationRepository} {@code @Bean} may be registered instead.
|
||||||
*
|
*
|
||||||
* <h2>Security Filters</h2>
|
* <h2>Security Filters</h2>
|
||||||
*
|
* <p>
|
||||||
* The following {@code Filter}'s are populated for {@link #authorizationCodeGrant()}:
|
* The following {@code Filter}'s are populated for {@link #authorizationCodeGrant()}:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -67,7 +67,7 @@ import org.springframework.util.Assert;
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <h2>Shared Objects Created</h2>
|
* <h2>Shared Objects Created</h2>
|
||||||
*
|
* <p>
|
||||||
* The following shared objects are populated:
|
* The following shared objects are populated:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -76,7 +76,7 @@ import org.springframework.util.Assert;
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <h2>Shared Objects Used</h2>
|
* <h2>Shared Objects Used</h2>
|
||||||
*
|
* <p>
|
||||||
* The following shared objects are used:
|
* The following shared objects are used:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -283,9 +283,11 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
if (this.authorizationRequestResolver != null) {
|
if (this.authorizationRequestResolver != null) {
|
||||||
return this.authorizationRequestResolver;
|
return this.authorizationRequestResolver;
|
||||||
}
|
}
|
||||||
ClientRegistrationRepository clientRegistrationRepository = OAuth2ClientConfigurerUtils
|
ResolvableType resolvableType = ResolvableType.forClass(OAuth2AuthorizationRequestResolver.class);
|
||||||
.getClientRegistrationRepository(getBuilder());
|
OAuth2AuthorizationRequestResolver bean = getBeanOrNull(resolvableType);
|
||||||
return new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository,
|
return (bean != null) ? bean
|
||||||
|
: new DefaultOAuth2AuthorizationRequestResolver(
|
||||||
|
OAuth2ClientConfigurerUtils.getClientRegistrationRepository(getBuilder()),
|
||||||
OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI);
|
OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4532,9 +4532,12 @@ public class ServerHttpSecurity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuth2AuthorizationRequestRedirectWebFilter getRedirectWebFilter() {
|
private OAuth2AuthorizationRequestRedirectWebFilter getRedirectWebFilter() {
|
||||||
OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter;
|
ServerOAuth2AuthorizationRequestResolver result = this.authorizationRequestResolver;
|
||||||
if (this.authorizationRequestResolver != null) {
|
if (result == null) {
|
||||||
return new OAuth2AuthorizationRequestRedirectWebFilter(this.authorizationRequestResolver);
|
result = getBeanOrNull(ServerOAuth2AuthorizationRequestResolver.class);
|
||||||
|
}
|
||||||
|
if (result != null) {
|
||||||
|
return new OAuth2AuthorizationRequestRedirectWebFilter(result);
|
||||||
}
|
}
|
||||||
return new OAuth2AuthorizationRequestRedirectWebFilter(getClientRegistrationRepository());
|
return new OAuth2AuthorizationRequestRedirectWebFilter(getClientRegistrationRepository());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -285,6 +285,18 @@ public class OAuth2ClientConfigurerTests {
|
||||||
verify(authorizationRedirectStrategy).sendRedirect(any(), any(), anyString());
|
verify(authorizationRedirectStrategy).sendRedirect(any(), any(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void configureWhenCustomAuthorizationRequestResolverBeanPresentThenAuthorizationRequestIncludesCustomParameters()
|
||||||
|
throws Exception {
|
||||||
|
this.spring.register(OAuth2ClientBeanConfig.class).autowire();
|
||||||
|
// @formatter:off
|
||||||
|
this.mockMvc.perform(get("/oauth2/authorization/registration-1"))
|
||||||
|
.andExpect(status().is3xxRedirection())
|
||||||
|
.andReturn();
|
||||||
|
// @formatter:on
|
||||||
|
verify(authorizationRequestResolver).resolve(any());
|
||||||
|
}
|
||||||
|
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
|
@ -362,4 +374,59 @@ public class OAuth2ClientConfigurerTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
@Configuration
|
||||||
|
@EnableWebMvc
|
||||||
|
static class OAuth2ClientBeanConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.authorizeRequests()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
.and()
|
||||||
|
.requestCache()
|
||||||
|
.requestCache(requestCache)
|
||||||
|
.and()
|
||||||
|
.oauth2Client()
|
||||||
|
.authorizationCodeGrant()
|
||||||
|
.authorizationRedirectStrategy(authorizationRedirectStrategy)
|
||||||
|
.accessTokenResponseClient(accessTokenResponseClient);
|
||||||
|
return http.build();
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ClientRegistrationRepository clientRegistrationRepository() {
|
||||||
|
return clientRegistrationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
OAuth2AuthorizedClientRepository authorizedClientRepository() {
|
||||||
|
return authorizedClientRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
OAuth2AuthorizationRequestResolver authorizationRequestResolver() {
|
||||||
|
OAuth2AuthorizationRequestResolver defaultAuthorizationRequestResolver = authorizationRequestResolver;
|
||||||
|
authorizationRequestResolver = mock(OAuth2AuthorizationRequestResolver.class);
|
||||||
|
given(authorizationRequestResolver.resolve(any()))
|
||||||
|
.willAnswer((invocation) -> defaultAuthorizationRequestResolver.resolve(invocation.getArgument(0)));
|
||||||
|
return authorizationRequestResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
class ResourceController {
|
||||||
|
|
||||||
|
@GetMapping("/resource1")
|
||||||
|
String resource1(
|
||||||
|
@RegisteredOAuth2AuthorizedClient("registration-1") OAuth2AuthorizedClient authorizedClient) {
|
||||||
|
return "resource1";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ import org.springframework.security.oauth2.client.registration.InMemoryReactiveC
|
||||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||||
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
|
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
|
||||||
import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService;
|
import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService;
|
||||||
|
import org.springframework.security.oauth2.client.web.server.DefaultServerOAuth2AuthorizationRequestResolver;
|
||||||
import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository;
|
import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository;
|
||||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizationRequestResolver;
|
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizationRequestResolver;
|
||||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||||
|
@ -457,6 +458,7 @@ public class OAuth2LoginTests {
|
||||||
OidcUser user = TestOidcUsers.create();
|
OidcUser user = TestOidcUsers.create();
|
||||||
ReactiveOAuth2UserService<OidcUserRequest, OidcUser> userService = config.userService;
|
ReactiveOAuth2UserService<OidcUserRequest, OidcUser> userService = config.userService;
|
||||||
given(userService.loadUser(any())).willReturn(Mono.just(user));
|
given(userService.loadUser(any())).willReturn(Mono.just(user));
|
||||||
|
ServerOAuth2AuthorizationRequestResolver resolver = config.resolver;
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
webTestClient.get()
|
webTestClient.get()
|
||||||
.uri("/login/oauth2/code/google")
|
.uri("/login/oauth2/code/google")
|
||||||
|
@ -466,6 +468,7 @@ public class OAuth2LoginTests {
|
||||||
verify(config.jwtDecoderFactory).createDecoder(any());
|
verify(config.jwtDecoderFactory).createDecoder(any());
|
||||||
verify(tokenResponseClient).getTokenResponse(any());
|
verify(tokenResponseClient).getTokenResponse(any());
|
||||||
verify(securityContextRepository).save(any(), any());
|
verify(securityContextRepository).save(any(), any());
|
||||||
|
verify(resolver).resolve(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
// gh-5562
|
// gh-5562
|
||||||
|
@ -837,6 +840,10 @@ public class OAuth2LoginTests {
|
||||||
|
|
||||||
ServerSecurityContextRepository securityContextRepository = mock(ServerSecurityContextRepository.class);
|
ServerSecurityContextRepository securityContextRepository = mock(ServerSecurityContextRepository.class);
|
||||||
|
|
||||||
|
ServerOAuth2AuthorizationRequestResolver resolver = spy(
|
||||||
|
new DefaultServerOAuth2AuthorizationRequestResolver(new InMemoryReactiveClientRegistrationRepository(
|
||||||
|
TestClientRegistrations.clientRegistration().build())));
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
|
SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
|
@ -864,6 +871,11 @@ public class OAuth2LoginTests {
|
||||||
return this.jwtDecoderFactory;
|
return this.jwtDecoderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ServerOAuth2AuthorizationRequestResolver resolver() {
|
||||||
|
return this.resolver;
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
|
ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
|
||||||
return this.tokenResponseClient;
|
return this.tokenResponseClient;
|
||||||
|
|
Loading…
Reference in New Issue