Browse Source

SEC-792: Filters should only be added to the default stack if they are labelled using custom-filter.
http://jira.springframework.org/browse/SEC-792. The filters are now maintained as a list in the context and have to be stored there explicitly on registration.

Luke Taylor 17 years ago
parent
commit
38774ec94f

+ 2 - 0
core/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java

@@ -3,6 +3,7 @@ package org.springframework.security.config;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
 import org.springframework.beans.factory.parsing.BeanComponentDefinition;
 import org.springframework.beans.factory.support.ManagedList;
 import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -70,6 +71,7 @@ public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
         authMgrProviderList.add(provider);
 
         parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter);
+        ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
         parserContext.registerComponent(new BeanComponentDefinition(filter, BeanIds.ANONYMOUS_PROCESSING_FILTER));
         
         return null;

+ 1 - 0
core/src/main/java/org/springframework/security/config/BasicAuthenticationBeanDefinitionParser.java

@@ -41,6 +41,7 @@ public class BasicAuthenticationBeanDefinitionParser implements BeanDefinitionPa
 
 	    parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER,
 	            filterBuilder.getBeanDefinition());
+	    ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER));
 	    parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), 
 	    		BeanIds.BASIC_AUTHENTICATION_FILTER));
 	    return null;

+ 1 - 0
core/src/main/java/org/springframework/security/config/BeanIds.java

@@ -18,6 +18,7 @@ public abstract class BeanIds {
     static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
     static final String HTTP_POST_PROCESSOR = "_httpConfigBeanFactoryPostProcessor";
     static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
+    static final String FILTER_LIST = "_filterChainList";
 
     public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager";
 	public static final String USER_DETAILS_SERVICE = "_userDetailsService";

+ 1 - 0
core/src/main/java/org/springframework/security/config/ConcurrentSessionsBeanDefinitionParser.java

@@ -83,6 +83,7 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
         parserContext.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER));
         beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, filterBuilder.getBeanDefinition());
         parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), BeanIds.CONCURRENT_SESSION_FILTER));
+        ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER));
         
         BeanDefinition providerManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
 

+ 50 - 1
core/src/main/java/org/springframework/security/config/ConfigUtils.java

@@ -1,7 +1,11 @@
 package org.springframework.security.config;
 
+import java.util.List;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.BeanMetadataElement;
+import org.springframework.beans.MutablePropertyValues;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -83,7 +87,6 @@ public abstract class ConfigUtils {
         return authManager;
     }
 
-
     /**
      * Obtains a user details service for use in RememberMeServices etc. Will return a caching version
      * if available so should not be used for beans which need to separate the two. 
@@ -110,4 +113,50 @@ public abstract class ConfigUtils {
         BeanDefinition authManager = registerProviderManagerIfNecessary(parserContext);
         return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
     }
+    
+    private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
+    	if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
+    		return;
+    	}
+        // Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
+        RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
+        filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+        pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
+        RootBeanDefinition filterList = new RootBeanDefinition(FilterChainList.class);
+        filterList.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+        pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_LIST, filterList);
+    }
+    
+    static void addHttpFilter(ParserContext pc, BeanMetadataElement filter) {
+    	registerFilterChainPostProcessorIfNecessary(pc);
+    	
+    	RootBeanDefinition filterList = (RootBeanDefinition) pc.getRegistry().getBeanDefinition(BeanIds.FILTER_LIST);
+    	
+    	ManagedList filters;
+    	MutablePropertyValues pvs = filterList.getPropertyValues();
+    	if (pvs.contains("filters")) {
+    		filters = (ManagedList) pvs.getPropertyValue("filters").getValue();
+    	} else {
+    		filters = new ManagedList();
+    		pvs.addPropertyValue("filters", filters);
+    	}
+    	
+    	filters.add(filter);
+    }
+
+    /**
+     * Bean which holds the list of filters which are maintained in the context and modified by calls to 
+     * addHttpFilter. The post processor retrieves these before injecting the list into the FilterChainProxy.
+     */
+    public static class FilterChainList {
+    	List filters;
+
+		public List getFilters() {
+			return filters;
+		}
+
+		public void setFilters(List filters) {
+			this.filters = filters;
+		}
+    }    
 }

+ 12 - 53
core/src/main/java/org/springframework/security/config/FilterChainProxyPostProcessor.java

@@ -2,12 +2,9 @@ package org.springframework.security.config;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import javax.servlet.Filter;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.BeansException;
@@ -16,9 +13,8 @@ import org.springframework.beans.factory.BeanFactoryAware;
 import org.springframework.beans.factory.ListableBeanFactory;
 import org.springframework.beans.factory.config.BeanPostProcessor;
 import org.springframework.core.OrderComparator;
-import org.springframework.core.Ordered;
+import org.springframework.security.config.ConfigUtils.FilterChainList;
 import org.springframework.security.util.FilterChainProxy;
-import org.springframework.util.Assert;
 
 /**
  * 
@@ -29,70 +25,33 @@ import org.springframework.util.Assert;
 public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFactoryAware {
     private Log logger = LogFactory.getLog(getClass());
     
-    private ListableBeanFactory beanFactory;    
-
+    private ListableBeanFactory beanFactory;
+    
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
         if(!beanName.equals(BeanIds.FILTER_CHAIN_PROXY)) {
             return bean;
         }
         
         FilterChainProxy filterChainProxy = (FilterChainProxy) bean;
-        // Set the default match
-        List defaultFilterChain = orderFilters(beanFactory);
-
+        FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST);
+        
+        List filters = new ArrayList(filterList.getFilters());
+        Collections.sort(filters, new OrderComparator());
         // Note that this returns a copy
         Map filterMap = filterChainProxy.getFilterChainMap();
-        String allUrlsMatch = filterChainProxy.getMatcher().getUniversalMatchPattern();
-
-        filterMap.put(allUrlsMatch, defaultFilterChain);
+        filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters);
         filterChainProxy.setFilterChainMap(filterMap);
 
-        logger.info("Configured filter chain(s): " + filterChainProxy);        
+        logger.info("FilterChainProxy: " + filterChainProxy);        
 
         return bean;
     }
 
-    private List orderFilters(ListableBeanFactory beanFactory) {
-        Map filters = beanFactory.getBeansOfType(Filter.class);
-
-        Assert.notEmpty(filters, "No filters found in app context!");
-
-        Iterator ids = filters.keySet().iterator();
-
-        List orderedFilters = new ArrayList();
-
-        while (ids.hasNext()) {
-            String id = (String) ids.next();
-            Filter filter = (Filter) filters.get(id);
-
-            if (filter instanceof FilterChainProxy) {
-                continue;
-            }
-
-            // Filters must be Spring security filters or wrapped using <custom-filter>
-            if (!filter.getClass().getName().startsWith("org.springframework.security")) {
-                continue;
-            }
-
-            if (!(filter instanceof Ordered)) {
-                logger.info("Filter " + id + " doesn't implement the Ordered interface, skipping it.");
-                continue;
-            }
-
-            orderedFilters.add(filter);
-        }
-
-        Collections.sort(orderedFilters, new OrderComparator());
-
-        return orderedFilters;
-    }    
-
     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
         return bean;
     }
 
-    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
-        this.beanFactory = (ListableBeanFactory) beanFactory;
-    }
-
+	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+		this.beanFactory = (ListableBeanFactory) beanFactory;
+	}
 }

+ 47 - 43
core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java

@@ -97,7 +97,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
     static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
     static final String ATT_ONCE_PER_REQUEST = "once-per-request";
     static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
-    
 
     public BeanDefinition parse(Element element, ParserContext parserContext) {
         ConfigUtils.registerProviderManagerIfNecessary(parserContext);
@@ -117,9 +116,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap, 
                 convertPathsToLowerCase, parserContext);
 
-        registerHttpSessionIntegrationFilter(element, registry);
+        registerHttpSessionIntegrationFilter(element, parserContext);
         
-        registerServletApiFilter(element, registry);
+        registerServletApiFilter(element, parserContext);
                 
         // Set up the access manager reference for http
         String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
@@ -134,15 +133,15 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
                 DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
         registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
 
-        registerExceptionTranslationFilter(element.getAttribute(ATT_ACCESS_DENIED_PAGE), registry);
+        registerExceptionTranslationFilter(element.getAttribute(ATT_ACCESS_DENIED_PAGE), parserContext);
 
 
         if (channelRequestMap.size() > 0) {
             // At least one channel requirement has been specified
-            registerChannelProcessingBeans(parserContext.getRegistry(), matcher, channelRequestMap);
+            registerChannelProcessingBeans(parserContext, matcher, channelRequestMap);
         }        
                 
-        registerFilterSecurityInterceptor(element, registry, matcher, accessManagerId, 
+        registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId, 
                 parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, parserContext));
 
         boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext);
@@ -200,15 +199,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
         filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
         pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
-        pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
-        
-        // Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
-        RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
-        filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
-        pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
+        pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);        
     }
 
-    private void registerHttpSessionIntegrationFilter(Element element, BeanDefinitionRegistry registry) {
+    private void registerHttpSessionIntegrationFilter(Element element, ParserContext pc) {
         RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
         
         String createSession = element.getAttribute(ATT_CREATE_SESSION);
@@ -224,19 +218,21 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
         }
 
-        registry.registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
+        pc.getRegistry().registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
+        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER));
     }
 
     // Adds the servlet-api integration filter if required    
-    private void registerServletApiFilter(Element element, BeanDefinitionRegistry registry) {
+    private void registerServletApiFilter(Element element, ParserContext pc) {
         String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
         if (!StringUtils.hasText(provideServletApi)) {
             provideServletApi = DEF_SERVLET_API_PROVISION;
         }
 
         if ("true".equals(provideServletApi)) {
-            registry.registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,
+            pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,
                     new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class));
+            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
         }
     }
     
@@ -253,7 +249,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         return true;
     }
     
-    private void registerExceptionTranslationFilter(String accessDeniedPage, BeanDefinitionRegistry registry) {
+    private void registerExceptionTranslationFilter(String accessDeniedPage, ParserContext pc) {
         BeanDefinitionBuilder exceptionTranslationFilterBuilder
             = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
  
@@ -263,10 +259,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
         }
 
-        registry.registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());        
+        pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
+        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
     }
     
-    private void registerFilterSecurityInterceptor(Element element, BeanDefinitionRegistry registry, UrlMatcher matcher,
+    private void registerFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher,
             String accessManagerId, LinkedHashMap filterInvocationDefinitionMap) {
         BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
 
@@ -279,10 +276,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         
         builder.addPropertyValue("objectDefinitionSource", 
                 new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap));
-        registry.registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition());
+        pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition());
+        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
     }
     
-    private void registerChannelProcessingBeans(BeanDefinitionRegistry registry, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
+    private void registerChannelProcessingBeans(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
         RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
         channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
                 new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER));
@@ -307,11 +305,13 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         channelProcessors.add(inSecureChannelProcessor);
         channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors);
 
-        registry.registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
-        registry.registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
+        pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
+        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
+        pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
+        
     }
     
-    private void registerSessionFixationProtectionFilter(ParserContext parserContext, String sessionFixationAttribute, boolean sessionControlEnabled) {
+    private void registerSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
         if(!StringUtils.hasText(sessionFixationAttribute)) {
             sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
         }
@@ -324,13 +324,14 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             if (sessionControlEnabled) {
                 sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
             }
-            parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER, 
+            pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER, 
                     sessionFixationFilter.getBeanDefinition());
+            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
         }        
         
     }
     
-    private void parseBasicFormLoginAndOpenID(Element element, ParserContext parserContext, boolean autoConfig) {
+    private void parseBasicFormLoginAndOpenID(Element element, ParserContext pc, boolean autoConfig) {
         RootBeanDefinition formLoginFilter = null;
         RootBeanDefinition formLoginEntryPoint = null;
         String formLoginPage = null;        
@@ -345,7 +346,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         
         Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
         if (basicAuthElt != null || autoConfig) {
-            new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, parserContext);
+            new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
         }        
         
     	Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
@@ -354,7 +355,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         	FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check", 
         			"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
         	
-            parser.parse(formLoginElt, parserContext);
+            parser.parse(formLoginElt, pc);
             formLoginFilter = parser.getFilterBean();
             formLoginEntryPoint = parser.getEntryPointBean();
             formLoginPage = parser.getLoginPage();
@@ -366,7 +367,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         	FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check", 
         			"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
         	
-            parser.parse(openIDLoginElt, parserContext);
+            parser.parse(openIDLoginElt, pc);
             openIDFilter = parser.getFilterBean();
             openIDEntryPoint = parser.getEntryPointBean();
             openIDLoginPage = parser.getLoginPage();
@@ -381,23 +382,25 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             }
             
             BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
-            ConfigUtils.getRegisteredProviders(parserContext).add(openIDProvider);
+            ConfigUtils.getRegisteredProviders(pc).add(openIDProvider);
             
-            parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
+            pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
         }
         
         boolean needLoginPage = false;
         
         if (formLoginFilter != null) {
         	needLoginPage = true;
-	        parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
-	        parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
+	        pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
+	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
+	        pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
         }        
 
         if (openIDFilter != null) {
         	needLoginPage = true;
-	        parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
-	        parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
+	        pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
+	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
+	        pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
         }
 
         // If no login page has been defined, add in the default page generator.
@@ -415,8 +418,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             	loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
             }
 
-            parserContext.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, 
+            pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, 
             		loginPageFilter.getBeanDefinition());
+            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
         }
         
         // We need to establish the main entry point.
@@ -424,39 +428,39 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
         
         if (StringUtils.hasText(customEntryPoint)) {
-            parserContext.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
+            pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
             return;
         }
         
         // Basic takes precedence if explicit element is used and no others are configured
         if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
-        	parserContext.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
+        	pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
         	return;
         }
         
         // If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
         // has been set
         if (formLoginFilter != null && openIDLoginPage == null) {
-        	parserContext.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
+        	pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
         	return;        	
         }
         
         // Otherwise use OpenID if enabled
         if (openIDFilter != null && formLoginFilter == null) {
-        	parserContext.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
+        	pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
         	return;        	
         }
         
         // If X.509 has been enabled, use the preauth entry point.
         if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) {
-            parserContext.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
+            pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
             return;
         }
         
-        parserContext.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
+        pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
         		"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
         		"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ", 
-                parserContext.extractSource(element));
+                pc.extractSource(element));
     }
     
     static UrlMatcher createUrlMatcher(Element element) {

+ 2 - 1
core/src/main/java/org/springframework/security/config/LogoutBeanDefinitionParser.java

@@ -70,7 +70,8 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
         builder.addConstructorArg(handlers);
 
         parserContext.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, builder.getBeanDefinition());
-
+        ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER));
+        
         return null;
 	}
 }

+ 11 - 6
core/src/main/java/org/springframework/security/config/OrderedFilterBeanDefinitionDecorator.java

@@ -9,8 +9,8 @@ import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 
-import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
 import org.springframework.beans.factory.xml.ParserContext;
@@ -22,8 +22,8 @@ import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
 /**
- * Replaces a Spring bean of type "Filter" with a wrapper class which implements the <tt>Ordered</tt>
- * interface. This allows user to add their own filter to the security chain. If the user's filter
+ * Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.  
+ * This allows user to add their own custom filters to the security chain. If the user's filter
  * already implements Ordered, and no "order" attribute is specified, the filter's default order will be used.
  *
  * @author Luke Taylor
@@ -39,16 +39,17 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
         Element elt = (Element)node;
         String order = getOrder(elt, parserContext);
 
-        BeanDefinition filter = holder.getBeanDefinition();
         BeanDefinitionBuilder wrapper = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.config.OrderedFilterBeanDefinitionDecorator$OrderedFilterDecorator");
         wrapper.addConstructorArg(holder.getBeanName());
-        wrapper.addConstructorArg(filter);
+        wrapper.addConstructorArg(new RuntimeBeanReference(holder.getBeanName()));
 
         if (StringUtils.hasText(order)) {
             wrapper.addPropertyValue("order", order);
         }
 
-        return new BeanDefinitionHolder(wrapper.getBeanDefinition(), holder.getBeanName());
+        ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
+        
+        return holder;
     }
 
     /**
@@ -123,5 +124,9 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
 		public String toString() {
 			return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
 		}
+		
+		Filter getDelegate() {
+			return delegate;
+		}
     }
 }

+ 1 - 0
core/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java

@@ -103,6 +103,7 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
 
         parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
         parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter);
+        ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER));
 
         return null;
     }

+ 1 - 0
core/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java

@@ -62,6 +62,7 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
 	    filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
 
 	    parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, filterBuilder.getBeanDefinition());
+	    ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.X509_FILTER));
 
 	    return null;
     }

+ 5 - 2
core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java

@@ -259,7 +259,8 @@ public class HttpSecurityBeanDefinitionParserTests {
 
     @Test
     public void externalFiltersAreTreatedCorrectly() throws Exception {
-        // Decorated user-filter should be added to stack. The other one should be ignored
+        // Decorated user-filter should be added to stack. The other MockFilter and the un-decorated standard filter
+    	// should be ignored
         setContext(
                 "<http auto-config='true'/>" + AUTH_PROVIDER_XML +
                 "<b:bean id='userFilter' class='org.springframework.security.util.MockFilter'>" +
@@ -268,7 +269,9 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "<b:bean id='userFilter2' class='org.springframework.security.util.MockFilter'>" +
                 "    <custom-filter position='FIRST'/>" +
                 "</b:bean>" +                
-                "<b:bean id='userFilter3' class='org.springframework.security.util.MockFilter'/>");
+                "<b:bean id='userFilter3' class='org.springframework.security.util.MockFilter'/>" +
+                "<b:bean id='userFilter4' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'/>"
+                );
         List filters = getFilters("/someurl");
 
         assertEquals(13, filters.size());