Skip to content

Commit ef1226d

Browse files
kse-musicjzheaux
authored andcommitted
Use Oauth2UserService bean in OidcReactiveOAuth2UserService
Closes gh-15846
1 parent 35cc794 commit ef1226d

File tree

2 files changed

+86
-1
lines changed

2 files changed

+86
-1
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4586,7 +4586,9 @@ private ReactiveOAuth2UserService<OidcUserRequest, OidcUser> getOidcUserService(
45864586
if (bean != null) {
45874587
return bean;
45884588
}
4589-
return new OidcReactiveOAuth2UserService();
4589+
OidcReactiveOAuth2UserService reactiveOAuth2UserService = new OidcReactiveOAuth2UserService();
4590+
reactiveOAuth2UserService.setOauth2UserService(getOauth2UserService());
4591+
return reactiveOAuth2UserService;
45904592
}
45914593

45924594
private ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> getOauth2UserService() {

config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
6565
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
6666
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
67+
import org.springframework.security.oauth2.client.userinfo.DefaultReactiveOAuth2UserService;
68+
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
6769
import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService;
6870
import org.springframework.security.oauth2.client.web.server.DefaultServerOAuth2AuthorizationRequestResolver;
6971
import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository;
@@ -84,6 +86,7 @@
8486
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
8587
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
8688
import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers;
89+
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
8790
import org.springframework.security.oauth2.core.user.OAuth2User;
8891
import org.springframework.security.oauth2.core.user.TestOAuth2Users;
8992
import org.springframework.security.oauth2.jwt.Jwt;
@@ -664,6 +667,41 @@ public void oauth2LoginWhenDefaultsThenNoOidcSessionRegistry() {
664667
.block()).isEmpty();
665668
}
666669

670+
@Test
671+
public void oauth2LoginWhenOauth2UserServiceBeanPresent() {
672+
this.spring.register(OAuth2LoginWithMultipleClientRegistrations.class, OAuth2LoginWithOauth2UserService.class)
673+
.autowire();
674+
WebTestClient webTestClient = WebTestClientBuilder.bindToWebFilters(this.springSecurity).build();
675+
OAuth2LoginWithOauth2UserService config = this.spring.getContext()
676+
.getBean(OAuth2LoginWithOauth2UserService.class);
677+
OAuth2AuthorizationRequest request = TestOAuth2AuthorizationRequests.request().scope("openid").build();
678+
OAuth2AuthorizationResponse response = TestOAuth2AuthorizationResponses.success().build();
679+
OAuth2AuthorizationExchange exchange = new OAuth2AuthorizationExchange(request, response);
680+
OAuth2AccessToken accessToken = TestOAuth2AccessTokens.scopes("openid");
681+
OAuth2AuthorizationCodeAuthenticationToken token = new OAuth2AuthorizationCodeAuthenticationToken(google,
682+
exchange, accessToken);
683+
ServerAuthenticationConverter converter = config.authenticationConverter;
684+
given(converter.convert(any())).willReturn(Mono.just(token));
685+
ServerSecurityContextRepository securityContextRepository = config.securityContextRepository;
686+
given(securityContextRepository.save(any(), any())).willReturn(Mono.empty());
687+
given(securityContextRepository.load(any())).willReturn(authentication(token));
688+
Map<String, Object> additionalParameters = new HashMap<>();
689+
additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token");
690+
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
691+
.tokenType(accessToken.getTokenType())
692+
.scopes(accessToken.getScopes())
693+
.additionalParameters(additionalParameters)
694+
.build();
695+
ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> tokenResponseClient = config.tokenResponseClient;
696+
given(tokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
697+
ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> userService = config.reactiveOAuth2UserService;
698+
given(userService.loadUser(any())).willReturn(Mono
699+
.just(new DefaultOAuth2User(AuthorityUtils.createAuthorityList("USER"), Map.of("sub", "subject"), "sub")));
700+
webTestClient.get().uri("/login/oauth2/code/google").exchange().expectStatus().is3xxRedirection();
701+
verify(userService).loadUser(any());
702+
703+
}
704+
667705
Mono<SecurityContext> authentication(Authentication authentication) {
668706
SecurityContext context = new SecurityContextImpl();
669707
context.setAuthentication(authentication);
@@ -674,6 +712,51 @@ <T> T getBean(Class<T> beanClass) {
674712
return this.spring.getContext().getBean(beanClass);
675713
}
676714

715+
@Configuration
716+
static class OAuth2LoginWithOauth2UserService {
717+
718+
ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> tokenResponseClient = mock(
719+
ReactiveOAuth2AccessTokenResponseClient.class);
720+
721+
ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> reactiveOAuth2UserService = mock(
722+
DefaultReactiveOAuth2UserService.class);
723+
724+
ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);
725+
726+
ServerSecurityContextRepository securityContextRepository = mock(ServerSecurityContextRepository.class);
727+
728+
@Bean
729+
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
730+
http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated())
731+
.oauth2Login((c) -> c.authenticationConverter(this.authenticationConverter)
732+
.securityContextRepository(this.securityContextRepository));
733+
return http.build();
734+
}
735+
736+
@Bean
737+
ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> customOAuth2UserService() {
738+
return this.reactiveOAuth2UserService;
739+
}
740+
741+
@Bean
742+
ReactiveJwtDecoderFactory<ClientRegistration> jwtDecoderFactory() {
743+
return (clientRegistration) -> (token) -> {
744+
Map<String, Object> claims = new HashMap<>();
745+
claims.put(IdTokenClaimNames.SUB, "subject");
746+
claims.put(IdTokenClaimNames.ISS, "http://localhost/issuer");
747+
claims.put(IdTokenClaimNames.AUD, Collections.singletonList("client"));
748+
claims.put(IdTokenClaimNames.AZP, "client");
749+
return Mono.just(TestJwts.jwt().claims((c) -> c.putAll(claims)).build());
750+
};
751+
}
752+
753+
@Bean
754+
ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> requestReactiveOAuth2AccessTokenResponseClient() {
755+
return this.tokenResponseClient;
756+
}
757+
758+
}
759+
677760
@Configuration
678761
@EnableWebFluxSecurity
679762
static class OAuth2LoginWithMultipleClientRegistrations {

0 commit comments

Comments
 (0)