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.
This commit is contained in:
Rob Winch 2012-01-07 12:27:40 -06:00
parent 22225effcc
commit 2d556c7b4f
5 changed files with 146 additions and 10 deletions

View File

@ -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; package org.springframework.security.config.debug;
import org.springframework.beans.BeansException; 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.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.config.BeanIds;
import org.springframework.security.web.FilterChainProxy;
/** /**
* @author Luke Taylor * @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" + Logger.logger.warn("\n\n" +
"********************************************************************\n" + "********************************************************************\n" +
"********** Security debugging is enabled. *************\n" + "********** Security debugging is enabled. *************\n" +
"********** This may include sensitive information. *************\n" + "********** This may include sensitive information. *************\n" +
"********** Do not use in a production system! *************\n" + "********** Do not use in a production system! *************\n" +
"********************************************************************\n\n"); "********************************************************************\n\n");
if (beanFactory.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) != null) { // SPRING_SECURITY_FILTER_CHAIN does not exist yet since it is an alias that has not been processed, so use FILTER_CHAIN_PROXY
FilterChainProxy fcp = beanFactory.getBean(BeanIds.FILTER_CHAIN_PROXY, FilterChainProxy.class); if (registry.containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
beanFactory.registerSingleton(BeanIds.DEBUG_FILTER, new DebugFilter(fcp)); BeanDefinition fcpBeanDef = registry.getBeanDefinition(BeanIds.FILTER_CHAIN_PROXY);
// Overwrite the filter chain alias BeanDefinitionBuilder debugFilterBldr = BeanDefinitionBuilder.genericBeanDefinition(DebugFilter.class);
beanFactory.registerAlias(BeanIds.DEBUG_FILTER, BeanIds.SPRING_SECURITY_FILTER_CHAIN); 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 {
}
} }

View File

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

View File

@ -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.<init>() is not thrown'
appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) instanceof DebugFilter
appContext.getBean(BeanIds.FILTER_CHAIN_PROXY) instanceof FilterChainProxy
}
}

View File

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

View File

@ -12,11 +12,13 @@ import org.springframework.security.util.InMemoryResource;
public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext { public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext {
private static final String BEANS_OPENING = private static final String BEANS_OPENING =
"<b:beans xmlns='http://www.springframework.org/schema/security'\n" + "<b:beans xmlns='http://www.springframework.org/schema/security'\n" +
" xmlns:context='http://www.springframework.org/schema/context'\n" +
" xmlns:b='http://www.springframework.org/schema/beans'\n" + " xmlns:b='http://www.springframework.org/schema/beans'\n" +
" xmlns:aop='http://www.springframework.org/schema/aop'\n" + " xmlns:aop='http://www.springframework.org/schema/aop'\n" +
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n" + " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n" +
" xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n" + " xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n" +
"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\n" + "http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\n" +
"http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\n" +
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-"; "http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-";
private static final String BEANS_CLOSE = "</b:beans>\n"; private static final String BEANS_CLOSE = "</b:beans>\n";