From 2d556c7b4f48537f91ea0ebed06e05182223ee7a Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Sat, 7 Jan 2012 12:27:40 -0600 Subject: [PATCH] SEC-1885: Change SecurityDebugBeanFactoryPostProcessor to only interact with BeanDefinitions rather than instances to prevent premature instatiation of FilterChainProxy and its dependencies This issue occurred because the AutowiredAnnotationBeanPostProcessor had not been registered when the SecurityDebugBeanFactoryPostProcessor tried to obtain the FilterChainProxy. This caused all of the FilterChainProxy's dependant beans to be resolved and if they used @Autowired they would not get processed properly. --- ...SecurityDebugBeanFactoryPostProcessor.java | 45 ++++++++++++++----- .../debug/AuthProviderDependency.groovy | 28 ++++++++++++ ...tyDebugBeanFactoryPostProcessorTest.groovy | 38 ++++++++++++++++ .../debug/TestAuthenticationProvider.groovy | 43 ++++++++++++++++++ .../util/InMemoryXmlApplicationContext.java | 2 + 5 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 config/src/test/groovy/org/springframework/security/config/debug/AuthProviderDependency.groovy create mode 100644 config/src/test/groovy/org/springframework/security/config/debug/SecurityDebugBeanFactoryPostProcessorTest.groovy create mode 100644 config/src/test/groovy/org/springframework/security/config/debug/TestAuthenticationProvider.groovy diff --git a/config/src/main/java/org/springframework/security/config/debug/SecurityDebugBeanFactoryPostProcessor.java b/config/src/main/java/org/springframework/security/config/debug/SecurityDebugBeanFactoryPostProcessor.java index 2dbff5d623..7c93f80ef9 100644 --- a/config/src/main/java/org/springframework/security/config/debug/SecurityDebugBeanFactoryPostProcessor.java +++ b/config/src/main/java/org/springframework/security/config/debug/SecurityDebugBeanFactoryPostProcessor.java @@ -1,28 +1,53 @@ +/* + * Copyright 2002-2011 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.debug; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.security.config.BeanIds; -import org.springframework.security.web.FilterChainProxy; /** * @author Luke Taylor + * @author Rob Winch */ -public class SecurityDebugBeanFactoryPostProcessor implements BeanFactoryPostProcessor { +public class SecurityDebugBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor { - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { Logger.logger.warn("\n\n" + "********************************************************************\n" + "********** Security debugging is enabled. *************\n" + "********** This may include sensitive information. *************\n" + "********** Do not use in a production system! *************\n" + "********************************************************************\n\n"); - if (beanFactory.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) != null) { - FilterChainProxy fcp = beanFactory.getBean(BeanIds.FILTER_CHAIN_PROXY, FilterChainProxy.class); - beanFactory.registerSingleton(BeanIds.DEBUG_FILTER, new DebugFilter(fcp)); - // Overwrite the filter chain alias - beanFactory.registerAlias(BeanIds.DEBUG_FILTER, BeanIds.SPRING_SECURITY_FILTER_CHAIN); + // SPRING_SECURITY_FILTER_CHAIN does not exist yet since it is an alias that has not been processed, so use FILTER_CHAIN_PROXY + if (registry.containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) { + BeanDefinition fcpBeanDef = registry.getBeanDefinition(BeanIds.FILTER_CHAIN_PROXY); + BeanDefinitionBuilder debugFilterBldr = BeanDefinitionBuilder.genericBeanDefinition(DebugFilter.class); + debugFilterBldr.addConstructorArgValue(fcpBeanDef); + // Remove the alias to SPRING_SECURITY_FILTER_CHAIN, so that it does not override the new + // SPRING_SECURITY_FILTER_CHAIN definition + registry.removeAlias(BeanIds.SPRING_SECURITY_FILTER_CHAIN); + registry.registerBeanDefinition(BeanIds.SPRING_SECURITY_FILTER_CHAIN, debugFilterBldr.getBeanDefinition()); } } -} + + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + } +} \ No newline at end of file diff --git a/config/src/test/groovy/org/springframework/security/config/debug/AuthProviderDependency.groovy b/config/src/test/groovy/org/springframework/security/config/debug/AuthProviderDependency.groovy new file mode 100644 index 0000000000..ca5c47e1b1 --- /dev/null +++ b/config/src/test/groovy/org/springframework/security/config/debug/AuthProviderDependency.groovy @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2011 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.debug + +import org.springframework.stereotype.Component + +/** + * Fake depenency for {@link TestAuthenticationProvider} + * @author Rob Winch + * + */ +@Component +public class AuthProviderDependency { + +} diff --git a/config/src/test/groovy/org/springframework/security/config/debug/SecurityDebugBeanFactoryPostProcessorTest.groovy b/config/src/test/groovy/org/springframework/security/config/debug/SecurityDebugBeanFactoryPostProcessorTest.groovy new file mode 100644 index 0000000000..ed9fe8899c --- /dev/null +++ b/config/src/test/groovy/org/springframework/security/config/debug/SecurityDebugBeanFactoryPostProcessorTest.groovy @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2011 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.debug + +import org.springframework.security.config.BeanIds +import org.springframework.security.config.http.AbstractHttpConfigTests +import org.springframework.security.web.FilterChainProxy; + +class SecurityDebugBeanFactoryPostProcessorTest extends AbstractHttpConfigTests { + + // SEC-1885 + def 'SEC-1885 - SecurityDebugBeanFactoryPostProcessor works when dependencies have Autowired constructor'() { + when: 'debug used and FilterChainProxy has dependency with @Autowired constructor' + xml.debug() + httpAutoConfig {} + xml.'authentication-manager'() { + 'authentication-provider'('ref': 'authProvider') + } + xml.'context:component-scan'('base-package':'org.springframework.security.config.debug') + createAppContext('') + then: 'TestAuthenticationProvider.() is not thrown' + appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) instanceof DebugFilter + appContext.getBean(BeanIds.FILTER_CHAIN_PROXY) instanceof FilterChainProxy + } +} diff --git a/config/src/test/groovy/org/springframework/security/config/debug/TestAuthenticationProvider.groovy b/config/src/test/groovy/org/springframework/security/config/debug/TestAuthenticationProvider.groovy new file mode 100644 index 0000000000..0cb8ce8176 --- /dev/null +++ b/config/src/test/groovy/org/springframework/security/config/debug/TestAuthenticationProvider.groovy @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2011 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.debug; + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.authentication.AuthenticationProvider +import org.springframework.security.core.Authentication +import org.springframework.security.core.AuthenticationException +import org.springframework.stereotype.Service + +/** + * An {@link AuthenticationProvider} that has an {@link Autowired} constructor which is necessary to recreate SEC-1885. + * @author Rob Winch + * + */ +@Service("authProvider") +public class TestAuthenticationProvider implements AuthenticationProvider { + + @Autowired + public TestAuthenticationProvider(AuthProviderDependency authProviderDependency) { + } + + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + throw new UnsupportedOperationException(); + } + + public boolean supports(Class authentication) { + throw new UnsupportedOperationException(); + } +} diff --git a/config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java b/config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java index ce878af4d5..b83058c0bc 100644 --- a/config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java +++ b/config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java @@ -12,11 +12,13 @@ import org.springframework.security.util.InMemoryResource; public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext { private static final String BEANS_OPENING = "