Relax ObjectPostProcessor Type Constraints

Closes gh-17175

Signed-off-by: Maciej Kowalski <f.kowal@gmail.com>
This commit is contained in:
Maciej Kowalski 2025-05-27 14:31:30 +02:00 committed by Josh Cummings
parent fc6650111a
commit 46283b3452
2 changed files with 78 additions and 4 deletions

View File

@ -404,11 +404,9 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
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(oidcAuthorizedClientRefreshedEventListener));
configureOidcUserRefreshedEventListener(http);
}
else {

View File

@ -43,7 +43,10 @@ import org.springframework.http.MediaType;
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.Customizer;
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 +55,7 @@ import org.springframework.security.config.test.SpringTestContext;
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 +218,28 @@ public class OAuth2LoginConfigurerTests {
.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 +1333,56 @@ public class OAuth2LoginConfigurerTests {
}
@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<AuthenticationProvider> {
@Override
public <O extends AuthenticationProvider> 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 {