mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-30 22:28:46 +00:00 
			
		
		
		
	SEC-2515: Detect object cycle for AuthenticationManager configuration
This commit is contained in:
		
							parent
							
								
									32d3e29c65
								
							
						
					
					
						commit
						e4a58375cc
					
				| @ -114,7 +114,7 @@ public class AuthenticationConfiguration { | |||||||
|         lazyTargetSource.setBeanFactory(applicationContext); |         lazyTargetSource.setBeanFactory(applicationContext); | ||||||
|         ProxyFactoryBean proxyFactory = new ProxyFactoryBean(); |         ProxyFactoryBean proxyFactory = new ProxyFactoryBean(); | ||||||
|         proxyFactory.setTargetSource(lazyTargetSource); |         proxyFactory.setTargetSource(lazyTargetSource); | ||||||
|         proxyFactory.setInterfaces(new Class[] { interfaceName }); |         proxyFactory.setInterfaces(new Class[] { interfaceName, LazyBean.class }); | ||||||
|         return (T) proxyFactory.getObject(); |         return (T) proxyFactory.getObject(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -122,6 +122,7 @@ public class AuthenticationConfiguration { | |||||||
|         return lazyBean(AuthenticationManager.class); |         return lazyBean(AuthenticationManager.class); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private interface LazyBean {} | ||||||
| 
 | 
 | ||||||
|     private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter { |     private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter { | ||||||
|         private final ApplicationContext context; |         private final ApplicationContext context; | ||||||
|  | |||||||
| @ -16,11 +16,13 @@ | |||||||
| package org.springframework.security.config.annotation.web.configuration; | package org.springframework.security.config.annotation.web.configuration; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | import java.lang.reflect.Field; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||||
| import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||||
|  | import org.springframework.beans.FatalBeanException; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.context.ApplicationContext; | import org.springframework.context.ApplicationContext; | ||||||
| import org.springframework.core.annotation.Order; | import org.springframework.core.annotation.Order; | ||||||
| @ -44,6 +46,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; | |||||||
| import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; | import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; | ||||||
| import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter; | import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter; | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
|  | import org.springframework.util.ReflectionUtils; | ||||||
| import org.springframework.web.accept.ContentNegotiationStrategy; | import org.springframework.web.accept.ContentNegotiationStrategy; | ||||||
| import org.springframework.web.accept.HeaderContentNegotiationStrategy; | import org.springframework.web.accept.HeaderContentNegotiationStrategy; | ||||||
| 
 | 
 | ||||||
| @ -71,8 +74,8 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
| 
 | 
 | ||||||
|     private AuthenticationConfiguration authenticationConfiguration; |     private AuthenticationConfiguration authenticationConfiguration; | ||||||
|     private AuthenticationManagerBuilder authenticationBuilder; |     private AuthenticationManagerBuilder authenticationBuilder; | ||||||
|     private AuthenticationManagerBuilder parentAuthenticationBuilder; |     private AuthenticationManagerBuilder localConfigureAuthenticationBldr; | ||||||
|     private boolean disableAuthenticationRegistration; |     private boolean disableLocalConfigureAuthenticationBldr; | ||||||
|     private boolean authenticationManagerInitialized; |     private boolean authenticationManagerInitialized; | ||||||
|     private AuthenticationManager authenticationManager; |     private AuthenticationManager authenticationManager; | ||||||
|     private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); |     private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); | ||||||
| @ -148,7 +151,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
|      * @throws Exception |      * @throws Exception | ||||||
|      */ |      */ | ||||||
|     protected void configure(AuthenticationManagerBuilder auth) throws Exception { |     protected void configure(AuthenticationManagerBuilder auth) throws Exception { | ||||||
|         this.disableAuthenticationRegistration = true; |         this.disableLocalConfigureAuthenticationBldr = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -163,11 +166,11 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher()); |         DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher()); | ||||||
|         parentAuthenticationBuilder.authenticationEventPublisher(eventPublisher); |         localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher); | ||||||
| 
 | 
 | ||||||
|         AuthenticationManager authenticationManager = authenticationManager(); |         AuthenticationManager authenticationManager = authenticationManager(); | ||||||
|         authenticationBuilder.parentAuthenticationManager(authenticationManager); |         authenticationBuilder.parentAuthenticationManager(authenticationManager); | ||||||
|         http = new HttpSecurity(objectPostProcessor,authenticationBuilder, parentAuthenticationBuilder.getSharedObjects()); |         http = new HttpSecurity(objectPostProcessor,authenticationBuilder, localConfigureAuthenticationBldr.getSharedObjects()); | ||||||
|         http.setSharedObject(UserDetailsService.class, userDetailsService()); |         http.setSharedObject(UserDetailsService.class, userDetailsService()); | ||||||
|         http.setSharedObject(ApplicationContext.class, context); |         http.setSharedObject(ApplicationContext.class, context); | ||||||
|         http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy); |         http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy); | ||||||
| @ -221,11 +224,11 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
|      */ |      */ | ||||||
|     protected AuthenticationManager authenticationManager() throws Exception { |     protected AuthenticationManager authenticationManager() throws Exception { | ||||||
|         if(!authenticationManagerInitialized) { |         if(!authenticationManagerInitialized) { | ||||||
|             configure(parentAuthenticationBuilder); |             configure(localConfigureAuthenticationBldr); | ||||||
|             if(disableAuthenticationRegistration) { |             if(disableLocalConfigureAuthenticationBldr) { | ||||||
|                 authenticationManager = authenticationConfiguration.getAuthenticationManager(); |                 authenticationManager = authenticationConfiguration.getAuthenticationManager(); | ||||||
|             } else { |             } else { | ||||||
|                 authenticationManager = parentAuthenticationBuilder.build(); |                 authenticationManager = localConfigureAuthenticationBldr.build(); | ||||||
|             } |             } | ||||||
|             authenticationManagerInitialized = true; |             authenticationManagerInitialized = true; | ||||||
|         } |         } | ||||||
| @ -253,7 +256,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
|      */ |      */ | ||||||
|     public UserDetailsService userDetailsServiceBean() throws Exception { |     public UserDetailsService userDetailsServiceBean() throws Exception { | ||||||
|         AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class); |         AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class); | ||||||
|         return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder)); |         return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -266,7 +269,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
|      */ |      */ | ||||||
|     protected UserDetailsService userDetailsService() { |     protected UserDetailsService userDetailsService() { | ||||||
|         AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class); |         AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class); | ||||||
|         return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder)); |         return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void init(final WebSecurity web) throws Exception { |     public void init(final WebSecurity web) throws Exception { | ||||||
| @ -337,7 +340,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
|         this.objectPostProcessor = objectPostProcessor; |         this.objectPostProcessor = objectPostProcessor; | ||||||
| 
 | 
 | ||||||
|         authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor); |         authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor); | ||||||
|         parentAuthenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor) { |         localConfigureAuthenticationBldr = new AuthenticationManagerBuilder(objectPostProcessor) { | ||||||
|             @Override |             @Override | ||||||
|             public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) { |             public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) { | ||||||
|                 authenticationBuilder.eraseCredentials(eraseCredentials); |                 authenticationBuilder.eraseCredentials(eraseCredentials); | ||||||
| @ -413,6 +416,9 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
| 
 | 
 | ||||||
|         AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) { |         AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) { | ||||||
|             Assert.notNull(delegateBuilder,"delegateBuilder cannot be null"); |             Assert.notNull(delegateBuilder,"delegateBuilder cannot be null"); | ||||||
|  |             Field parentAuthMgrField = ReflectionUtils.findField(AuthenticationManagerBuilder.class, "parentAuthenticationManager"); | ||||||
|  |             ReflectionUtils.makeAccessible(parentAuthMgrField); | ||||||
|  |             validateBeanCycle(ReflectionUtils.getField(parentAuthMgrField, delegateBuilder)); | ||||||
|             this.delegateBuilder = delegateBuilder; |             this.delegateBuilder = delegateBuilder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -430,5 +436,18 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu | |||||||
| 
 | 
 | ||||||
|             return delegate.authenticate(authentication); |             return delegate.authenticate(authentication); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         private static void validateBeanCycle(Object auth) { | ||||||
|  |             if(auth != null) { | ||||||
|  |                 String lazyBeanClassName = AuthenticationConfiguration.class.getName() + "$LazyBean"; | ||||||
|  |                 Class<?>[] interfaces = auth.getClass().getInterfaces(); | ||||||
|  |                 for(Class<?> i : interfaces) { | ||||||
|  |                     String className = i.getName(); | ||||||
|  |                     if(className.equals(lazyBeanClassName)) { | ||||||
|  |                         throw new FatalBeanException("A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication."); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -0,0 +1,72 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2002-2013 the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | package org.springframework.security.config.annotation.web.configuration; | ||||||
|  | 
 | ||||||
|  | import org.springframework.beans.FatalBeanException; | ||||||
|  | import org.springframework.context.annotation.Bean | ||||||
|  | import org.springframework.context.annotation.Configuration | ||||||
|  | import org.springframework.security.authentication.AuthenticationManager | ||||||
|  | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken | ||||||
|  | import org.springframework.security.config.annotation.BaseSpringSpec | ||||||
|  | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | ||||||
|  | 
 | ||||||
|  | public class Sec2515Tests extends BaseSpringSpec { | ||||||
|  | 
 | ||||||
|  |     def "SEC-2515: Prevent StackOverflow with bean graph cycle"() { | ||||||
|  |         when: | ||||||
|  |            loadConfig(StackOverflowSecurityConfig) | ||||||
|  |         then: | ||||||
|  |             thrown(FatalBeanException) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @EnableWebSecurity | ||||||
|  |     @Configuration | ||||||
|  |     static class StackOverflowSecurityConfig extends WebSecurityConfigurerAdapter { | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         @Bean | ||||||
|  |         public AuthenticationManager authenticationManagerBean() | ||||||
|  |                 throws Exception { | ||||||
|  |             return super.authenticationManagerBean(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def "SEC-2515: @Bean still works when configure(AuthenticationManagerBuilder) used"() { | ||||||
|  |         when: | ||||||
|  |            loadConfig(SecurityConfig) | ||||||
|  |         then: | ||||||
|  |             noExceptionThrown(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @EnableWebSecurity | ||||||
|  |     @Configuration | ||||||
|  |     static class SecurityConfig extends WebSecurityConfigurerAdapter { | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         @Bean | ||||||
|  |         public AuthenticationManager authenticationManagerBean() | ||||||
|  |                 throws Exception { | ||||||
|  |             return super.authenticationManagerBean(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void configure(AuthenticationManagerBuilder auth) | ||||||
|  |                 throws Exception { | ||||||
|  |             auth.inMemoryAuthentication() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user