From d1d0e67cccdd38efa1547408747cb470d0de617f Mon Sep 17 00:00:00 2001 From: Maciej Kowalski Date: Tue, 27 May 2025 14:31:30 +0200 Subject: [PATCH 1/2] fix: #17175 relax type constraint (6.4 -> 6.5) compatible Signed-off-by: Maciej Kowalski --- .../configurers/oauth2/client/OAuth2LoginConfigurer.java | 6 ++---- 1 file changed, 2 insertions(+), 4 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 355e49670b9..4a9b849ea6a 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 @@ -404,11 +404,9 @@ public void init(B http) throws Exception { oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper); oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper); } - oidcAuthorizationCodeAuthenticationProvider = this.postProcess(oidcAuthorizationCodeAuthenticationProvider); - http.authenticationProvider(oidcAuthorizationCodeAuthenticationProvider); + http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); - oidcAuthorizedClientRefreshedEventListener = this.postProcess(oidcAuthorizedClientRefreshedEventListener); - registerDelegateApplicationListener(oidcAuthorizedClientRefreshedEventListener); + registerDelegateApplicationListener(this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); configureOidcUserRefreshedEventListener(http); } else { From 197e4b0b2d8764b8359ddf4f1d2bd1593fa2fb93 Mon Sep 17 00:00:00 2001 From: Maciej Kowalski Date: Wed, 11 Jun 2025 13:23:36 +0200 Subject: [PATCH 2/2] add regression showcase ObjectProcessor returning a custom AuthenticationProvider Signed-off-by: Maciej Kowalski --- .../oauth2/client/OAuth2LoginConfigurer.java | 3 +- .../client/OAuth2LoginConfigurerTests.java | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) 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 4a9b849ea6a..402f2ff277e 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 @@ -404,9 +404,10 @@ public void init(B http) throws Exception { oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper); oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper); } + http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); - registerDelegateApplicationListener(this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); + registerDelegateApplicationListener(this.postProcess(oidcAuthorizedClientRefreshedEventListener)); configureOidcUserRefreshedEventListener(http); } else { 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 9895beaded3..da9d3745604 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 @@ -43,7 +43,9 @@ import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -52,6 +54,7 @@ import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.context.DelegatingApplicationListener; import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -214,6 +217,28 @@ public void oauth2Login() throws Exception { .hasToString("OAUTH2_USER"); } + // gh-17175 + @Test + public void postProcessorSucceedsWhenProcessorReturnsAuthenticationProvider() throws Exception { + loadConfig(OAuth2LoginConfigCustomWithPostProcessor.class); + // setup authorization request + OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest(); + 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 + Authentication authentication = this.securityContextRepository + .loadContext(new HttpRequestResponseHolder(this.request, this.response)) + .getAuthentication(); + assertThat(authentication.getAuthorities()).hasSize(1); + assertThat(authentication.getAuthorities()).first() + .isInstanceOf(OAuth2UserAuthority.class) + .hasToString("OAUTH2_USER"); + } + @Test public void requestWhenCustomSecurityContextHolderStrategyThenUses() throws Exception { loadConfig(OAuth2LoginConfig.class, SecurityContextChangedListenerConfig.class); @@ -1307,6 +1332,56 @@ OAuth2AuthorizedClientRepository authorizedClientRepository() { } + @Configuration + @EnableWebSecurity + static class OAuth2LoginConfigCustomWithPostProcessor + extends CommonLambdaSecurityFilterChainConfig { + + private ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository( + GOOGLE_CLIENT_REGISTRATION); + + OAuth2AuthorizationRequestResolver resolver = mock(OAuth2AuthorizationRequestResolver.class); + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .oauth2Login((oauth2Login) -> + oauth2Login + .clientRegistrationRepository(this.clientRegistrationRepository) +// .authorizedClientRepository(this.authorizedClientRepository) + .withObjectPostProcessor(new CustomProcessor()) + ); + // @formatter:on + return super.configureFilterChain(http); + } + + class CustomProcessor implements ObjectPostProcessor { + @Override + public O postProcess(O object) { + AuthenticationProvider p = new NoopWrapperProvider(object); + + return (O) p; + } + } + + record NoopWrapperProvider( + AuthenticationProvider delegate + ) implements AuthenticationProvider { + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + return delegate.authenticate(authentication); + } + + @Override + public boolean supports(Class authentication) { + return delegate.supports(authentication); + } + } + + } + private abstract static class CommonSecurityFilterChainConfig { SecurityFilterChain configureFilterChain(HttpSecurity http) throws Exception {