Skip to content

Commit

Permalink
Use Oauth2UserService bean in OidcReactiveOAuth2UserService
Browse files Browse the repository at this point in the history
Closes gh-15846
  • Loading branch information
kse-music committed Oct 4, 2024
1 parent b06c40d commit ea672fa
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -4506,7 +4506,9 @@ private ReactiveOAuth2UserService<OidcUserRequest, OidcUser> getOidcUserService(
if (bean != null) {
return bean;
}
return new OidcReactiveOAuth2UserService();
OidcReactiveOAuth2UserService reactiveOAuth2UserService = new OidcReactiveOAuth2UserService();
reactiveOAuth2UserService.setOauth2UserService(getOauth2UserService());
return reactiveOAuth2UserService;
}

private ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> getOauth2UserService() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
import org.springframework.security.oauth2.client.userinfo.DefaultReactiveOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
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;
Expand All @@ -84,6 +86,7 @@
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.core.user.TestOAuth2Users;
import org.springframework.security.oauth2.jwt.Jwt;
Expand Down Expand Up @@ -664,6 +667,41 @@ public void oauth2LoginWhenDefaultsThenNoOidcSessionRegistry() {
.block()).isEmpty();
}

@Test
public void oauth2LoginWhenOauth2UserServiceBeanPresent() {
this.spring.register(OAuth2LoginWithMultipleClientRegistrations.class, OAuth2LoginWithOauth2UserService.class)
.autowire();
WebTestClient webTestClient = WebTestClientBuilder.bindToWebFilters(this.springSecurity).build();
OAuth2LoginWithOauth2UserService config = this.spring.getContext()
.getBean(OAuth2LoginWithOauth2UserService.class);
OAuth2AuthorizationRequest request = TestOAuth2AuthorizationRequests.request().scope("openid").build();
OAuth2AuthorizationResponse response = TestOAuth2AuthorizationResponses.success().build();
OAuth2AuthorizationExchange exchange = new OAuth2AuthorizationExchange(request, response);
OAuth2AccessToken accessToken = TestOAuth2AccessTokens.scopes("openid");
OAuth2AuthorizationCodeAuthenticationToken token = new OAuth2AuthorizationCodeAuthenticationToken(google,
exchange, accessToken);
ServerAuthenticationConverter converter = config.authenticationConverter;
given(converter.convert(any())).willReturn(Mono.just(token));
ServerSecurityContextRepository securityContextRepository = config.securityContextRepository;
given(securityContextRepository.save(any(), any())).willReturn(Mono.empty());
given(securityContextRepository.load(any())).willReturn(authentication(token));
Map<String, Object> additionalParameters = new HashMap<>();
additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token");
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
.tokenType(accessToken.getTokenType())
.scopes(accessToken.getScopes())
.additionalParameters(additionalParameters)
.build();
ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> tokenResponseClient = config.tokenResponseClient;
given(tokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> userService = config.reactiveOAuth2UserService;
given(userService.loadUser(any())).willReturn(Mono
.just(new DefaultOAuth2User(AuthorityUtils.createAuthorityList("USER"), Map.of("sub", "subject"), "sub")));
webTestClient.get().uri("/login/oauth2/code/google").exchange().expectStatus().is3xxRedirection();
verify(userService).loadUser(any());

}

Mono<SecurityContext> authentication(Authentication authentication) {
SecurityContext context = new SecurityContextImpl();
context.setAuthentication(authentication);
Expand All @@ -674,6 +712,51 @@ <T> T getBean(Class<T> beanClass) {
return this.spring.getContext().getBean(beanClass);
}

@Configuration
static class OAuth2LoginWithOauth2UserService {

ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> tokenResponseClient = mock(
ReactiveOAuth2AccessTokenResponseClient.class);

ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> reactiveOAuth2UserService = mock(
DefaultReactiveOAuth2UserService.class);

ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);

ServerSecurityContextRepository securityContextRepository = mock(ServerSecurityContextRepository.class);

@Bean
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated())
.oauth2Login((c) -> c.authenticationConverter(this.authenticationConverter)
.securityContextRepository(this.securityContextRepository));
return http.build();
}

@Bean
ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> customOAuth2UserService() {
return this.reactiveOAuth2UserService;
}

@Bean
ReactiveJwtDecoderFactory<ClientRegistration> jwtDecoderFactory() {
return (clientRegistration) -> (token) -> {
Map<String, Object> claims = new HashMap<>();
claims.put(IdTokenClaimNames.SUB, "subject");
claims.put(IdTokenClaimNames.ISS, "http://localhost/issuer");
claims.put(IdTokenClaimNames.AUD, Collections.singletonList("client"));
claims.put(IdTokenClaimNames.AZP, "client");
return Mono.just(TestJwts.jwt().claims((c) -> c.putAll(claims)).build());
};
}

@Bean
ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> requestReactiveOAuth2AccessTokenResponseClient() {
return this.tokenResponseClient;
}

}

@Configuration
@EnableWebFluxSecurity
static class OAuth2LoginWithMultipleClientRegistrations {
Expand Down

0 comments on commit ea672fa

Please sign in to comment.