From d244e8ce96ac0afe37ec226454dcfc2d34132756 Mon Sep 17 00:00:00 2001 From: seeun0210 Date: Fri, 26 Sep 2025 18:18:11 +0900 Subject: [PATCH] Fix OAuth2LoginConfigurer AuthenticationProvider decoration - Cast postProcess result to AuthenticationProvider interface - Enables custom ObjectPostProcessor implementations for OAuth2 and OIDC authentication providers - Add test for OIDC AuthenticationProvider postProcess functionality Closes gh-17357 Signed-off-by: seeun0210 --- .../oauth2/client/OAuth2LoginConfigurer.java | 4 +- .../client/OAuth2LoginConfigurerTests.java | 67 ++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index 37ec87dcc2..1f5d493250 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -344,7 +344,7 @@ public void init(B http) { if (userAuthoritiesMapper != null) { oauth2LoginAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper); } - http.authenticationProvider(this.postProcess(oauth2LoginAuthenticationProvider)); + http.authenticationProvider((AuthenticationProvider) this.postProcess(oauth2LoginAuthenticationProvider)); boolean oidcAuthenticationProviderEnabled = ClassUtils .isPresent("org.springframework.security.oauth2.jwt.JwtDecoder", this.getClass().getClassLoader()); if (oidcAuthenticationProviderEnabled) { @@ -365,7 +365,7 @@ public void init(B http) { oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper); oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper); } - http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); + http.authenticationProvider((AuthenticationProvider) this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); registerDelegateApplicationListener(this.postProcess(oidcAuthorizedClientRefreshedEventListener)); configureOidcUserRefreshedEventListener(http); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index d2f5574a67..9baab2a330 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -87,7 +87,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; -import org.springframework.security.oauth2.core.oidc.OidcIdToken; +import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.security.oauth2.core.oidc.TestOidcIdTokens; import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames; import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; @@ -697,6 +697,22 @@ public void oauth2LoginWhenAuthenticationProviderPostProcessorThenUses() throws verify(this.context.getBean(SpyObjectPostProcessor.class).spy).authenticate(any()); } + // gh-17357 + @Test + public void oauth2LoginWhenOidcAuthenticationProviderPostProcessorThenUses() throws Exception { + loadConfig(OAuth2LoginConfigCustomWithOidcPostProcessor.class); + // setup authorization request with OIDC scope + OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest(OidcScopes.OPENID); + this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, this.request, this.response); + // setup authentication parameters + this.request.setParameter("code", "code123"); + this.request.setParameter("state", authorizationRequest.getState()); + // perform test + this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain); + // assertions + verify(this.context.getBean(OidcSpyObjectPostProcessor.class).spy).authenticate(any()); + } + // gh-16623 @Test public void oauth2LoginWithCustomSecurityContextRepository() { @@ -1454,6 +1470,55 @@ JwtDecoderFactory jwtDecoderFactory2() { return (clientRegistration) -> JwtDecoderFactoryConfig.getJwtDecoder(); } + @Configuration + static class OAuth2LoginConfigCustomWithOidcPostProcessor { + + private final ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository( + TestClientRegistrations.oidc().build()); + + private final ObjectPostProcessor postProcessor = new OidcSpyObjectPostProcessor(); + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .oauth2Login((oauth2Login) -> oauth2Login + .clientRegistrationRepository(this.clientRegistrationRepository) + .withObjectPostProcessor(this.postProcessor) + ); + // @formatter:on + return http.build(); + } + + @Bean + ObjectPostProcessor mockPostProcessor() { + return this.postProcessor; + } + + @Bean + HttpSessionOAuth2AuthorizationRequestRepository oauth2AuthorizationRequestRepository() { + return new HttpSessionOAuth2AuthorizationRequestRepository(); + } + + @Bean + JwtDecoderFactory jwtDecoderFactory() { + return (clientRegistration) -> JwtDecoderFactoryConfig.getJwtDecoder(); + } + + static class OidcSpyObjectPostProcessor implements ObjectPostProcessor { + + AuthenticationProvider spy; + + @Override + public O postProcess(O object) { + O spy = Mockito.spy(object); + this.spy = spy; + return spy; + } + + } + } } +}