Sfoglia il codice sorgente

Pick Up SecurityContextHolderStrategy Bean

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

Issue gh-17862
Josh Cummings 1 mese fa
parent
commit
44fef786aa

+ 30 - 0
config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java

@@ -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);
+		}
+
+	}
+
 }

+ 2 - 0
config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java

@@ -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);
 		}

+ 1 - 0
config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java

@@ -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();

+ 2 - 0
config/src/main/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.java

@@ -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());

+ 4 - 2
config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java

@@ -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(

+ 6 - 0
config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerFactoryBean.java

@@ -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;
 			}