Pick Up SecurityContextHolderStrategy Bean

This commit provides the SecurityContextHolderStrategy bean to
ProviderManager instances that the HttpSecurity DSL constructs.

Issue gh-17862
This commit is contained in:
Josh Cummings 2025-08-22 16:24:25 -06:00
parent 8468c6a805
commit 44fef786aa
6 changed files with 45 additions and 2 deletions

View File

@ -18,10 +18,14 @@ package org.springframework.security.config.annotation.authentication.builders;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
@ -37,6 +41,8 @@ import org.springframework.security.config.annotation.authentication.configurers
import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.userdetails.UserDetailsAwareConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.Assert;
@ -235,6 +241,10 @@ public class AuthenticationManagerBuilder
if (this.eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(this.eventPublisher);
}
SecurityContextHolderStrategy securityContextHolderStrategy = getBeanProvider(
SecurityContextHolderStrategy.class)
.getIfUnique(SecurityContextHolder::getContextHolderStrategy);
providerManager.setSecurityContextHolderStrategy(securityContextHolderStrategy);
providerManager = postProcess(providerManager);
return providerManager;
}
@ -283,4 +293,24 @@ public class AuthenticationManagerBuilder
return configurer;
}
private <C> ObjectProvider<C> getBeanProvider(Class<C> clazz) {
BeanFactory beanFactory = getSharedObject(BeanFactory.class);
return (beanFactory != null) ? beanFactory.getBeanProvider(clazz) : new SingleObjectProvider<>(null);
}
private static final class SingleObjectProvider<O> implements ObjectProvider<O> {
private final @Nullable O object;
private SingleObjectProvider(@Nullable O object) {
this.object = object;
}
@Override
public Stream<O> stream() {
return Stream.ofNullable(this.object);
}
}
}

View File

@ -27,6 +27,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
@ -83,6 +84,7 @@ public class AuthenticationConfiguration {
AuthenticationEventPublisher authenticationEventPublisher = getAuthenticationEventPublisher(context);
DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(
objectPostProcessor, defaultPasswordEncoder);
result.setSharedObject(BeanFactory.class, this.applicationContext);
if (authenticationEventPublisher != null) {
result.authenticationEventPublisher(authenticationEventPublisher);
}

View File

@ -318,6 +318,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInit
.postProcess(new DefaultAuthenticationEventPublisher());
this.auth = new AuthenticationManagerBuilder(this.objectPostProcessor);
this.auth.authenticationEventPublisher(eventPublisher);
this.auth.setSharedObject(BeanFactory.class, this.context);
configure(this.auth);
this.authenticationManager = (this.disableAuthenticationRegistry)
? getAuthenticationConfiguration().getAuthenticationManager() : this.auth.build();

View File

@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
@ -116,6 +117,7 @@ class HttpSecurityConfiguration {
LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);
authenticationBuilder.setSharedObject(BeanFactory.class, this.context);
authenticationBuilder.parentAuthenticationManager(authenticationManager());
authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());

View File

@ -162,8 +162,10 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
WebAuthnRelyingPartyOperations rpOperations = webAuthnRelyingPartyOperations(userEntities, userCredentials);
PublicKeyCredentialCreationOptionsRepository creationOptionsRepository = creationOptionsRepository();
WebAuthnAuthenticationFilter webAuthnAuthnFilter = new WebAuthnAuthenticationFilter();
webAuthnAuthnFilter.setAuthenticationManager(
new ProviderManager(new WebAuthnAuthenticationProvider(rpOperations, userDetailsService)));
ProviderManager manager = new ProviderManager(
new WebAuthnAuthenticationProvider(rpOperations, userDetailsService));
manager.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
webAuthnAuthnFilter.setAuthenticationManager(manager);
WebAuthnRegistrationFilter webAuthnRegistrationFilter = new WebAuthnRegistrationFilter(userCredentials,
rpOperations);
PublicKeyCredentialCreationOptionsFilter creationOptionsFilter = new PublicKeyCredentialCreationOptionsFilter(

View File

@ -30,6 +30,8 @@ import org.springframework.security.authentication.ObservationAuthenticationMana
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.BeanIds;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
@ -72,6 +74,10 @@ public class AuthenticationManagerFactoryBean implements FactoryBean<Authenticat
}
provider.afterPropertiesSet();
ProviderManager manager = new ProviderManager(Arrays.asList(provider));
SecurityContextHolderStrategy securityContextHolderStrategy = this.bf
.getBeanProvider(SecurityContextHolderStrategy.class)
.getIfUnique(SecurityContextHolder::getContextHolderStrategy);
manager.setSecurityContextHolderStrategy(securityContextHolderStrategy);
if (this.observationRegistry.isNoop()) {
return manager;
}