Explorar o código

SEC-1186: intermediate commit of namespace changes for improved tooling support

Luke Taylor %!s(int64=16) %!d(string=hai) anos
pai
achega
8ddd96af2b
Modificáronse 49 ficheiros con 2363 adicións e 1177 borrados
  1. 0 2
      config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java
  2. 9 8
      config/src/main/java/org/springframework/security/config/AuthenticationManagerBeanDefinitionParser.java
  3. 15 15
      config/src/main/java/org/springframework/security/config/BeanIds.java
  4. 43 41
      config/src/main/java/org/springframework/security/config/ConfigUtils.java
  5. 22 22
      config/src/main/java/org/springframework/security/config/EntryPointInjectionBeanPostProcessor.java
  6. 1 1
      config/src/main/java/org/springframework/security/config/FilterChainOrder.java
  7. 98 98
      config/src/main/java/org/springframework/security/config/FilterChainProxyPostProcessor.java
  8. 24 24
      config/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java
  9. 19 14
      config/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java
  10. 421 181
      config/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java
  11. 1 1
      config/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java
  12. 2 2
      config/src/main/java/org/springframework/security/config/NamespaceAuthenticationManager.java
  13. 1 2
      config/src/main/java/org/springframework/security/config/OrderedFilterBeanDefinitionDecorator.java
  14. 25 25
      config/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java
  15. 17 17
      config/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java
  16. 2 7
      config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java
  17. 9 3
      config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc
  18. 1478 480
      config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd
  19. 57 41
      config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java
  20. 10 1
      config/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java
  21. 9 2
      config/src/test/java/org/springframework/security/config/TestBusinessBeanImpl.java
  22. 2 0
      config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java
  23. 21 1
      web/src/main/java/org/springframework/security/web/FilterChainProxy.java
  24. 10 1
      web/src/main/java/org/springframework/security/web/SpringSecurityFilter.java
  25. 0 5
      web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java
  26. 0 5
      web/src/main/java/org/springframework/security/web/access/channel/ChannelProcessingFilter.java
  27. 1 6
      web/src/main/java/org/springframework/security/web/access/intercept/FilterSecurityInterceptor.java
  28. 8 14
      web/src/main/java/org/springframework/security/web/authentication/AnonymousProcessingFilter.java
  29. 4 10
      web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationProcessingFilter.java
  30. 9 13
      web/src/main/java/org/springframework/security/web/authentication/concurrent/ConcurrentSessionFilter.java
  31. 0 5
      web/src/main/java/org/springframework/security/web/authentication/logout/LogoutFilter.java
  32. 16 21
      web/src/main/java/org/springframework/security/web/authentication/preauth/RequestHeaderPreAuthenticatedProcessingFilter.java
  33. 0 4
      web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java
  34. 0 4
      web/src/main/java/org/springframework/security/web/authentication/preauth/websphere/WebSpherePreAuthenticatedProcessingFilter.java
  35. 3 7
      web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PreAuthenticatedProcessingFilter.java
  36. 11 15
      web/src/main/java/org/springframework/security/web/authentication/rememberme/RememberMeProcessingFilter.java
  37. 0 5
      web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserProcessingFilter.java
  38. 0 5
      web/src/main/java/org/springframework/security/web/authentication/ui/DefaultLoginPageGeneratingFilter.java
  39. 7 12
      web/src/main/java/org/springframework/security/web/authentication/www/BasicProcessingFilter.java
  40. 0 5
      web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java
  41. 0 7
      web/src/main/java/org/springframework/security/web/context/HttpSessionContextIntegrationFilter.java
  42. 0 5
      web/src/main/java/org/springframework/security/web/context/SecurityContextPersistenceFilter.java
  43. 0 5
      web/src/main/java/org/springframework/security/web/session/SessionFixationProtectionFilter.java
  44. 0 5
      web/src/main/java/org/springframework/security/web/wrapper/SecurityContextHolderAwareRequestFilter.java
  45. 0 4
      web/src/test/java/org/springframework/security/web/authentication/AbstractProcessingFilterTests.java
  46. 0 5
      web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java
  47. 0 4
      web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java
  48. 4 7
      web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedProcessingFilterTests.java
  49. 4 10
      web/src/test/java/org/springframework/security/web/context/SecurityContextPersistenceFilterTests.java

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

@@ -3,8 +3,6 @@ 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.RootBeanDefinition;
 import org.springframework.beans.factory.xml.BeanDefinitionParser;
 import org.springframework.beans.factory.xml.ParserContext;

+ 9 - 8
config/src/main/java/org/springframework/security/config/AuthenticationManagerBeanDefinitionParser.java

@@ -22,31 +22,32 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
     private static final String ATT_ALIAS = "alias";
 
     public BeanDefinition parse(Element element, ParserContext parserContext) {
-        ConfigUtils.registerProviderManagerIfNecessary(parserContext);
-        
+        ConfigUtils.registerProviderManagerIfNecessary(parserContext, element);
+
         String alias = element.getAttribute(ATT_ALIAS);
 
         if (!StringUtils.hasText(alias)) {
             parserContext.getReaderContext().error(ATT_ALIAS + " is required.", element );
         }
-        
+
         String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF);
-        
+
         if (StringUtils.hasText(sessionControllerRef)) {
             BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
-            ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext, 
+            ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext,
                     BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
-            authManager.getPropertyValues().addPropertyValue("sessionController", 
+            authManager.getPropertyValues().addPropertyValue("sessionController",
                     new RuntimeBeanReference(sessionControllerRef));
             RootBeanDefinition sessionRegistryInjector = new RootBeanDefinition(SessionRegistryInjectionBeanPostProcessor.class);
             sessionRegistryInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
             sessionRegistryInjector.getConstructorArgumentValues().addGenericArgumentValue(sessionControllerRef);
-            
+
             parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_REGISTRY_INJECTION_POST_PROCESSOR, sessionRegistryInjector);
         }
 
         parserContext.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
+        parserContext.getReaderContext().fireAliasRegistered(BeanIds.AUTHENTICATION_MANAGER, alias, parserContext.extractSource(element));
 
         return null;
-    }    
+    }
 }

+ 15 - 15
config/src/main/java/org/springframework/security/config/BeanIds.java

@@ -16,20 +16,20 @@ public abstract class BeanIds {
     /** Package protected as end users shouldn't really be using this BFPP directly */
     static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP";
     static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
-    static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor";
+//    static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor";
     static final String USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR = "_userServiceInjectionPostProcessor";
     static final String SESSION_REGISTRY_INJECTION_POST_PROCESSOR = "_sessionRegistryInjectionPostProcessor";
-    static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
-    static final String FILTER_LIST = "_filterChainList";
+//    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";
-    public static final String ANONYMOUS_PROCESSING_FILTER = "_anonymousProcessingFilter";
+//    public static final String ANONYMOUS_PROCESSING_FILTER = "_anonymousProcessingFilter";
     public static final String ANONYMOUS_AUTHENTICATION_PROVIDER = "_anonymousAuthenticationProvider";
-    public static final String BASIC_AUTHENTICATION_FILTER = "_basicAuthenticationFilter";
+//    public static final String BASIC_AUTHENTICATION_FILTER = "_basicAuthenticationFilter";
     public static final String BASIC_AUTHENTICATION_ENTRY_POINT = "_basicAuthenticationEntryPoint";
     public static final String SESSION_REGISTRY = "_sessionRegistry";
-    public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter";
+//    public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter";
     public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
     public static final String METHOD_ACCESS_MANAGER = "_defaultMethodAccessManager";
     public static final String WEB_ACCESS_MANAGER = "_webAccessManager";
@@ -42,18 +42,18 @@ public abstract class BeanIds {
     public static final String OPEN_ID_PROVIDER = "_openIDAuthenticationProvider";
     public static final String MAIN_ENTRY_POINT = "_mainEntryPoint";
     public static final String FILTER_CHAIN_PROXY = "_filterChainProxy";
-    public static final String SECURITY_CONTEXT_PERSISTENCE_FILTER = "_securityContextPersistenceFilter";
+//    public static final String SECURITY_CONTEXT_PERSISTENCE_FILTER = "_securityContextPersistenceFilter";
     public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider";
-    public static final String LOGOUT_FILTER = "_logoutFilter";
-    public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter";
-    public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor";
-    public static final String CHANNEL_PROCESSING_FILTER = "_channelProcessingFilter";
+//    public static final String LOGOUT_FILTER = "_logoutFilter";
+//    public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter";
+//    public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor";
+//    public static final String CHANNEL_PROCESSING_FILTER = "_channelProcessingFilter";
     public static final String CHANNEL_DECISION_MANAGER = "_channelDecisionManager";
-    public static final String REMEMBER_ME_FILTER = "_rememberMeFilter";
+//    public static final String REMEMBER_ME_FILTER = "_rememberMeFilter";
     public static final String REMEMBER_ME_SERVICES = "_rememberMeServices";
     public static final String REMEMBER_ME_AUTHENTICATION_PROVIDER = "_rememberMeAuthenticationProvider";
-    public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
-    public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
+//    public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
+//    public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
     public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
     public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = "_methodSecurityMetadataSourceAdvisor";
     public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
@@ -62,7 +62,7 @@ public abstract class BeanIds {
     public static final String EMBEDDED_APACHE_DS = "_apacheDirectoryServerContainer";
     public static final String CONTEXT_SOURCE = "_securityContextSource";
     public static final String PORT_MAPPER = "_portMapper";
-    public static final String X509_FILTER = "_x509ProcessingFilter";
+//    public static final String X509_FILTER = "_x509ProcessingFilter";
     public static final String X509_AUTH_PROVIDER = "_x509AuthenticationProvider";
     public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
     public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";

+ 43 - 41
config/src/main/java/org/springframework/security/config/ConfigUtils.java

@@ -3,8 +3,6 @@ package org.springframework.security.config;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.springframework.beans.BeanMetadataElement;
-import org.springframework.beans.MutablePropertyValues;
 import org.springframework.beans.PropertyValue;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -20,6 +18,7 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
 import org.springframework.security.access.vote.RoleVoter;
 import org.springframework.security.web.util.UrlUtils;
 import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
 import org.w3c.dom.Element;
 
 /**
@@ -40,7 +39,7 @@ abstract class ConfigUtils {
     }
 
     @SuppressWarnings("unchecked")
-    static BeanDefinition createAccessManagerBean(Class<? extends AccessDecisionVoter>... voters) {
+    static RootBeanDefinition createAccessManagerBean(Class<? extends AccessDecisionVoter>... voters) {
         ManagedList defaultVoters = new ManagedList(voters.length);
 
         for(Class<? extends AccessDecisionVoter> voter : voters) {
@@ -49,7 +48,7 @@ abstract class ConfigUtils {
 
         BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
         accessMgrBuilder.addPropertyValue("decisionVoters", defaultVoters);
-        return accessMgrBuilder.getBeanDefinition();
+        return (RootBeanDefinition) accessMgrBuilder.getBeanDefinition();
     }
 
     public static int countNonEmpty(String[] objects) {
@@ -69,20 +68,24 @@ abstract class ConfigUtils {
      * the BeanDefinition for it. This method will typically be called when registering authentication providers
      * using the &lt;security:provider /> tag or by other beans which have a dependency on the
      * authentication manager.
+     * @param element the source element under which this bean should be registered.
      */
-    static void registerProviderManagerIfNecessary(ParserContext parserContext) {
-        if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) {
+    static void registerProviderManagerIfNecessary(ParserContext pc, Element element) {
+
+        if(pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) {
             return;
         }
 
-        BeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class);
+        RootBeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class);
         authManager.getPropertyValues().addPropertyValue("providerBeanNames", new ArrayList<String>());
-        parserContext.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager);
+        authManager.setSource(pc.extractSource(element.getOwnerDocument().getFirstChild()));
+        pc.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager);
+        pc.registerBeanComponent(new BeanComponentDefinition(authManager, BeanIds.AUTHENTICATION_MANAGER));
     }
 
     @SuppressWarnings("unchecked")
     static void addAuthenticationProvider(ParserContext parserContext, String beanName) {
-        registerProviderManagerIfNecessary(parserContext);
+        registerProviderManagerIfNecessary(parserContext, null);
         BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
         ((ArrayList) authManager.getPropertyValues().getPropertyValue("providerBeanNames").getValue()).add(beanName);
     }
@@ -106,37 +109,37 @@ abstract class ConfigUtils {
         return manager;
     }
 
-    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);
-        pc.registerBeanComponent(new BeanComponentDefinition(filterList, BeanIds.FILTER_LIST));
-    }
-
-    @SuppressWarnings("unchecked")
-    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);
-    }
+//    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);
+//        pc.registerBeanComponent(new BeanComponentDefinition(filterList, BeanIds.FILTER_LIST));
+//    }
+
+ //   @SuppressWarnings("unchecked")
+//    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
@@ -167,7 +170,6 @@ abstract class ConfigUtils {
     }
 
     static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
-        registerProviderManagerIfNecessary(pc);
         BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
         PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
 

+ 22 - 22
config/src/main/java/org/springframework/security/config/EntryPointInjectionBeanPostProcessor.java

@@ -24,28 +24,28 @@ public class EntryPointInjectionBeanPostProcessor implements BeanPostProcessor,
 
     @SuppressWarnings("unchecked")
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-        if (!BeanIds.EXCEPTION_TRANSLATION_FILTER.equals(beanName)) {
-            return bean;
-        }
-
-        logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
-
-        ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
-
-        Object entryPoint = null;
-
-        if (beanFactory.containsBean(BeanIds.MAIN_ENTRY_POINT)) {
-            entryPoint = beanFactory.getBean(BeanIds.MAIN_ENTRY_POINT);
-            logger.info("Using main configured AuthenticationEntryPoint.");
-        } else {
-            Map entryPoints = beanFactory.getBeansOfType(AuthenticationEntryPoint.class);
-            Assert.isTrue(entryPoints.size() != 0, "No AuthenticationEntryPoint instances defined");
-            Assert.isTrue(entryPoints.size() == 1, "More than one AuthenticationEntryPoint defined in context");
-            entryPoint = entryPoints.values().toArray()[0];
-        }
-
-        logger.info("Using bean '" + entryPoint + "' as the entry point.");
-        etf.setAuthenticationEntryPoint((AuthenticationEntryPoint) entryPoint);
+//        if (!BeanIds.EXCEPTION_TRANSLATION_FILTER.equals(beanName)) {
+//            return bean;
+//        }
+//
+//        logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
+//
+//        ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
+//
+//        Object entryPoint = null;
+//
+//        if (beanFactory.containsBean(BeanIds.MAIN_ENTRY_POINT)) {
+//            entryPoint = beanFactory.getBean(BeanIds.MAIN_ENTRY_POINT);
+//            logger.info("Using main configured AuthenticationEntryPoint.");
+//        } else {
+//            Map entryPoints = beanFactory.getBeansOfType(AuthenticationEntryPoint.class);
+//            Assert.isTrue(entryPoints.size() != 0, "No AuthenticationEntryPoint instances defined");
+//            Assert.isTrue(entryPoints.size() == 1, "More than one AuthenticationEntryPoint defined in context");
+//            entryPoint = entryPoints.values().toArray()[0];
+//        }
+//
+//        logger.info("Using bean '" + entryPoint + "' as the entry point.");
+//        etf.setAuthenticationEntryPoint((AuthenticationEntryPoint) entryPoint);
 
         return bean;
     }

+ 1 - 1
web/src/main/java/org/springframework/security/web/FilterChainOrder.java → config/src/main/java/org/springframework/security/config/FilterChainOrder.java

@@ -1,4 +1,4 @@
-package org.springframework.security.web;
+package org.springframework.security.config;
 
 import org.springframework.util.Assert;
 

+ 98 - 98
config/src/main/java/org/springframework/security/config/FilterChainProxyPostProcessor.java

@@ -45,51 +45,51 @@ public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFac
 
     @SuppressWarnings("unchecked")
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-        if(!BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
-            return bean;
-        }
-
-        FilterChainProxy filterChainProxy = (FilterChainProxy) bean;
-        FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST);
-
-        List<Filter> filters = new ArrayList<Filter>(filterList.getFilters());
-        Collections.sort(filters, new OrderComparator());
-
-        logger.info("Checking sorted filter chain: " + filters);
-
-        for(int i=0; i < filters.size(); i++) {
-            Ordered filter = (Ordered)filters.get(i);
-
-            if (i > 0) {
-                Ordered previous = (Ordered)filters.get(i-1);
-                if (filter.getOrder() == previous.getOrder()) {
-                    throw new SecurityConfigurationException("Filters '" + unwrapFilter(filter) + "' and '" +
-                            unwrapFilter(previous) + "' have the same 'order' value. When using custom filters, " +
-                                    "please make sure the positions do not conflict with default filters. " +
-                                    "Alternatively you can disable the default filters by removing the corresponding " +
-                                    "child elements from <http> and avoiding the use of <http auto-config='true'>.");
-                }
-            }
-        }
-
-        logger.info("Filter chain...");
-        for (int i=0; i < filters.size(); i++) {
-        // Remove the ordered wrapper from the filter and put it back in the chain at the same position.
-            Filter filter = unwrapFilter(filters.get(i));
-            logger.info("[" + i + "] - " + filter);
-            filters.set(i, filter);
-        }
-
-        checkFilterStack(filters);
-
-        // Note that this returns a copy
-        Map<String, List<Filter>> filterMap = filterChainProxy.getFilterChainMap();
-        filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters);
-        filterChainProxy.setFilterChainMap(filterMap);
-
-        checkLoginPageIsntProtected(filterChainProxy);
-
-        logger.info("FilterChainProxy: " + filterChainProxy);
+//        if(!BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
+//            return bean;
+//        }
+//
+//        FilterChainProxy filterChainProxy = (FilterChainProxy) bean;
+//        FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST);
+//
+//        List<Filter> filters = new ArrayList<Filter>(filterList.getFilters());
+//        Collections.sort(filters, new OrderComparator());
+//
+//        logger.info("Checking sorted filter chain: " + filters);
+//
+//        for(int i=0; i < filters.size(); i++) {
+//            Ordered filter = (Ordered)filters.get(i);
+//
+//            if (i > 0) {
+//                Ordered previous = (Ordered)filters.get(i-1);
+//                if (filter.getOrder() == previous.getOrder()) {
+//                    throw new SecurityConfigurationException("Filters '" + unwrapFilter(filter) + "' and '" +
+//                            unwrapFilter(previous) + "' have the same 'order' value. When using custom filters, " +
+//                                    "please make sure the positions do not conflict with default filters. " +
+//                                    "Alternatively you can disable the default filters by removing the corresponding " +
+//                                    "child elements from <http> and avoiding the use of <http auto-config='true'>.");
+//                }
+//            }
+//        }
+//
+//        logger.info("Filter chain...");
+//        for (int i=0; i < filters.size(); i++) {
+//        // Remove the ordered wrapper from the filter and put it back in the chain at the same position.
+//            Filter filter = unwrapFilter(filters.get(i));
+//            logger.info("[" + i + "] - " + filter);
+//            filters.set(i, filter);
+//        }
+//
+//        checkFilterStack(filters);
+//
+//        // Note that this returns a copy
+//        Map<String, List<Filter>> filterMap = filterChainProxy.getFilterChainMap();
+//        filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters);
+//        filterChainProxy.setFilterChainMap(filterMap);
+//
+//        checkLoginPageIsntProtected(filterChainProxy);
+//
+//        logger.info("FilterChainProxy: " + filterChainProxy);
 
         return bean;
     }
@@ -126,59 +126,59 @@ public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFac
 
     /* Checks for the common error of having a login page URL protected by the security interceptor */
     private void checkLoginPageIsntProtected(FilterChainProxy fcp) {
-        ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
-
-        if (etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint) {
-            String loginPage =
-                ((LoginUrlAuthenticationEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
-            List<Filter> filters = fcp.getFilters(loginPage);
-            logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
-
-            if (filters == null || filters.isEmpty()) {
-                logger.debug("Filter chain is empty for the login page");
-                return;
-            }
-
-            if (loginPage.equals(DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL) &&
-                    beanFactory.containsBean(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)) {
-                logger.debug("Default generated login page is in use");
-                return;
-            }
-
-            FilterSecurityInterceptor fsi =
-                    ((FilterSecurityInterceptor)beanFactory.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR));
-            DefaultFilterInvocationSecurityMetadataSource fids =
-                    (DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource();
-            List<ConfigAttribute> attributes = fids.lookupAttributes(loginPage, "POST");
-
-            if (attributes == null) {
-                logger.debug("No access attributes defined for login page URL");
-                if (fsi.isRejectPublicInvocations()) {
-                    logger.warn("FilterSecurityInterceptor is configured to reject public invocations." +
-                            " Your login page may not be accessible.");
-                }
-                return;
-            }
-
-            if (!beanFactory.containsBean(BeanIds.ANONYMOUS_PROCESSING_FILTER)) {
-                logger.warn("The login page is being protected by the filter chain, but you don't appear to have" +
-                        " anonymous authentication enabled. This is almost certainly an error.");
-                return;
-            }
-
-            // Simulate an anonymous access with the supplied attributes.
-            AnonymousProcessingFilter anonPF = (AnonymousProcessingFilter) beanFactory.getBean(BeanIds.ANONYMOUS_PROCESSING_FILTER);
-            AnonymousAuthenticationToken token =
-                    new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
-                            anonPF.getUserAttribute().getAuthorities());
-            try {
-                fsi.getAccessDecisionManager().decide(token, new Object(), fids.lookupAttributes(loginPage, "POST"));
-            } catch (Exception e) {
-                logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " +
-                        "an error. Please check your configuration allows unauthenticated access to the configured " +
-                        "login page. (Simulated access was rejected: " + e + ")");
-            }
-        }
+//        ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
+//
+//        if (etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint) {
+//            String loginPage =
+//                ((LoginUrlAuthenticationEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
+//            List<Filter> filters = fcp.getFilters(loginPage);
+//            logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
+//
+//            if (filters == null || filters.isEmpty()) {
+//                logger.debug("Filter chain is empty for the login page");
+//                return;
+//            }
+//
+//            if (loginPage.equals(DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL) &&
+//                    beanFactory.containsBean(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)) {
+//                logger.debug("Default generated login page is in use");
+//                return;
+//            }
+//
+//            FilterSecurityInterceptor fsi =
+//                    ((FilterSecurityInterceptor)beanFactory.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR));
+//            DefaultFilterInvocationSecurityMetadataSource fids =
+//                    (DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource();
+//            List<ConfigAttribute> attributes = fids.lookupAttributes(loginPage, "POST");
+//
+//            if (attributes == null) {
+//                logger.debug("No access attributes defined for login page URL");
+//                if (fsi.isRejectPublicInvocations()) {
+//                    logger.warn("FilterSecurityInterceptor is configured to reject public invocations." +
+//                            " Your login page may not be accessible.");
+//                }
+//                return;
+//            }
+//
+//            if (!beanFactory.containsBean(BeanIds.ANONYMOUS_PROCESSING_FILTER)) {
+//                logger.warn("The login page is being protected by the filter chain, but you don't appear to have" +
+//                        " anonymous authentication enabled. This is almost certainly an error.");
+//                return;
+//            }
+//
+//            // Simulate an anonymous access with the supplied attributes.
+//            AnonymousProcessingFilter anonPF = (AnonymousProcessingFilter) beanFactory.getBean(BeanIds.ANONYMOUS_PROCESSING_FILTER);
+//            AnonymousAuthenticationToken token =
+//                    new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
+//                            anonPF.getUserAttribute().getAuthorities());
+//            try {
+//                fsi.getAccessDecisionManager().decide(token, new Object(), fids.lookupAttributes(loginPage, "POST"));
+//            } catch (Exception e) {
+//                logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " +
+//                        "an error. Please check your configuration allows unauthenticated access to the configured " +
+//                        "login page. (Simulated access was rejected: " + e + ")");
+//            }
+//        }
     }
 
     /**

+ 24 - 24
config/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java

@@ -1,28 +1,25 @@
 package org.springframework.security.config;
 
-import org.springframework.beans.PropertyValue;
+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.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.support.RootBeanDefinition;
-import org.springframework.beans.factory.xml.BeanDefinitionParser;
 import org.springframework.beans.factory.xml.ParserContext;
 import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
 import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
 import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
 import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
 import org.springframework.util.StringUtils;
-
 import org.w3c.dom.Element;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 
 /**
  * @author Luke Taylor
  * @author Ben Alex
  * @version $Id$
  */
-public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
+public class FormLoginBeanDefinitionParser {
     protected final Log logger = LogFactory.getLog(getClass());
 
     private static final String ATT_LOGIN_URL = "login-processing-url";
@@ -52,7 +49,7 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
         this.filterClassName = filterClassName;
     }
 
-    public BeanDefinition parse(Element elt, ParserContext pc) {
+    public BeanDefinition parse(Element elt, ParserContext pc, RootBeanDefinition sfpf) {
         String loginUrl = null;
         String defaultTargetUrl = null;
         String authenticationFailureUrl = null;
@@ -62,17 +59,16 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
 
         Object source = null;
 
-        // Copy values from the session fixation protection filter
-        final Boolean sessionFixationProtectionEnabled =
-            new Boolean(pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
-        Boolean migrateSessionAttributes = Boolean.FALSE;
-
-        if (sessionFixationProtectionEnabled.booleanValue()) {
-            PropertyValue pv =
-                    pc.getRegistry().getBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)
-                        .getPropertyValues().getPropertyValue("migrateSessionAttributes");
-            migrateSessionAttributes = (Boolean)pv.getValue();
-        }
+//        final Boolean sessionFixationProtectionEnabled =
+//            new Boolean(pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
+//        Boolean migrateSessionAttributes = Boolean.FALSE;
+//
+//        if (sessionFixationProtectionEnabled.booleanValue()) {
+//            PropertyValue pv =
+//                    pc.getRegistry().getBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)
+//                        .getPropertyValues().getPropertyValue("migrateSessionAttributes");
+//            migrateSessionAttributes = (Boolean)pv.getValue();
+//        }
 
         if (elt != null) {
             source = pc.extractSource(elt);
@@ -93,18 +89,22 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
             ConfigUtils.validateHttpRedirect(loginPage, pc, source);
         }
 
-        ConfigUtils.registerProviderManagerIfNecessary(pc);
-
         filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl,
                 successHandlerRef, failureHandlerRef);
         filterBean.setSource(source);
         filterBean.getPropertyValues().addPropertyValue("authenticationManager",
                 new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
 
-        filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication",
-                sessionFixationProtectionEnabled);
-        filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes",
-                migrateSessionAttributes);
+        // Copy session migration values from the session fixation protection filter
+        if (sfpf != null) {
+            filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes", sfpf.getPropertyValues().getPropertyValue("migrateSessionAttributes").getValue());
+            filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication", Boolean.TRUE);
+        }
+
+//        filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication",
+//                sessionFixationProtectionEnabled);
+//        filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes",
+//                migrateSessionAttributes);
 
         if (pc.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
             filterBean.getPropertyValues().addPropertyValue("rememberMeServices",

+ 19 - 14
config/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java

@@ -13,6 +13,7 @@ import org.springframework.aop.config.AopNamespaceUtils;
 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.parsing.CompositeComponentDefinition;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.support.ManagedList;
 import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -71,9 +72,13 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
     private static final String ATT_USE_PREPOST = "pre-post-annotations";
 
     @SuppressWarnings("unchecked")
-    public BeanDefinition parse(Element element, ParserContext parserContext) {
-        ConfigUtils.registerProviderManagerIfNecessary(parserContext);
-        Object source = parserContext.extractSource(element);
+    public BeanDefinition parse(Element element, ParserContext pc) {
+        ConfigUtils.registerProviderManagerIfNecessary(pc, element);
+        CompositeComponentDefinition compositeDef =
+            new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
+        pc.pushContainingComponent(compositeDef);
+
+        Object source = pc.extractSource(element);
         // The list of method metadata delegates
         ManagedList delegates = new ManagedList();
 
@@ -87,7 +92,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
             Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, EXPRESSION_HANDLER);
 
             if (prePostElt != null && expressionHandlerElt != null) {
-                parserContext.getReaderContext().error(INVOCATION_HANDLING + " and " +
+                pc.getReaderContext().error(INVOCATION_HANDLING + " and " +
                         EXPRESSION_HANDLER + " cannot be used together ", source);
             }
 
@@ -116,7 +121,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
                 if (StringUtils.hasText(expressionHandlerRef)) {
                     logger.info("Using bean '" + expressionHandlerRef + "' as method ExpressionHandler implementation");
                 } else {
-                    parserContext.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, new RootBeanDefinition(DefaultMethodSecurityExpressionHandler.class));
+                    pc.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, new RootBeanDefinition(DefaultMethodSecurityExpressionHandler.class));
                     logger.warn("Expressions were enabled for method security but no SecurityExpressionHandler was configured. " +
                             "All hasPermision() expressions will evaluate to false.");
                     expressionHandlerRef = EXPRESSION_HANDLER_ID;
@@ -136,7 +141,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
             }
 
             preInvocationVoter = preInvocationVoterBldr.getBeanDefinition();
-            ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(afterInvocationBldr.getBeanDefinition());
+            ConfigUtils.getRegisteredAfterInvocationProviders(pc).add(afterInvocationBldr.getBeanDefinition());
             delegates.add(mds.getBeanDefinition());
         }
 
@@ -149,33 +154,33 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
         }
 
         // Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
-        Map<String, List<ConfigAttribute>> pointcutMap = parseProtectPointcuts(parserContext,
+        Map<String, List<ConfigAttribute>> pointcutMap = parseProtectPointcuts(pc,
                 DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));
 
         if (pointcutMap.size() > 0) {
             // Only add it if there are actually any pointcuts defined.
             MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource = new MapBasedMethodSecurityMetadataSource();
             delegates.add(mapBasedMethodSecurityMetadataSource);
-            registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodSecurityMetadataSource, source);
+            registerProtectPointcutPostProcessor(pc, pointcutMap, mapBasedMethodSecurityMetadataSource, source);
         }
 
-        registerDelegatingMethodSecurityMetadataSource(parserContext, delegates, source);
+        registerDelegatingMethodSecurityMetadataSource(pc, delegates, source);
 
         String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
 
         if (!StringUtils.hasText(accessManagerId)) {
-            registerAccessManager(parserContext, jsr250Enabled, preInvocationVoter);
+            registerAccessManager(pc, jsr250Enabled, preInvocationVoter);
             accessManagerId = ACCESS_MANAGER_ID;
         }
 
         String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR);
 
-        registerMethodSecurityInterceptor(parserContext, accessManagerId, runAsManagerId, source);
-
-        registerAdvisor(parserContext, source);
+        registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId, source);
 
-        AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
+        registerAdvisor(pc, source);
 
+        AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
+        pc.popAndRegisterContainingComponent();
         return null;
     }
 

+ 421 - 181
config/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java

@@ -1,5 +1,7 @@
 package org.springframework.security.config;
 
+import static org.springframework.security.config.FilterChainOrder.*;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -14,6 +16,7 @@ import org.springframework.beans.PropertyValues;
 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.parsing.CompositeComponentDefinition;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.beans.factory.support.ManagedList;
@@ -21,9 +24,9 @@ import org.springframework.beans.factory.support.ManagedMap;
 import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.beans.factory.xml.BeanDefinitionParser;
 import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.security.access.AccessDecisionVoter;
+import org.springframework.core.OrderComparator;
+import org.springframework.core.Ordered;
 import org.springframework.security.access.ConfigAttribute;
-import org.springframework.security.access.ConfigAttributeEditor;
 import org.springframework.security.access.SecurityConfig;
 import org.springframework.security.access.vote.AuthenticatedVoter;
 import org.springframework.security.access.vote.RoleVoter;
@@ -40,7 +43,10 @@ import org.springframework.security.web.access.expression.WebExpressionVoter;
 import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
 import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
 import org.springframework.security.web.access.intercept.RequestKey;
+import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
 import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
+import org.springframework.security.web.authentication.www.BasicProcessingFilter;
+import org.springframework.security.web.authentication.www.BasicProcessingFilterEntryPoint;
 import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
 import org.springframework.security.web.context.SecurityContextPersistenceFilter;
 import org.springframework.security.web.session.SessionFixationProtectionFilter;
@@ -120,9 +126,20 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
     static final String EXPRESSION_HANDLER_CLASS = "org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler";
     private static final String EXPRESSION_HANDLER_ID = "_webExpressionHandler";
 
-    @SuppressWarnings("unchecked")
+    /**
+     * The aim of this method is to build the list of filters which have been defined by the namespace elements
+     * and attributes within the &lt;http&gt; configuration, along with any custom-filter's linked to user-defined
+     * filter beans.
+     * <p>
+     * By the end of this method, the default <tt>FilterChainProxy</tt> bean should have been registered and will have
+     * the map of filter chains defined, with the "universal" match pattern mapped to the list of beans which have been parsed here.
+     */
     public BeanDefinition parse(Element element, ParserContext pc) {
-        ConfigUtils.registerProviderManagerIfNecessary(pc);
+        ConfigUtils.registerProviderManagerIfNecessary(pc, element);
+        CompositeComponentDefinition compositeDef =
+            new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
+        pc.pushContainingComponent(compositeDef);
+
         final BeanDefinitionRegistry registry = pc.getRegistry();
         final UrlMatcher matcher = createUrlMatcher(element);
         final Object source = pc.extractSource(element);
@@ -130,203 +147,385 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         // true if Ant path and using lower case
         final boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
         final boolean allowSessionCreation = !OPT_CREATE_SESSION_NEVER.equals(element.getAttribute(ATT_CREATE_SESSION));
-
-        final List<Element> interceptUrlElts = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
-        final Map filterChainMap =  new ManagedMap();
-        final LinkedHashMap channelRequestMap = new LinkedHashMap();
-
-        registerFilterChainProxy(pc, filterChainMap, matcher, source);
+        final boolean autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
+        final Map<String, List<BeanMetadataElement>> filterChainMap =  new ManagedMap<String, List<BeanMetadataElement>>();
+        final LinkedHashMap<RequestKey, List<ConfigAttribute>> channelRequestMap = new LinkedHashMap<RequestKey, List<ConfigAttribute>>();
 
         // filterChainMap and channelRequestMap are populated by this call
-        parseInterceptUrlsForChannelSecurityAndEmptyFilterChains(interceptUrlElts, filterChainMap, channelRequestMap,
-                convertPathsToLowerCase, pc);
+        parseInterceptUrlsForChannelSecurityAndEmptyFilterChains(DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL),
+                filterChainMap, channelRequestMap, convertPathsToLowerCase, pc);
 
-        // Add the default filter list
-        List filterList = new ManagedList();
-        filterChainMap.put(matcher.getUniversalMatchPattern(), filterList);
+        BeanDefinition cpf = null;
+        BeanDefinition concurrentSessionFilter = createConcurrentSessionFilterAndRelatedBeansIfRequired(element, pc);
+        boolean sessionControlEnabled = concurrentSessionFilter != null;
 
         BeanDefinition scpf = createSecurityContextPersistenceFilter(element, pc);
-        pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER, scpf);
-        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER));
 
-        BeanDefinition servApiFilter = createServletApiFilter(element, pc);
-        if (servApiFilter != null) {
-	        pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,servApiFilter);
-	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
+        if (sessionControlEnabled) {
+            logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
+            scpf.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
+
         }
+
+        BeanDefinition servApiFilter = createServletApiFilter(element, pc);
         // Register the portMapper. A default will always be created, even if no element exists.
         BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
                 DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), pc);
-        registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
+        RootBeanDefinition rememberMeFilter = createRememberMeFilter(element, pc);
+        BeanDefinition anonFilter = createAnonymousFilter(element, pc);
 
         BeanDefinition etf = createExceptionTranslationFilter(element, pc, allowSessionCreation);
-        pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, etf);
-        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
+        RootBeanDefinition sfpf = createSessionFixationProtectionFilter(pc, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
+                sessionControlEnabled);
+        BeanDefinition fsi = createFilterSecurityInterceptor(element, pc, matcher, convertPathsToLowerCase);
 
+        registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
         if (channelRequestMap.size() > 0) {
             // At least one channel requirement has been specified
-            BeanDefinition cpf = createChannelProcessingFilter(pc, matcher, channelRequestMap);
-            pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, cpf);
-            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
+            cpf = createChannelProcessingFilter(pc, matcher, channelRequestMap);
+        }
+
+//        if (cpf != null) {
+//            pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, cpf);
+//            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
+//        }
+
+//          pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER, scpf);
+//        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER));
+
+//        if (anonFilter != null) {
+//            pc.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, anonFilter);
+//            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
+//        }
+//
+//        if (servApiFilter != null) {
+//	        pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,servApiFilter);
+//	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
+//        }
+
+//        pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, etf);
+//        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
+//
+
+//          pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, fsi);
+//        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
+
+//        if (sessionControlEnabled) {
+//	        pc.getRegistry().registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, concurrentSessionFilter);
+//	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER));
+//        }
+
+        if (sfpf != null) {
+            // Used by SessionRegistrynjectionPP
+            pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER, sfpf);
+//        	ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
+        }
 
+        final FilterAndEntryPoint basic = createBasicFilter(element, pc, autoConfig);
+        final FilterAndEntryPoint form = createFormLoginFilter(element, pc, autoConfig, allowSessionCreation, sfpf);
+        final FilterAndEntryPoint openID = createOpenIDLoginFilter(element, pc, autoConfig, allowSessionCreation, sfpf);
+
+        String rememberMeServicesId = null;
+        if (rememberMeFilter != null) {
+            //pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, rememberMeFilter);
+            rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName();
+            //ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER));
+            // Post processor to inject RememberMeServices into filters which need it
+
+            RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
+            rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+            pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
         }
 
-        boolean useExpressions = "true".equals(element.getAttribute(ATT_USE_EXPRESSIONS));
+        final BeanDefinition logoutFilter = createLogoutFilter(element, autoConfig, pc, rememberMeServicesId);
 
-        LinkedHashMap<RequestKey, List<ConfigAttribute>> requestToAttributesMap =
-            parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, useExpressions, pc);
+//        if (logoutFilter != null) {
+//	        pc.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, logoutFilter);
+//	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER));
+//        }
 
-        BeanDefinitionBuilder fidsBuilder;
-        Class<? extends AccessDecisionVoter>[] voters;
+        BeanDefinition loginPageGenerationFilter = createLoginPageFilterIfNeeded(form, openID);
 
-        if (useExpressions) {
-            Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER);
-            String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
+//        if (basic.filter != null) {
+//	        pc.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER, basic.filter);
+//	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER));
+//        }
 
-            if (StringUtils.hasText(expressionHandlerRef)) {
-                logger.info("Using bean '" + expressionHandlerRef + "' as web SecurityExpressionHandler implementation");
-            } else {
-                pc.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID,
-                        BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_HANDLER_CLASS).getBeanDefinition());
-                expressionHandlerRef = EXPRESSION_HANDLER_ID;
+        if (form.filter != null) {
+            // Required by login page filter
+            pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, form.filter);
+            if (rememberMeServicesId != null) {
+                form.filter.getPropertyValues().addPropertyValue("rememberMeServices", new RuntimeBeanReference(rememberMeServicesId));
             }
+//		    ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
+//		    pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, form.entryPoint);
+        }
 
-            fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_FIMDS_CLASS);
-            fidsBuilder.addConstructorArgValue(matcher);
-            fidsBuilder.addConstructorArgValue(requestToAttributesMap);
-            fidsBuilder.addConstructorArgReference(expressionHandlerRef);
-            voters = new Class[] {WebExpressionVoter.class};
-        } else {
-            fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
-            fidsBuilder.addConstructorArgValue(matcher);
-            fidsBuilder.addConstructorArgValue(requestToAttributesMap);
-            voters = new Class[] {RoleVoter.class, AuthenticatedVoter.class};
+        if (openID.filter != null) {
+            // Required by login page filter
+            pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openID.filter);
+            if (rememberMeServicesId != null) {
+                openID.filter.getPropertyValues().addPropertyValue("rememberMeServices", new RuntimeBeanReference(rememberMeServicesId));
+            }
+//		    ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
+//		    pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openID.entryPoint);
+        }
+//
+//		if (loginPageGenerationFilter != null) {
+//		    pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, loginPageGenerationFilter);
+//		    ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
+//		}
+
+        FilterAndEntryPoint x509 = createX509Filter(element, pc);
+//		if (x509.filter != null) {
+//	        pc.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, x509.filter);
+//            pc.getRegistry().registerBeanDefinition(BeanIds.PRE_AUTH_ENTRY_POINT, x509.entryPoint);
+//	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.X509_FILTER));
+//		}
+
+        BeanMetadataElement entryPoint = selectEntryPoint(element, pc, basic, form, openID, x509);
+        etf.getPropertyValues().addPropertyValue("authenticationEntryPoint", entryPoint);
+
+        // Now build the filter chain and add it to the map
+        List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();
+//        List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();
+
+        if (cpf != null) {
+            unorderedFilterChain.add(new OrderDecorator(cpf, CHANNEL_FILTER));
         }
-        fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
 
-        // Set up the access manager reference for http
-        String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
+        if (concurrentSessionFilter != null) {
+            unorderedFilterChain.add(new OrderDecorator(concurrentSessionFilter, CONCURRENT_SESSION_FILTER));
+        }
 
-        if (!StringUtils.hasText(accessManagerId)) {
-            pc.getRegistry().registerBeanDefinition(BeanIds.WEB_ACCESS_MANAGER,
-                        ConfigUtils.createAccessManagerBean(voters));
-            accessManagerId = BeanIds.WEB_ACCESS_MANAGER;
+        unorderedFilterChain.add(new OrderDecorator(scpf, SECURITY_CONTEXT_FILTER));
+
+        if (logoutFilter != null) {
+            unorderedFilterChain.add(new OrderDecorator(logoutFilter, LOGOUT_FILTER));
         }
 
-        BeanDefinition fsi = createFilterSecurityInterceptor(element, pc, accessManagerId, fidsBuilder.getBeanDefinition());
-        pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, fsi);
-        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
+        if (x509.filter != null) {
+            unorderedFilterChain.add(new OrderDecorator(x509.filter, X509_FILTER));
+        }
 
-        boolean sessionControlEnabled = false;
+        if (form.filter != null) {
+            unorderedFilterChain.add(new OrderDecorator(form.filter, AUTHENTICATION_PROCESSING_FILTER));
+        }
 
-        BeanDefinition concurrentSessionFilter = createConcurrentSessionFilterAndRelatedBeansIfRequired(element, pc);
-        if (concurrentSessionFilter != null) {
-        	sessionControlEnabled = true;
-	        pc.getRegistry().registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, concurrentSessionFilter);
-	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER));
+        if (openID.filter != null) {
+            unorderedFilterChain.add(new OrderDecorator(openID.filter, OPENID_PROCESSING_FILTER));
         }
 
-        BeanDefinition sfpf = createSessionFixationProtectionFilter(pc, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
-                sessionControlEnabled);
-        if (sfpf != null) {
-        	pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER, sfpf);
-        	ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
+        if (loginPageGenerationFilter != null) {
+            unorderedFilterChain.add(new OrderDecorator(loginPageGenerationFilter, LOGIN_PAGE_FILTER));
         }
-        boolean autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
 
-        Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS);
+        if (basic.filter != null) {
+            unorderedFilterChain.add(new OrderDecorator(basic.filter, BASIC_PROCESSING_FILTER));
+        }
 
-        if (anonymousElt == null || !"false".equals(anonymousElt.getAttribute("enabled"))) {
-        	BeanDefinition anonFilter = new AnonymousBeanDefinitionParser().parse(anonymousElt, pc);
-            pc.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, anonFilter);
-            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
+        if (servApiFilter != null) {
+            unorderedFilterChain.add(new OrderDecorator(servApiFilter, SERVLET_API_SUPPORT_FILTER));
         }
 
-        parseRememberMeAndLogout(element, autoConfig, pc);
+        if (rememberMeFilter != null) {
+            unorderedFilterChain.add(new OrderDecorator(rememberMeFilter, REMEMBER_ME_FILTER));
+        }
 
-        String realm = element.getAttribute(ATT_REALM);
-		if (!StringUtils.hasText(realm)) {
-		    realm = DEF_REALM;
-		}
+        if (anonFilter != null) {
+            unorderedFilterChain.add(new OrderDecorator(anonFilter, ANONYMOUS_FILTER));
+        }
+
+        unorderedFilterChain.add(new OrderDecorator(etf, EXCEPTION_TRANSLATION_FILTER));
 
-		final FilterAndEntryPoint form = createFormLoginFilter(element, pc, autoConfig, allowSessionCreation);
+        if (sfpf != null) {
+            unorderedFilterChain.add(new OrderDecorator(sfpf, SESSION_FIXATION_FILTER));
+        }
 
-		if (form.filter != null) {
-		    pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, form.filter);
-		    ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
-		    pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, form.entryPoint);
-		}
+        unorderedFilterChain.add(new OrderDecorator(fsi, FILTER_SECURITY_INTERCEPTOR));
 
-		Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
-		if (basicAuthElt != null || autoConfig) {
-		    BeanDefinition basicFilter = new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
-	        pc.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER, basicFilter);
-	        ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER));
-		}
 
-		FilterAndEntryPoint openID = createOpenIDLoginFilter(element, pc, autoConfig, allowSessionCreation);
+        List<OrderDecorator> customFilters = buildCustomFilterList(element, pc);
 
-		if (openID.filter != null) {
-		    pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openID.filter);
-		    ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
-		    pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openID.entryPoint);
-		}
+        unorderedFilterChain.addAll(customFilters);
 
-		BeanDefinition loginPageGenerationFilter = createLoginPageFilterIfNeeded(form, openID);
+        Collections.sort(unorderedFilterChain, new OrderComparator());
+        checkFilterChainOrder(unorderedFilterChain, pc, source);
 
-		if (loginPageGenerationFilter != null) {
-		    pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, loginPageGenerationFilter);
-		    ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
-		}
+        List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();
 
-        Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509);
-        if (x509Elt != null) {
-            BeanDefinition x509Filter = new X509BeanDefinitionParser().parse(x509Elt, pc);
-            pc.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, x509Filter);
-            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.X509_FILTER));
+        for (OrderDecorator od : unorderedFilterChain) {
+            filterChain.add(od.bean);
         }
 
-		selectEntryPoint(element, pc, form, openID);
+        filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
+
+        registerFilterChainProxy(pc, filterChainMap, matcher, source);
+
 
         // Register the post processors which will tie up the loose ends in the configuration once the app context has been created and all beans are available.
-        RootBeanDefinition postProcessor = new RootBeanDefinition(EntryPointInjectionBeanPostProcessor.class);
-        postProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
-        registry.registerBeanDefinition(BeanIds.ENTRY_POINT_INJECTION_POST_PROCESSOR, postProcessor);
+//        RootBeanDefinition postProcessor = new RootBeanDefinition(EntryPointInjectionBeanPostProcessor.class);
+//        postProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+//        registry.registerBeanDefinition(BeanIds.ENTRY_POINT_INJECTION_POST_PROCESSOR, postProcessor);
         RootBeanDefinition postProcessor2 = new RootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
         postProcessor2.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         registry.registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR, postProcessor2);
 
+        pc.popAndRegisterContainingComponent();
         return null;
     }
 
-    private void parseRememberMeAndLogout(Element elt, boolean autoConfig, ParserContext pc) {
-        // Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
-        Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME);
-        String rememberMeServices = null;
+    private void checkFilterChainOrder(List<OrderDecorator> filters, ParserContext pc, Object source) {
+        logger.info("Checking sorted filter chain: " + filters);
 
-        if (rememberMeElt != null) {
-            RememberMeBeanDefinitionParser rmbdp = new RememberMeBeanDefinitionParser();
-            BeanDefinition filter = rmbdp.parse(rememberMeElt, pc);
-            pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter);
-            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER));
-            rememberMeServices = rmbdp.getServicesName();
-            // Post processor to inject RememberMeServices into filters which need it
-            RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
-            rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
-            pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
+        for(int i=0; i < filters.size(); i++) {
+            OrderDecorator filter = (OrderDecorator)filters.get(i);
+
+            if (i > 0) {
+                OrderDecorator previous = (OrderDecorator)filters.get(i-1);
+                if (filter.getOrder() == previous.getOrder()) {
+                    pc.getReaderContext().error("Filter beans '" + filter.bean + "' and '" +
+                            previous.bean + "' have the same 'order' value. When using custom filters, " +
+                                    "please make sure the positions do not conflict with default filters. " +
+                                    "Alternatively you can disable the default filters by removing the corresponding " +
+                                    "child elements from <http> and avoiding the use of <http auto-config='true'>.", source);
+                }
+            }
+        }
+    }
+
+    private class OrderDecorator implements Ordered {
+        BeanMetadataElement bean;
+        int order;
+
+        public OrderDecorator(BeanMetadataElement bean, int order) {
+            super();
+            this.bean = bean;
+            this.order = order;
+        }
+
+        public int getOrder() {
+            return order;
         }
+    }
+
+    List<OrderDecorator> buildCustomFilterList(Element element, ParserContext pc) {
+        List<Element> customFilterElts = DomUtils.getChildElementsByTagName(element, Elements.CUSTOM_FILTER);
+        List<OrderDecorator> customFilters = new ArrayList<OrderDecorator>();
+
+        final String ATT_AFTER = "after";
+        final String ATT_BEFORE = "before";
+        final String ATT_POSITION = "position";
+        final String REF = "ref";
+
+
+        for (Element elt: customFilterElts) {
+            String after = elt.getAttribute(ATT_AFTER);
+            String before = elt.getAttribute(ATT_BEFORE);
+            String position = elt.getAttribute(ATT_POSITION);
+
+            String ref = elt.getAttribute(REF);
+
+            if (!StringUtils.hasText(ref)) {
+                pc.getReaderContext().error("The '" + REF + "' attribute must be supplied", pc.extractSource(elt));
+            }
+
+            RuntimeBeanReference bean = new RuntimeBeanReference(ref);
+
+            if(ConfigUtils.countNonEmpty(new String[] {after, before, position}) != 1) {
+                pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
+                        ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
+            }
+
+            if (StringUtils.hasText(position)) {
+                customFilters.add(new OrderDecorator(bean, FilterChainOrder.getOrder(position)));
+            } else if (StringUtils.hasText(after)) {
+                int order = FilterChainOrder.getOrder(after);
+                customFilters.add(new OrderDecorator(bean, order == Integer.MAX_VALUE ? order : order + 1));
+            } else if (StringUtils.hasText(before)) {
+                int order = FilterChainOrder.getOrder(before);
+                customFilters.add(new OrderDecorator(bean, order == Integer.MIN_VALUE ? order : order - 1));
+            }
+        }
+
+        return customFilters;
+    }
+
+    private BeanDefinition createAnonymousFilter(Element element, ParserContext pc) {
+        Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS);
+
+        if (anonymousElt == null || !"false".equals(anonymousElt.getAttribute("enabled"))) {
+            return new AnonymousBeanDefinitionParser().parse(anonymousElt, pc);
+        }
+
+        return null;
+
+    }
 
+    private FilterAndEntryPoint createBasicFilter(Element elt, ParserContext pc, boolean autoConfig) {
+        Element basicAuthElt = DomUtils.getChildElementByTagName(elt, Elements.BASIC_AUTH);
+
+        String realm = elt.getAttribute(ATT_REALM);
+        if (!StringUtils.hasText(realm)) {
+            realm = DEF_REALM;
+        }
+
+        RootBeanDefinition filter = null;
+        RootBeanDefinition entryPoint = null;
+
+        if (basicAuthElt != null || autoConfig) {
+            BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicProcessingFilter.class);
+            entryPoint = new RootBeanDefinition(BasicProcessingFilterEntryPoint.class);
+            entryPoint.setSource(pc.extractSource(elt));
+
+            entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
+
+            pc.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, entryPoint);
+
+            filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
+            filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT));
+            filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
+        }
+
+        return new FilterAndEntryPoint(filter, entryPoint);
+    }
+
+    private FilterAndEntryPoint createX509Filter(Element elt, ParserContext pc) {
+        Element x509Elt = DomUtils.getChildElementByTagName(elt, Elements.X509);
+        RootBeanDefinition filter = null;
+        RootBeanDefinition entryPoint = null;
+
+        if (x509Elt != null) {
+            filter = new X509BeanDefinitionParser().parse(x509Elt, pc);
+            entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
+            entryPoint.setSource(pc.extractSource(x509Elt));
+        }
+
+        return new FilterAndEntryPoint(filter, entryPoint);
+    }
+
+    private BeanDefinition createLogoutFilter(Element elt, boolean autoConfig, ParserContext pc, String rememberMeServicesId) {
         Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT);
         if (logoutElt != null || autoConfig) {
-            BeanDefinition logoutFilter = new LogoutBeanDefinitionParser(rememberMeServices).parse(logoutElt, pc);
+            BeanDefinition logoutFilter = new LogoutBeanDefinitionParser(rememberMeServicesId).parse(logoutElt, pc);
 
-            pc.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, logoutFilter);
-            ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER));
+            return logoutFilter;
         }
+        return null;
     }
 
-    @SuppressWarnings("unchecked")
-    private void registerFilterChainProxy(ParserContext pc, Map filterChainMap, UrlMatcher matcher, Object source) {
+    private RootBeanDefinition createRememberMeFilter(Element elt, ParserContext pc) {
+        // Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
+        Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME);
+
+        if (rememberMeElt != null) {
+            return (RootBeanDefinition) new RememberMeBeanDefinitionParser().parse(rememberMeElt, pc);
+        }
+
+        return null;
+    }
+
+    private void registerFilterChainProxy(ParserContext pc, Map<String, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
         if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
             pc.getReaderContext().error("Duplicate <http> element detected", source);
         }
@@ -339,7 +538,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
         pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, fcpBean);
         pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
-        pc.registerBeanComponent(new BeanComponentDefinition(fcpBean,BeanIds.FILTER_CHAIN_PROXY));
+        pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
     }
 
     private BeanDefinition createSecurityContextPersistenceFilter(Element element, ParserContext pc) {
@@ -391,7 +590,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         }
 
         if ("true".equals(provideServletApi)) {
-        	return new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class);
+            return new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class);
         }
         return null;
     }
@@ -403,9 +602,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         }
 
         BeanDefinition sessionControlFilter = new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
-        logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
-        BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
-        sessionIntegrationFilter.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
         return sessionControlFilter;
     }
 
@@ -455,8 +651,54 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         return accessDeniedHandler.getBeanDefinition();
     }
 
-    private BeanDefinition createFilterSecurityInterceptor(Element element, ParserContext pc, String accessManagerId,
-            BeanDefinition fids) {
+    @SuppressWarnings("unchecked")
+    private BeanDefinition createFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher, boolean convertPathsToLowerCase) {
+        BeanDefinitionBuilder fidsBuilder;
+
+        boolean useExpressions = "true".equals(element.getAttribute(ATT_USE_EXPRESSIONS));
+
+        LinkedHashMap<RequestKey, List<ConfigAttribute>> requestToAttributesMap =
+            parseInterceptUrlsForFilterInvocationRequestMap(DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL),
+                    convertPathsToLowerCase, useExpressions, pc);
+
+
+        RootBeanDefinition accessDecisionMgr;
+
+        if (useExpressions) {
+            Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER);
+            String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
+
+            if (StringUtils.hasText(expressionHandlerRef)) {
+                logger.info("Using bean '" + expressionHandlerRef + "' as web SecurityExpressionHandler implementation");
+            } else {
+                pc.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID,
+                        BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_HANDLER_CLASS).getBeanDefinition());
+                expressionHandlerRef = EXPRESSION_HANDLER_ID;
+            }
+
+            fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_FIMDS_CLASS);
+            fidsBuilder.addConstructorArgValue(matcher);
+            fidsBuilder.addConstructorArgValue(requestToAttributesMap);
+            fidsBuilder.addConstructorArgReference(expressionHandlerRef);
+            accessDecisionMgr = ConfigUtils.createAccessManagerBean(WebExpressionVoter.class);
+        } else {
+            fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
+            fidsBuilder.addConstructorArgValue(matcher);
+            fidsBuilder.addConstructorArgValue(requestToAttributesMap);
+            accessDecisionMgr = ConfigUtils.createAccessManagerBean(RoleVoter.class, AuthenticatedVoter.class);
+        }
+        accessDecisionMgr.setSource(pc.extractSource(element));
+        fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
+
+        // Set up the access manager reference for http
+        String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
+
+        if (!StringUtils.hasText(accessManagerId)) {
+            pc.getRegistry().registerBeanDefinition(BeanIds.WEB_ACCESS_MANAGER, accessDecisionMgr);
+            pc.registerBeanComponent(new BeanComponentDefinition(accessDecisionMgr, BeanIds.WEB_ACCESS_MANAGER));
+            accessManagerId = BeanIds.WEB_ACCESS_MANAGER;
+        }
+
         BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
 
         builder.addPropertyReference("accessDecisionManager", accessManagerId);
@@ -466,12 +708,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
         }
 
-        builder.addPropertyValue("securityMetadataSource", fids);
+        builder.addPropertyValue("securityMetadataSource", fidsBuilder.getBeanDefinition());
         return builder.getBeanDefinition();
     }
 
-    @SuppressWarnings("unchecked")
-    private BeanDefinition createChannelProcessingFilter(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
+    private BeanDefinition createChannelProcessingFilter(ParserContext pc, UrlMatcher matcher, LinkedHashMap<RequestKey, List<ConfigAttribute>> channelRequestMap) {
         RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
         channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
                 new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER));
@@ -481,7 +722,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
 
         channelFilter.getPropertyValues().addPropertyValue("securityMetadataSource", channelFilterInvDefSource);
         RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
-        ManagedList channelProcessors = new ManagedList(3);
+        ManagedList<RootBeanDefinition> channelProcessors = new ManagedList<RootBeanDefinition>(3);
         RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
         RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
         RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
@@ -499,7 +740,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         return channelFilter;
     }
 
-    private BeanDefinition createSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
+    private RootBeanDefinition createSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
         if(!StringUtils.hasText(sessionFixationAttribute)) {
             sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
         }
@@ -512,12 +753,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             if (sessionControlEnabled) {
                 sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
             }
-            return sessionFixationFilter.getBeanDefinition();
+            return (RootBeanDefinition) sessionFixationFilter.getBeanDefinition();
         }
         return null;
     }
 
-    private FilterAndEntryPoint createFormLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation) {
+    private FilterAndEntryPoint createFormLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation, RootBeanDefinition sfpf) {
         RootBeanDefinition formLoginFilter = null;
         RootBeanDefinition formLoginEntryPoint = null;
 
@@ -527,7 +768,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
                     AUTHENTICATION_PROCESSING_FILTER_CLASS);
 
-            parser.parse(formLoginElt, pc);
+            parser.parse(formLoginElt, pc, sfpf);
             formLoginFilter = parser.getFilterBean();
             formLoginEntryPoint = parser.getEntryPointBean();
         }
@@ -539,7 +780,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         return new FilterAndEntryPoint(formLoginFilter, formLoginEntryPoint);
     }
 
-    private FilterAndEntryPoint createOpenIDLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation) {
+    private FilterAndEntryPoint createOpenIDLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation, RootBeanDefinition sfpf) {
         Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN);
         RootBeanDefinition openIDFilter = null;
         RootBeanDefinition openIDEntryPoint = null;
@@ -548,7 +789,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
                     OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS);
 
-            parser.parse(openIDLoginElt, pc);
+            parser.parse(openIDLoginElt, pc, sfpf);
             openIDFilter = parser.getFilterBean();
             openIDEntryPoint = parser.getEntryPointBean();
 
@@ -575,22 +816,22 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
 
     class FilterAndEntryPoint {
         RootBeanDefinition filter;
-    	RootBeanDefinition entryPoint;
+        RootBeanDefinition entryPoint;
 
-		public FilterAndEntryPoint(RootBeanDefinition filter, RootBeanDefinition entryPoint) {
-			this.filter = filter;
-			this.entryPoint = entryPoint;
-		}
+        public FilterAndEntryPoint(RootBeanDefinition filter, RootBeanDefinition entryPoint) {
+            this.filter = filter;
+            this.entryPoint = entryPoint;
+        }
     }
 
-    private void selectEntryPoint(Element element, ParserContext pc, FilterAndEntryPoint form, FilterAndEntryPoint openID) {
+    private BeanMetadataElement selectEntryPoint(Element element, ParserContext pc, FilterAndEntryPoint basic, FilterAndEntryPoint form, FilterAndEntryPoint openID, FilterAndEntryPoint x509) {
         // We need to establish the main entry point.
         // First check if a custom entry point bean is set
         String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
 
         if (StringUtils.hasText(customEntryPoint)) {
-            pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
-            return;
+//            pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
+            return new RuntimeBeanReference(customEntryPoint);
         }
 
         Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
@@ -598,8 +839,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN);
         // Basic takes precedence if explicit element is used and no others are configured
         if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
-            pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
-            return;
+            //pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
+            return basic.entryPoint;
         }
 
         // If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
@@ -607,37 +848,38 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         String openIDLoginPage = getLoginFormUrl(openID.entryPoint);
 
         if (form.filter != null && openIDLoginPage == null) {
-            pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
-            return;
+            //pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
+            return form.entryPoint;
         }
 
         // Otherwise use OpenID if enabled
         if (openID.filter != null && form.filter == null) {
-            pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
-            return;
+            //pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
+            return openID.entryPoint;
         }
 
         // If X.509 has been enabled, use the preauth entry point.
         if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) {
-            pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
-            return;
+            //pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
+            return x509.entryPoint;
         }
 
         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 '" + ATT_ENTRY_POINT_REF+ "' attribute ",
                 pc.extractSource(element));
+        return null;
     }
 
     private String getLoginFormUrl(RootBeanDefinition entryPoint) {
-    	if (entryPoint == null) {
-    		return null;
-    	}
+        if (entryPoint == null) {
+            return null;
+        }
 
-    	PropertyValues pvs = entryPoint.getPropertyValues();
-    	PropertyValue pv = pvs.getPropertyValue("loginFormUrl");
+        PropertyValues pvs = entryPoint.getPropertyValues();
+        PropertyValue pv = pvs.getPropertyValue("loginFormUrl");
         if (pv == null) {
-        	 return null;
+             return null;
         }
 
         return (String) pv.getValue();
@@ -649,7 +891,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         String formLoginPage = getLoginFormUrl(form.entryPoint);
         // If the login URL is the default one, then it is assumed not to have been set explicitly
         if (DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL == formLoginPage) {
-        	formLoginPage = null;
+            formLoginPage = null;
         }
         String openIDLoginPage = getLoginFormUrl(openID.entryPoint);
 
@@ -714,12 +956,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
      * Parses the intercept-url elements and populates the FilterChainProxy's filter chain Map and the
      * map used to create the FilterInvocationDefintionSource for the FilterSecurityInterceptor.
      */
-    @SuppressWarnings("unchecked")
-    void parseInterceptUrlsForChannelSecurityAndEmptyFilterChains(List<Element> urlElts, Map filterChainMap,  Map channelRequestMap,
+    void parseInterceptUrlsForChannelSecurityAndEmptyFilterChains(List<Element> urlElts, Map<String, List<BeanMetadataElement>> filterChainMap,  Map<RequestKey, List<ConfigAttribute>> channelRequestMap,
             boolean useLowerCasePaths, ParserContext parserContext) {
 
-        ConfigAttributeEditor editor = new ConfigAttributeEditor();
-
         for (Element urlElt : urlElts) {
             String path = urlElt.getAttribute(ATT_PATH_PATTERN);
 
@@ -746,8 +985,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
                     parserContext.getReaderContext().error("Unsupported channel " + requiredChannel, urlElt);
                 }
 
-                editor.setAsText(channelConfigAttribute);
-                channelRequestMap.put(new RequestKey(path), editor.getValue());
+                channelRequestMap.put(new RequestKey(path),
+                        SecurityConfig.createList((StringUtils.commaDelimitedListToStringArray(channelConfigAttribute))));
             }
 
             String filters = urlElt.getAttribute(ATT_FILTERS);
@@ -758,7 +997,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
                             "filters attribute", urlElt);
                 }
 
-                filterChainMap.put(path, Collections.EMPTY_LIST);
+                List<BeanMetadataElement> noFilters = Collections.emptyList();
+                filterChainMap.put(path, noFilters);
             }
         }
     }

+ 1 - 1
config/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java

@@ -31,7 +31,7 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe
     private BeanDefinitionDecorator delegate = new InternalInterceptMethodsBeanDefinitionDecorator();
 
     public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
-        ConfigUtils.registerProviderManagerIfNecessary(parserContext);
+        ConfigUtils.registerProviderManagerIfNecessary(parserContext, (Element) node);
         ConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext);
 
         return delegate.decorate(node, definition, parserContext);

+ 2 - 2
config/src/main/java/org/springframework/security/config/NamespaceAuthenticationManager.java

@@ -20,8 +20,8 @@ import org.springframework.util.Assert;
  * @since 2.0.4
  */
 public class NamespaceAuthenticationManager extends ProviderManager implements BeanFactoryAware {
-    BeanFactory beanFactory;
-    List<String> providerBeanNames;
+    private BeanFactory beanFactory;
+    private List<String> providerBeanNames;
 
     public void setBeanFactory(BeanFactory beanFactory) {
         this.beanFactory = beanFactory;

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

@@ -15,7 +15,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
 import org.springframework.beans.factory.xml.ParserContext;
 import org.springframework.core.Ordered;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 import org.w3c.dom.Element;
@@ -47,7 +46,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
             wrapper.addPropertyValue("order", order);
         }
 
-        ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
+//        ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
 
         return holder;
     }

+ 25 - 25
config/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java

@@ -4,6 +4,8 @@ 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.parsing.CompositeComponentDefinition;
 import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.beans.factory.xml.BeanDefinitionParser;
 import org.springframework.beans.factory.xml.ParserContext;
@@ -33,24 +35,18 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
     protected final Log logger = LogFactory.getLog(getClass());
     private String servicesName;
 
-    public BeanDefinition parse(Element element, ParserContext parserContext) {
-        String tokenRepository = null;
-        String dataSource = null;
-        String key = null;
-        Object source = null;
-        String userServiceRef = null;
-        String rememberMeServicesRef = null;
-        String tokenValiditySeconds = null;
-
-        if (element != null) {
-            tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY);
-            dataSource = element.getAttribute(ATT_DATA_SOURCE);
-            key = element.getAttribute(ATT_KEY);
-            userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
-            rememberMeServicesRef = element.getAttribute(ATT_SERVICES_REF);
-            tokenValiditySeconds = element.getAttribute(ATT_TOKEN_VALIDITY);
-            source = parserContext.extractSource(element);
-        }
+    public BeanDefinition parse(Element element, ParserContext pc) {
+        CompositeComponentDefinition compositeDef =
+            new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
+        pc.pushContainingComponent(compositeDef);
+
+        String tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY);
+        String dataSource = element.getAttribute(ATT_DATA_SOURCE);
+        String key = element.getAttribute(ATT_KEY);
+        String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
+        String rememberMeServicesRef = element.getAttribute(ATT_SERVICES_REF);
+        String tokenValiditySeconds = element.getAttribute(ATT_TOKEN_VALIDITY);
+        Object source = pc.extractSource(element);
 
         if (!StringUtils.hasText(key)) {
             key = DEF_KEY;
@@ -65,12 +61,12 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
         boolean tokenValiditySet = StringUtils.hasText(tokenValiditySeconds);
 
         if (servicesRefSet && (dataSourceSet || tokenRepoSet || userServiceSet || tokenValiditySet)) {
-            parserContext.getReaderContext().error(ATT_SERVICES_REF + " can't be used in combination with attributes "
+            pc.getReaderContext().error(ATT_SERVICES_REF + " can't be used in combination with attributes "
                     + ATT_TOKEN_REPOSITORY + "," + ATT_DATA_SOURCE + ", " + ATT_USER_SERVICE_REF + " or " + ATT_TOKEN_VALIDITY, source);
         }
 
         if (dataSourceSet && tokenRepoSet) {
-            parserContext.getReaderContext().error("Specify " + ATT_TOKEN_REPOSITORY + " or " +
+            pc.getReaderContext().error("Specify " + ATT_TOKEN_REPOSITORY + " or " +
                     ATT_DATA_SOURCE +" but not both", source);
         }
 
@@ -100,23 +96,27 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
             if (tokenValiditySet) {
                 Integer tokenValidity = new Integer(tokenValiditySeconds);
                 if (tokenValidity.intValue() < 0 && isPersistent) {
-                    parserContext.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" +
+                    pc.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" +
                             " a persistent remember-me token repository", source);
                 }
                 services.getPropertyValues().addPropertyValue("tokenValiditySeconds", tokenValidity);
             }
             services.setSource(source);
             services.getPropertyValues().addPropertyValue(ATT_KEY, key);
-            parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
+            pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
+            pc.registerBeanComponent(new BeanComponentDefinition(services, BeanIds.REMEMBER_ME_SERVICES));
             servicesName = BeanIds.REMEMBER_ME_SERVICES;
         } else {
             servicesName = rememberMeServicesRef;
-            parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES);
+            pc.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES);
         }
 
-        registerProvider(parserContext, source, key);
+        registerProvider(pc, source, key);
 
-        return createFilter(parserContext, source);
+        BeanDefinition filter = createFilter(pc, source);
+        pc.popAndRegisterContainingComponent();
+
+        return filter;
     }
 
     String getServicesName() {

+ 17 - 17
config/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java

@@ -26,23 +26,23 @@ public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostPro
     private ListableBeanFactory beanFactory;
 
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-        if (bean instanceof AbstractAuthenticationProcessingFilter) {
-            AbstractAuthenticationProcessingFilter pf = (AbstractAuthenticationProcessingFilter) bean;
-
-            if (pf.getRememberMeServices() == null) {
-                logger.info("Setting RememberMeServices on bean " + beanName);
-                pf.setRememberMeServices(getRememberMeServices());
-            }
-        } else if (BeanIds.BASIC_AUTHENTICATION_FILTER.equals(beanName)) {
-            // NB: For remember-me to be sent back, a user must submit a "_spring_security_remember_me" with their login request.
-            // Most of the time a user won't present such a parameter with their BASIC authentication request.
-            // In the future we might support setting the AbstractRememberMeServices.alwaysRemember = true, but I am reluctant to
-            // do so because it seems likely to lead to lower security for 99.99% of users if they set the property to true.
-
-            BasicProcessingFilter bf = (BasicProcessingFilter) bean;
-            logger.info("Setting RememberMeServices on bean " + beanName);
-            bf.setRememberMeServices(getRememberMeServices());
-        }
+//        if (bean instanceof AbstractAuthenticationProcessingFilter) {
+//            AbstractAuthenticationProcessingFilter pf = (AbstractAuthenticationProcessingFilter) bean;
+//
+//            if (pf.getRememberMeServices() == null) {
+//                logger.info("Setting RememberMeServices on bean " + beanName);
+//                pf.setRememberMeServices(getRememberMeServices());
+//            }
+//        } else if (BeanIds.BASIC_AUTHENTICATION_FILTER.equals(beanName)) {
+//            // NB: For remember-me to be sent back, a user must submit a "_spring_security_remember_me" with their login request.
+//            // Most of the time a user won't present such a parameter with their BASIC authentication request.
+//            // In the future we might support setting the AbstractRememberMeServices.alwaysRemember = true, but I am reluctant to
+//            // do so because it seems likely to lead to lower security for 99.99% of users if they set the property to true.
+//
+//            BasicProcessingFilter bf = (BasicProcessingFilter) bean;
+//            logger.info("Setting RememberMeServices on bean " + beanName);
+//            bf.setRememberMeServices(getRememberMeServices());
+//        }
 
         return bean;
     }

+ 2 - 7
config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java

@@ -27,13 +27,10 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
     public static final String ATT_REGEX = "subject-principal-regex";
     public static final String ATT_USER_SERVICE_REF = "user-service-ref";
 
-    public BeanDefinition parse(Element element, ParserContext parserContext) {
+    public RootBeanDefinition parse(Element element, ParserContext parserContext) {
         BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509PreAuthenticatedProcessingFilter.class);
-        RootBeanDefinition entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
-
         Object source = parserContext.extractSource(element);
         filterBuilder.getRawBeanDefinition().setSource(source);
-        entryPoint.setSource(source);
 
         String regex = element.getAttribute(ATT_REGEX);
 
@@ -57,10 +54,8 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
             provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService);
         }
 
-        parserContext.getRegistry().registerBeanDefinition(BeanIds.PRE_AUTH_ENTRY_POINT, entryPoint);
-
         filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
 
-        return filterBuilder.getBeanDefinition();
+        return (RootBeanDefinition) filterBuilder.getBeanDefinition();
     }
 }

+ 9 - 3
config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc

@@ -240,7 +240,7 @@ protect-pointcut.attlist &=
 
 http =
     ## Container element for HTTP security configuration
-   element http {http.attlist, (intercept-url+ & access-denied-handler? & form-login? & openid-login? & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings) }
+   element http {http.attlist, (intercept-url+ & access-denied-handler? & form-login? & openid-login? & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings & custom-filter*) }
 http.attlist &=
     ## Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false".
     attribute auto-config {boolean}?
@@ -553,7 +553,14 @@ any-user-service = user-service | jdbc-user-service | ldap-user-service
     
 custom-filter =
     ## Used to indicate that a filter bean declaration should be incorporated into the security filter chain. If neither the 'after' or 'before' options are supplied, then the filter must implement the Ordered interface directly. 
-    element custom-filter {after | before | position}?
+    element custom-filter {custom-filter.attlist}
+
+custom-filter.attlist &=
+    ref
+
+custom-filter.attlist &=
+    (after | before | position)
+
 after =
     ## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters. 
     attribute after {named-security-filter}
@@ -565,7 +572,6 @@ position =
     attribute position {named-security-filter}
 
 
-
 named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "OPENID_PROCESSING_FILTER" |"BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
     
     

+ 1478 - 480
config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd

@@ -1,1690 +1,2688 @@
 <?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
-   xmlns:security="http://www.springframework.org/schema/security" elementFormDefault="qualified"
-   targetNamespace="http://www.springframework.org/schema/security">
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:security="http://www.springframework.org/schema/security" elementFormDefault="qualified" targetNamespace="http://www.springframework.org/schema/security">
+  
    <xs:attributeGroup name="hash">
+    
       <xs:attribute name="hash" use="required">
+      
          <xs:annotation>
-            <xs:documentation>Defines the hashing algorithm used on user passwords. We recommend
-               strongly against using MD4, as it is a very weak hashing
-               algorithm.</xs:documentation>
+        
+            <xs:documentation>Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="plaintext"/>
+          
                <xs:enumeration value="sha"/>
+          
                <xs:enumeration value="sha-256"/>
+          
                <xs:enumeration value="md5"/>
+          
                <xs:enumeration value="md4"/>
+          
                <xs:enumeration value="{sha}"/>
+          
                <xs:enumeration value="{ssha}"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="base64">
+    
       <xs:attribute name="base64" use="required">
+      
          <xs:annotation>
+        
             <xs:documentation>Whether a string should be base64 encoded</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="true"/>
+          
                <xs:enumeration value="false"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="path-type">
+    
       <xs:attribute name="path-type" use="required">
+      
          <xs:annotation>
-            <xs:documentation>Defines the type of pattern used to specify URL paths (either JDK
-               1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if
-               unspecified.</xs:documentation>
+        
+            <xs:documentation>Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="ant"/>
+          
                <xs:enumeration value="regex"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="port">
+    
       <xs:attribute name="port" use="required" type="xs:positiveInteger">
+      
          <xs:annotation>
-            <xs:documentation>Specifies an IP port number. Used to configure an embedded LDAP
-               server, for example.</xs:documentation>
+        
+            <xs:documentation>Specifies an IP port number. Used to configure an embedded LDAP server, for example.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="url">
+    
       <xs:attribute name="url" use="required" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>Specifies a URL.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="id">
+    
       <xs:attribute name="id" use="required" type="xs:ID">
+      
          <xs:annotation>
-            <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the
-               context.</xs:documentation>
+        
+            <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="ref">
+    
       <xs:attribute name="ref" use="required" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>Defines a reference to a Spring bean Id.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="cache-ref">
+    
       <xs:attribute name="cache-ref" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Defines a reference to a cache for use with a
-               UserDetailsService.</xs:documentation>
+        
+            <xs:documentation>Defines a reference to a cache for use with a UserDetailsService.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="user-service-ref">
+    
       <xs:attribute name="user-service-ref" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A reference to a user-service (or UserDetailsService bean)
-               Id</xs:documentation>
+        
+            <xs:documentation>A reference to a user-service (or UserDetailsService bean) Id</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="data-source-ref">
+    
       <xs:attribute name="data-source-ref" use="required" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>A reference to a DataSource bean</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="password-encoder.attlist">
+    
       <xs:attribute name="ref" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>Defines a reference to a Spring bean Id.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="hash">
+      
          <xs:annotation>
-            <xs:documentation>Defines the hashing algorithm used on user passwords. We recommend
-               strongly against using MD4, as it is a very weak hashing
-               algorithm.</xs:documentation>
+        
+            <xs:documentation>Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="plaintext"/>
+          
                <xs:enumeration value="sha"/>
+          
                <xs:enumeration value="sha-256"/>
+          
                <xs:enumeration value="md5"/>
+          
                <xs:enumeration value="md4"/>
+          
                <xs:enumeration value="{sha}"/>
+          
                <xs:enumeration value="{ssha}"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="base64">
+      
          <xs:annotation>
+        
             <xs:documentation>Whether a string should be base64 encoded</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="true"/>
+          
                <xs:enumeration value="false"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="user-property">
+    
       <xs:attribute name="user-property" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A property of the UserDetails object which will be used as salt by a
-               password encoder. Typically something like "username" might be used.
-            </xs:documentation>
+        
+            <xs:documentation>A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="system-wide">
+    
       <xs:attribute name="system-wide" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A single value that will be used as the salt for a password encoder.
-            </xs:documentation>
+        
+            <xs:documentation>A single value that will be used as the salt for a password encoder. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:simpleType name="boolean">
+    
       <xs:restriction base="xs:token">
+      
          <xs:enumeration value="true"/>
+      
          <xs:enumeration value="false"/>
+    
       </xs:restriction>
+  
    </xs:simpleType>
+  
    <xs:attributeGroup name="role-prefix">
+    
       <xs:attribute name="role-prefix" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A non-empty string prefix that will be added to role strings loaded
-               from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases
-               where the default is non-empty.</xs:documentation>
+        
+            <xs:documentation>A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="use-expressions">
+    
       <xs:attribute name="use-expressions" use="required" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Enables the use of expressions in the 'access' attributes in
-               &lt;intercept-url&gt; elements rather than the traditional list of
-               configuration attributes. Defaults to 'false'. If enabled, each attribute should
-               contain a single boolean expression. If the expression evaluates to 'true', access
-               will be granted. </xs:documentation>
+        
+            <xs:documentation>Enables the use of expressions in the 'access' attributes in &lt;intercept-url&gt; elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="ldap-server">
       <xs:annotation>
-         <xs:documentation>Defines an LDAP server location or starts an embedded server. The url
-            indicates the location of a remote server. If no url is given, an embedded server will
-            be started, listening on the supplied port number. The port is optional and defaults to
-            33389. A Spring LDAP ContextSource bean will be registered for the server with the id
-            supplied. </xs:documentation>
+      
+         <xs:documentation>Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied. </xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:attributeGroup ref="security:ldap-server.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="ldap-server.attlist">
+    
       <xs:attribute name="id" type="xs:ID">
+      
          <xs:annotation>
-            <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the
-               context.</xs:documentation>
+        
+            <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="url" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>Specifies a URL.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="port" type="xs:positiveInteger">
+      
          <xs:annotation>
-            <xs:documentation>Specifies an IP port number. Used to configure an embedded LDAP
-               server, for example.</xs:documentation>
+        
+            <xs:documentation>Specifies an IP port number. Used to configure an embedded LDAP server, for example.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="manager-dn" type="xs:string">
+      
          <xs:annotation>
-            <xs:documentation>Username (DN) of the "manager" user identity which will be used to
-               authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be
-               used. </xs:documentation>
+        
+            <xs:documentation>Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="manager-password" type="xs:string">
+      
          <xs:annotation>
+        
             <xs:documentation>The password for the manager DN.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="ldif" type="xs:string">
+      
          <xs:annotation>
-            <xs:documentation>Explicitly specifies an ldif file resource to load into an embedded
-               LDAP server</xs:documentation>
+        
+            <xs:documentation>Explicitly specifies an ldif file resource to load into an embedded LDAP server</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="root" type="xs:string">
+      
          <xs:annotation>
-            <xs:documentation>Optional root suffix for the embedded LDAP server. Default is
-               "dc=springframework,dc=org"</xs:documentation>
+        
+            <xs:documentation>Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org"</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="ldap-server-ref-attribute">
+    
       <xs:attribute name="server-ref" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The optional server to use. If omitted, and a default LDAP server is
-               registered (using &lt;ldap-server&gt; with no Id), that server will be used.
-            </xs:documentation>
+        
+            <xs:documentation>The optional server to use. If omitted, and a default LDAP server is registered (using &lt;ldap-server&gt; with no Id), that server will be used. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="group-search-filter-attribute">
+    
       <xs:attribute name="group-search-filter" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Group search filter. Defaults to (uniqueMember={0}). The substituted
-               parameter is the DN of the user.</xs:documentation>
+        
+            <xs:documentation>Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="group-search-base-attribute">
+    
       <xs:attribute name="group-search-base" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Search base for group membership searches. Defaults to "" (searching
-               from the root).</xs:documentation>
+        
+            <xs:documentation>Search base for group membership searches. Defaults to "" (searching from the root).</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="user-search-filter-attribute">
+    
       <xs:attribute name="user-search-filter" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The LDAP filter used to search for users (optional). For example
-               "(uid={0})". The substituted parameter is the user's login name.</xs:documentation>
+        
+            <xs:documentation>The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="user-search-base-attribute">
+    
       <xs:attribute name="user-search-base" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Search base for user searches. Defaults to "". Only used with a
-               'user-search-filter'.</xs:documentation>
+        
+            <xs:documentation>Search base for user searches. Defaults to "". Only used with a 'user-search-filter'.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="group-role-attribute-attribute">
+    
       <xs:attribute name="group-role-attribute" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The LDAP attribute name which contains the role name which will be
-               used within Spring Security. Defaults to "cn".</xs:documentation>
+        
+            <xs:documentation>The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="user-details-class-attribute">
+    
       <xs:attribute name="user-details-class" use="required">
+      
          <xs:annotation>
-            <xs:documentation>Allows the objectClass of the user entry to be specified. If set, the
-               framework will attempt to load standard attributes for the defined class into the
-               returned UserDetails object</xs:documentation>
+        
+            <xs:documentation>Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="person"/>
+          
                <xs:enumeration value="inetOrgPerson"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="user-context-mapper-attribute">
+    
       <xs:attribute name="user-context-mapper-ref" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Allows explicit customization of the loaded user object by specifying
-               a UserDetailsContextMapper bean which will be called with the context information
-               from the user's directory entry</xs:documentation>
+        
+            <xs:documentation>Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="ldap-user-service" substitutionGroup="security:any-user-service">
       <xs:complexType>
+      
          <xs:attributeGroup ref="security:ldap-us.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="ldap-us.attlist">
+    
       <xs:attribute name="id" type="xs:ID">
+      
          <xs:annotation>
-            <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the
-               context.</xs:documentation>
+        
+            <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="server-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The optional server to use. If omitted, and a default LDAP server is
-               registered (using &lt;ldap-server&gt; with no Id), that server will be used.
-            </xs:documentation>
+        
+            <xs:documentation>The optional server to use. If omitted, and a default LDAP server is registered (using &lt;ldap-server&gt; with no Id), that server will be used. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-search-filter" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The LDAP filter used to search for users (optional). For example
-               "(uid={0})". The substituted parameter is the user's login name.</xs:documentation>
+        
+            <xs:documentation>The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-search-base" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Search base for user searches. Defaults to "". Only used with a
-               'user-search-filter'.</xs:documentation>
+        
+            <xs:documentation>Search base for user searches. Defaults to "". Only used with a 'user-search-filter'.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="group-search-filter" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Group search filter. Defaults to (uniqueMember={0}). The substituted
-               parameter is the DN of the user.</xs:documentation>
+        
+            <xs:documentation>Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="group-search-base" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Search base for group membership searches. Defaults to "" (searching
-               from the root).</xs:documentation>
+        
+            <xs:documentation>Search base for group membership searches. Defaults to "" (searching from the root).</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="group-role-attribute" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The LDAP attribute name which contains the role name which will be
-               used within Spring Security. Defaults to "cn".</xs:documentation>
+        
+            <xs:documentation>The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="cache-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Defines a reference to a cache for use with a
-               UserDetailsService.</xs:documentation>
+        
+            <xs:documentation>Defines a reference to a cache for use with a UserDetailsService.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="role-prefix" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A non-empty string prefix that will be added to role strings loaded
-               from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases
-               where the default is non-empty.</xs:documentation>
+        
+            <xs:documentation>A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-details-class">
+      
          <xs:annotation>
-            <xs:documentation>Allows the objectClass of the user entry to be specified. If set, the
-               framework will attempt to load standard attributes for the defined class into the
-               returned UserDetails object</xs:documentation>
+        
+            <xs:documentation>Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="person"/>
+          
                <xs:enumeration value="inetOrgPerson"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-context-mapper-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Allows explicit customization of the loaded user object by specifying
-               a UserDetailsContextMapper bean which will be called with the context information
-               from the user's directory entry</xs:documentation>
+        
+            <xs:documentation>Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="ldap-authentication-provider">
       <xs:annotation>
+      
          <xs:documentation>Sets up an ldap authentication provider</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:sequence>
+        
             <xs:element minOccurs="0" name="password-compare">
                <xs:annotation>
-                  <xs:documentation>Specifies that an LDAP provider should use an LDAP compare
-                     operation of the user's password to authenticate the user</xs:documentation>
+      
+                  <xs:documentation>Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:sequence>
+        
                      <xs:element minOccurs="0" name="password-encoder">
                         <xs:annotation>
-                           <xs:documentation>element which defines a password encoding strategy.
-                              Used by an authentication provider to convert submitted passwords to
-                              hashed versions, for example.</xs:documentation>
+      
+                           <xs:documentation>element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example.</xs:documentation>
+    
                         </xs:annotation>
                         <xs:complexType>
+      
                            <xs:sequence>
+        
                               <xs:element minOccurs="0" name="salt-source">
                                  <xs:annotation>
-                                    <xs:documentation>Password salting strategy. A system-wide
-                                       constant or a property from the UserDetails object can be
-                                       used.</xs:documentation>
+      
+                                    <xs:documentation>Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.</xs:documentation>
+    
                                  </xs:annotation>
                                  <xs:complexType>
+      
                                     <xs:attribute name="user-property" type="xs:token">
+        
                                        <xs:annotation>
-                                          <xs:documentation>A property of the UserDetails object
-                                             which will be used as salt by a password encoder.
-                                             Typically something like "username" might be used.
-                                          </xs:documentation>
+          
+                                          <xs:documentation>A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used. </xs:documentation>
+        
                                        </xs:annotation>
+      
                                     </xs:attribute>
+      
                                     <xs:attribute name="system-wide" type="xs:token">
+        
                                        <xs:annotation>
-                                          <xs:documentation>A single value that will be used as the
-                                             salt for a password encoder. </xs:documentation>
+          
+                                          <xs:documentation>A single value that will be used as the salt for a password encoder. </xs:documentation>
+        
                                        </xs:annotation>
+      
                                     </xs:attribute>
+      
                                     <xs:attribute name="ref" type="xs:token">
+        
                                        <xs:annotation>
-                                          <xs:documentation>Defines a reference to a Spring bean
-                                             Id.</xs:documentation>
+          
+                                          <xs:documentation>Defines a reference to a Spring bean Id.</xs:documentation>
+        
                                        </xs:annotation>
+      
                                     </xs:attribute>
+    
                                  </xs:complexType>
                               </xs:element>
+      
                            </xs:sequence>
+      
                            <xs:attributeGroup ref="security:password-encoder.attlist"/>
+    
                         </xs:complexType>
                      </xs:element>
+      
                   </xs:sequence>
+      
                   <xs:attributeGroup ref="security:password-compare.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+      
          </xs:sequence>
+      
          <xs:attributeGroup ref="security:ldap-ap.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="ldap-ap.attlist">
+    
       <xs:attribute name="server-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The optional server to use. If omitted, and a default LDAP server is
-               registered (using &lt;ldap-server&gt; with no Id), that server will be used.
-            </xs:documentation>
+        
+            <xs:documentation>The optional server to use. If omitted, and a default LDAP server is registered (using &lt;ldap-server&gt; with no Id), that server will be used. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-search-base" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Search base for user searches. Defaults to "". Only used with a
-               'user-search-filter'.</xs:documentation>
+        
+            <xs:documentation>Search base for user searches. Defaults to "". Only used with a 'user-search-filter'.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-search-filter" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The LDAP filter used to search for users (optional). For example
-               "(uid={0})". The substituted parameter is the user's login name.</xs:documentation>
+        
+            <xs:documentation>The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="group-search-base" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Search base for group membership searches. Defaults to "" (searching
-               from the root).</xs:documentation>
+        
+            <xs:documentation>Search base for group membership searches. Defaults to "" (searching from the root).</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="group-search-filter" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Group search filter. Defaults to (uniqueMember={0}). The substituted
-               parameter is the DN of the user.</xs:documentation>
+        
+            <xs:documentation>Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="group-role-attribute" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The LDAP attribute name which contains the role name which will be
-               used within Spring Security. Defaults to "cn".</xs:documentation>
+        
+            <xs:documentation>The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-dn-pattern" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A specific pattern used to build the user's DN, for example
-               "uid={0},ou=people". The key "{0}" must be present and will be substituted with the
-               username.</xs:documentation>
+        
+            <xs:documentation>A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present and will be substituted with the username.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="role-prefix" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A non-empty string prefix that will be added to role strings loaded
-               from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases
-               where the default is non-empty.</xs:documentation>
+        
+            <xs:documentation>A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-details-class">
+      
          <xs:annotation>
-            <xs:documentation>Allows the objectClass of the user entry to be specified. If set, the
-               framework will attempt to load standard attributes for the defined class into the
-               returned UserDetails object</xs:documentation>
+        
+            <xs:documentation>Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="person"/>
+          
                <xs:enumeration value="inetOrgPerson"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-context-mapper-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Allows explicit customization of the loaded user object by specifying
-               a UserDetailsContextMapper bean which will be called with the context information
-               from the user's directory entry</xs:documentation>
+        
+            <xs:documentation>Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="password-compare.attlist">
+    
       <xs:attribute name="password-attribute" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The attribute in the directory which contains the user password.
-               Defaults to "userPassword".</xs:documentation>
+        
+            <xs:documentation>The attribute in the directory which contains the user password. Defaults to "userPassword".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="hash">
+      
          <xs:annotation>
-            <xs:documentation>Defines the hashing algorithm used on user passwords. We recommend
-               strongly against using MD4, as it is a very weak hashing
-               algorithm.</xs:documentation>
+        
+            <xs:documentation>Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="plaintext"/>
+          
                <xs:enumeration value="sha"/>
+          
                <xs:enumeration value="sha-256"/>
+          
                <xs:enumeration value="md5"/>
+          
                <xs:enumeration value="md4"/>
+          
                <xs:enumeration value="{sha}"/>
+          
                <xs:enumeration value="{ssha}"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="intercept-methods">
       <xs:annotation>
-         <xs:documentation>Can be used inside a bean definition to add a security interceptor to the
-            bean and set up access configuration attributes for the bean's
-            methods</xs:documentation>
+      
+         <xs:documentation>Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:sequence>
+        
             <xs:element maxOccurs="unbounded" name="protect">
                <xs:annotation>
-                  <xs:documentation>Defines a protected method and the access control configuration
-                     attributes that apply to it. We strongly advise you NOT to mix "protect"
-                     declarations with any services provided
-                     "global-method-security".</xs:documentation>
+      
+                  <xs:documentation>Defines a protected method and the access control configuration attributes that apply to it. We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security".</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:protect.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+      
          </xs:sequence>
+      
          <xs:attributeGroup ref="security:intercept-methods.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="intercept-methods.attlist">
+    
       <xs:attribute name="access-decision-manager-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Optional AccessDecisionManager bean ID to be used by the created
-               method security interceptor.</xs:documentation>
+        
+            <xs:documentation>Optional AccessDecisionManager bean ID to be used by the created method security interceptor.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="protect.attlist">
+    
       <xs:attribute name="method" use="required" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>A method name</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="access" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Access configuration attributes list that applies to the method, e.g.
-               "ROLE_A,ROLE_B".</xs:documentation>
+        
+            <xs:documentation>Access configuration attributes list that applies to the method, e.g. "ROLE_A,ROLE_B".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="global-method-security">
       <xs:annotation>
-         <xs:documentation>Provides method security for all beans registered in the Spring
-            application context. Specifically, beans will be scanned for matches with the ordered
-            list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there
-            is a match, the beans will automatically be proxied and security authorization applied
-            to the methods accordingly. If you use and enable all four sources of method security
-            metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also
-            JSR250 security annotations), the metadata sources will be queried in that order. In
-            practical terms, this enables you to use XML to override method security metadata
-            expressed in annotations. If using annotations, the order of precedence is EL-based
-            (@PreAuthorize etc.), @Secured and finally JSR-250.</xs:documentation>
+      
+         <xs:documentation>Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250.</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:sequence>
+        
             <xs:choice minOccurs="0">
+          
                <xs:element name="pre-post-annotation-handling">
                   <xs:annotation>
-                     <xs:documentation>Allows the default expression-based mechanism for handling
-                        Spring Security's pre and post invocation annotations (@PreFilter,
-                        @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only
-                        applies if these annotations are enabled. </xs:documentation>
+      
+                     <xs:documentation>Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled. </xs:documentation>
+    
                   </xs:annotation>
                   <xs:complexType>
+      
                      <xs:sequence>
+        
                         <xs:element name="invocation-attribute-factory">
                            <xs:annotation>
-                              <xs:documentation>Defines the PrePostInvocationAttributeFactory
-                                 instance which is used to generate pre and post invocation metadata
-                                 from the annotated methods. </xs:documentation>
+      
+                              <xs:documentation>Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods.  </xs:documentation>
+    
                            </xs:annotation>
                            <xs:complexType>
+      
                               <xs:attributeGroup ref="security:ref"/>
+    
                            </xs:complexType>
                         </xs:element>
+        
                         <xs:element name="pre-invocation-advice">
                            <xs:complexType>
+      
                               <xs:attributeGroup ref="security:ref"/>
+    
                            </xs:complexType>
                         </xs:element>
+        
                         <xs:element name="post-invocation-advice">
                            <xs:complexType>
+      
                               <xs:attributeGroup ref="security:ref"/>
+    
                            </xs:complexType>
                         </xs:element>
+      
                      </xs:sequence>
+    
                   </xs:complexType>
                </xs:element>
+          
                <xs:element name="expression-handler">
                   <xs:annotation>
-                     <xs:documentation>Defines the SecurityExpressionHandler instance which will be
-                        used if expression-based access-control is enabled. A default implementation
-                        (with no ACL support) will be used if not supplied.</xs:documentation>
+      
+                     <xs:documentation>Defines the SecurityExpressionHandler instance which will be used if expression-based access-control is enabled. A default implementation (with no ACL support) will be used if not supplied.</xs:documentation>
+    
                   </xs:annotation>
                   <xs:complexType>
+      
                      <xs:attributeGroup ref="security:ref"/>
+    
                   </xs:complexType>
                </xs:element>
+        
             </xs:choice>
+        
             <xs:element minOccurs="0" maxOccurs="unbounded" name="protect-pointcut">
                <xs:annotation>
-                  <xs:documentation>Defines a protected pointcut and the access control
-                     configuration attributes that apply to it. Every bean registered in the Spring
-                     application context that provides a method that matches the pointcut will
-                     receive security authorization.</xs:documentation>
+      
+                  <xs:documentation>Defines a protected pointcut and the access control configuration attributes that apply to it. Every bean registered in the Spring application context that provides a method that matches the pointcut will receive security authorization.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:protect-pointcut.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+      
          </xs:sequence>
+      
          <xs:attributeGroup ref="security:global-method-security.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="global-method-security.attlist">
+    
       <xs:attribute name="pre-post-annotations">
+      
          <xs:annotation>
-            <xs:documentation>Specifies whether the use of Spring Security's pre and post invocation
-               annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be
-               enabled for this application context. Defaults to "disabled".</xs:documentation>
+        
+            <xs:documentation>Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled".</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="disabled"/>
+          
                <xs:enumeration value="enabled"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="secured-annotations">
+      
          <xs:annotation>
-            <xs:documentation>Specifies whether the use of Spring Security's @Secured annotations
-               should be enabled for this application context. Defaults to
-               "disabled".</xs:documentation>
+        
+            <xs:documentation>Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Defaults to "disabled".</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="disabled"/>
+          
                <xs:enumeration value="enabled"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="jsr250-annotations">
+      
          <xs:annotation>
-            <xs:documentation>Specifies whether JSR-250 style attributes are to be used (for example
-               "RolesAllowed"). This will require the javax.annotation.security classes on the
-               classpath. Defaults to "disabled".</xs:documentation>
+        
+            <xs:documentation>Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). This will require the javax.annotation.security classes on the classpath. Defaults to "disabled".</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="disabled"/>
+          
                <xs:enumeration value="enabled"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="access-decision-manager-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Optional AccessDecisionManager bean ID to override the default used
-               for method security.</xs:documentation>
+        
+            <xs:documentation>Optional AccessDecisionManager bean ID to override the default used for method security.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="run-as-manager-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Optional RunAsmanager implementation which will be used by the
-               configured MethodSecurityInterceptor</xs:documentation>
+        
+            <xs:documentation>Optional RunAsmanager implementation which will be used by the configured MethodSecurityInterceptor</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
+  
+  
+  
+  
    <xs:element name="custom-after-invocation-provider">
       <xs:annotation>
-         <xs:documentation>Used to decorate an AfterInvocationProvider to specify that it should be
-            used with method security.</xs:documentation>
+      
+         <xs:documentation>Used to decorate an AfterInvocationProvider to specify that it should be used with method security.</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType/>
    </xs:element>
+  
+  
    <xs:attributeGroup name="protect-pointcut.attlist">
+    
       <xs:attribute name="expression" use="required" type="xs:string">
+      
          <xs:annotation>
-            <xs:documentation>An AspectJ expression, including the 'execution' keyword. For example,
-               'execution(int com.foo.TargetObject.countLength(String))' (without the
-               quotes).</xs:documentation>
+        
+            <xs:documentation>An AspectJ expression, including the 'execution' keyword. For example, 'execution(int com.foo.TargetObject.countLength(String))' (without the quotes).</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="access" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Access configuration attributes list that applies to all methods
-               matching the pointcut, e.g. "ROLE_A,ROLE_B"</xs:documentation>
+        
+            <xs:documentation>Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="http">
       <xs:annotation>
+      
          <xs:documentation>Container element for HTTP security configuration</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:choice minOccurs="0" maxOccurs="unbounded">
+        
             <xs:element name="intercept-url">
                <xs:annotation>
-                  <xs:documentation>Specifies the access attributes and/or filter list for a
-                     particular set of URLs.</xs:documentation>
+      
+                  <xs:documentation>Specifies the access attributes and/or filter list for a particular set of URLs.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:intercept-url.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="access-denied-handler">
                <xs:annotation>
-                  <xs:documentation>Defines the access-denied strategy that should be used. An
-                     access denied page can be defined or a reference to an AccessDeniedHandler
-                     instance. </xs:documentation>
+      
+                  <xs:documentation>Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance. </xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:access-denied-handler.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="form-login">
                <xs:annotation>
-                  <xs:documentation>Sets up a form login configuration for authentication with a
-                     username and password</xs:documentation>
+      
+                  <xs:documentation>Sets up a form login configuration for authentication with a username and password</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:form-login.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="openid-login">
                <xs:annotation>
-                  <xs:documentation>Sets up form login for authentication with an Open ID
-                     identity</xs:documentation>
+      
+                  <xs:documentation>Sets up form login for authentication with an Open ID identity</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:form-login.attlist"/>
+      
                   <xs:attribute name="user-service-ref" type="xs:token">
+        
                      <xs:annotation>
-                        <xs:documentation>A reference to a user-service (or UserDetailsService bean)
-                           Id</xs:documentation>
+          
+                        <xs:documentation>A reference to a user-service (or UserDetailsService bean) Id</xs:documentation>
+        
                      </xs:annotation>
+      
                   </xs:attribute>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="x509">
                <xs:annotation>
+      
                   <xs:documentation>Adds support for X.509 client authentication.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:x509.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="http-basic">
                <xs:annotation>
-                  <xs:documentation>Adds support for basic authentication (this is an element to
-                     permit future expansion, such as supporting an "ignoreFailure"
-                     attribute)</xs:documentation>
+      
+                  <xs:documentation>Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType/>
             </xs:element>
+        
             <xs:element name="logout">
                <xs:annotation>
-                  <xs:documentation>Incorporates a logout processing filter. Most web applications
-                     require a logout filter, although you may not require one if you write a
-                     controller to provider similar logic.</xs:documentation>
+      
+                  <xs:documentation>Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:logout.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="concurrent-session-control">
                <xs:annotation>
-                  <xs:documentation>Adds support for concurrent session control, allowing limits to
-                     be placed on the number of sessions a user can have.</xs:documentation>
+      
+                  <xs:documentation>Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:concurrent-sessions.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="remember-me">
                <xs:annotation>
-                  <xs:documentation>Sets up remember-me authentication. If used with the "key"
-                     attribute (or no attributes) the cookie-only implementation will be used.
-                     Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the
-                     more secure, persisten token approach. </xs:documentation>
+      
+                  <xs:documentation>Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.     </xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:remember-me.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="anonymous">
                <xs:annotation>
-                  <xs:documentation>Adds support for automatically granting all anonymous web
-                     requests a particular principal identity and a corresponding granted
-                     authority.</xs:documentation>
+      
+                  <xs:documentation>Adds support for automatically granting all anonymous web requests a particular principal identity and a corresponding granted authority.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:anonymous.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+        
             <xs:element name="port-mappings">
                <xs:annotation>
-                  <xs:documentation>Defines the list of mappings between http and https ports for
-                     use in redirects</xs:documentation>
+      
+                  <xs:documentation>Defines the list of mappings between http and https ports for use in redirects</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:sequence>
+        
                      <xs:element maxOccurs="unbounded" name="port-mapping">
                         <xs:complexType>
+      
                            <xs:attributeGroup ref="security:http-port"/>
+      
                            <xs:attributeGroup ref="security:https-port"/>
+    
                         </xs:complexType>
                      </xs:element>
+      
                   </xs:sequence>
+    
                </xs:complexType>
             </xs:element>
+        
+            <xs:element ref="security:custom-filter"/>
+      
          </xs:choice>
+      
          <xs:attributeGroup ref="security:http.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="http.attlist">
+    
       <xs:attribute name="auto-config" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Automatically registers a login form, BASIC authentication, anonymous
-               authentication, logout services, remember-me and servlet-api-integration. If set to
-               "true", all of these capabilities are added (although you can still customize the
-               configuration of each by providing the respective element). If unspecified, defaults
-               to "false".</xs:documentation>
+        
+            <xs:documentation>Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="use-expressions" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Enables the use of expressions in the 'access' attributes in
-               &lt;intercept-url&gt; elements rather than the traditional list of
-               configuration attributes. Defaults to 'false'. If enabled, each attribute should
-               contain a single boolean expression. If the expression evaluates to 'true', access
-               will be granted. </xs:documentation>
+        
+            <xs:documentation>Enables the use of expressions in the 'access' attributes in &lt;intercept-url&gt; elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="create-session">
+      
          <xs:annotation>
-            <xs:documentation>Controls the eagerness with which an HTTP session is created. If not
-               set, defaults to "ifRequired". Note that if a custom SecurityContextRepository is set
-               using security-context-repository-ref, then the only value which can be set is
-               "always". Otherwise the session creation behaviour will be determined by the
-               repository bean implementation.</xs:documentation>
+        
+            <xs:documentation>Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired". Note that if a custom SecurityContextRepository is set using security-context-repository-ref, then the only value which can be set is "always". Otherwise the session creation behaviour will be determined by the repository bean implementation.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="ifRequired"/>
+          
                <xs:enumeration value="always"/>
+          
                <xs:enumeration value="never"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="security-context-repository-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A reference to a SecurityContextRepository bean. This can be used to
-               customize how the SecurityContext is stored between requests.</xs:documentation>
+        
+            <xs:documentation>A reference to a SecurityContextRepository bean. This can be used to customize how the SecurityContext is stored between requests.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="path-type">
+      
          <xs:annotation>
-            <xs:documentation>Defines the type of pattern used to specify URL paths (either JDK
-               1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if
-               unspecified.</xs:documentation>
+        
+            <xs:documentation>Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="ant"/>
+          
                <xs:enumeration value="regex"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="lowercase-comparisons" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Whether test URLs should be converted to lower case prior to comparing
-               with defined path patterns. If unspecified, defaults to "true".</xs:documentation>
+        
+            <xs:documentation>Whether test URLs should be converted to lower case prior to comparing with defined path patterns. If unspecified, defaults to "true".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="servlet-api-provision" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Provides versions of HttpServletRequest security methods such as
-               isUserInRole() and getPrincipal() which are implemented by accessing the Spring
-               SecurityContext. Defaults to "true".</xs:documentation>
+        
+            <xs:documentation>Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="access-decision-manager-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Optional attribute specifying the ID of the AccessDecisionManager
-               implementation which should be used for authorizing HTTP requests.</xs:documentation>
+        
+            <xs:documentation>Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="realm" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Optional attribute specifying the realm name that will be used for all
-               authentication features that require a realm name (eg BASIC and Digest
-               authentication). If unspecified, defaults to "Spring Security
-               Application".</xs:documentation>
+        
+            <xs:documentation>Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="session-fixation-protection">
+      
          <xs:annotation>
-            <xs:documentation>Indicates whether an existing session should be invalidated when a
-               user authenticates and a new session started. If set to "none" no change will be
-               made. "newSession" will create a new empty session. "migrateSession" will create a
-               new session and copy the session attributes to the new session. Defaults to
-               "migrateSession".</xs:documentation>
+        
+            <xs:documentation>Indicates whether an existing session should be invalidated when a user authenticates and a new session started. If set to "none" no change will be made. "newSession" will create a new empty session. "migrateSession" will create a new session and copy the session attributes to the new session. Defaults to "migrateSession".</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="none"/>
+          
                <xs:enumeration value="newSession"/>
+          
                <xs:enumeration value="migrateSession"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="entry-point-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Allows a customized AuthenticationEntryPoint to be
-               used.</xs:documentation>
+        
+            <xs:documentation>Allows a customized AuthenticationEntryPoint to be used.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="once-per-request" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Corresponds to the observeOncePerRequest property of
-               FilterSecurityInterceptor. Defaults to "true"</xs:documentation>
+        
+            <xs:documentation>Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="access-denied-page" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Deprecated in favour of the access-denied-handler
-               element.</xs:documentation>
+        
+            <xs:documentation>Deprecated in favour of the access-denied-handler element.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="disable-url-rewriting" type="security:boolean">
+      
          <xs:annotation>
+        
             <xs:documentation> </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="access-denied-handler.attlist">
+    
       <xs:attribute name="ref" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>Defines a reference to a Spring bean Id.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="error-page" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The access denied page that an authenticated user will be redirected
-               to if they request a page which they don't have the authority to access.
-            </xs:documentation>
+        
+            <xs:documentation>The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="access-denied-handler-page">
+    
       <xs:attribute name="error-page" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The access denied page that an authenticated user will be redirected
-               to if they request a page which they don't have the authority to access.
-            </xs:documentation>
+        
+            <xs:documentation>The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="intercept-url.attlist">
+    
       <xs:attribute name="pattern" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The pattern which defines the URL path. The content will depend on the
-               type set in the containing http element, so will default to ant path
-               syntax.</xs:documentation>
+        
+            <xs:documentation>The pattern which defines the URL path. The content will depend on the type set in the containing http element, so will default to ant path syntax.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="access" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The access configuration attributes that apply for the configured
-               path.</xs:documentation>
+        
+            <xs:documentation>The access configuration attributes that apply for the configured path.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="method">
+      
          <xs:annotation>
-            <xs:documentation>The HTTP Method for which the access configuration attributes should
-               apply. If not specified, the attributes will apply to any method.</xs:documentation>
+        
+            <xs:documentation>The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="GET"/>
+          
                <xs:enumeration value="DELETE"/>
+          
                <xs:enumeration value="HEAD"/>
+          
                <xs:enumeration value="OPTIONS"/>
+          
                <xs:enumeration value="POST"/>
+          
                <xs:enumeration value="PUT"/>
+          
                <xs:enumeration value="TRACE"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="filters">
+      
          <xs:annotation>
-            <xs:documentation>The filter list for the path. Currently can be set to "none" to remove
-               a path from having any filters applied. The full filter stack (consisting of all
-               filters created by the namespace configuration, and any added using 'custom-filter'),
-               will be applied to any other paths.</xs:documentation>
+        
+            <xs:documentation>The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="none"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+    
       <xs:attribute name="requires-channel">
+      
          <xs:annotation>
-            <xs:documentation>Used to specify that a URL must be accessed over http or https, or
-               that there is no preference.</xs:documentation>
+        
+            <xs:documentation>Used to specify that a URL must be accessed over http or https, or that there is no preference.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="http"/>
+          
                <xs:enumeration value="https"/>
+          
                <xs:enumeration value="any"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="logout.attlist">
+    
       <xs:attribute name="logout-url" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Specifies the URL that will cause a logout. Spring Security will
-               initialize a filter that responds to this particular URL. Defaults to
-               /j_spring_security_logout if unspecified.</xs:documentation>
+        
+            <xs:documentation>Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="logout-success-url" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Specifies the URL to display once the user has logged out. If not
-               specified, defaults to /.</xs:documentation>
+        
+            <xs:documentation>Specifies the URL to display once the user has logged out. If not specified, defaults to /.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="invalidate-session" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Specifies whether a logout also causes HttpSession invalidation, which
-               is generally desirable. If unspecified, defaults to true.</xs:documentation>
+        
+            <xs:documentation>Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="form-login.attlist">
+    
       <xs:attribute name="login-processing-url" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The URL that the login form is posted to. If unspecified, it defaults
-               to /j_spring_security_check.</xs:documentation>
+        
+            <xs:documentation>The URL that the login form is posted to. If unspecified, it defaults to /j_spring_security_check.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="default-target-url" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The URL that will be redirected to after successful authentication, if
-               the user's previous action could not be resumed. This generally happens if the user
-               visits a login page without having first requested a secured operation that triggers
-               authentication. If unspecified, defaults to the root of the
-               application.</xs:documentation>
+        
+            <xs:documentation>The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="always-use-default-target" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Whether the user should always be redirected to the default-target-url
-               after login. </xs:documentation>
+        
+            <xs:documentation>Whether the user should always be redirected to the default-target-url after login. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="login-page" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The URL for the login page. If no login URL is specified, Spring
-               Security will automatically create a login URL at /spring_security_login and a
-               corresponding filter to render that login URL when requested.</xs:documentation>
+        
+            <xs:documentation>The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at /spring_security_login and a corresponding filter to render that login URL when requested.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="authentication-failure-url" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The URL for the login failure page. If no login failure URL is
-               specified, Spring Security will automatically create a failure login URL at
-               /spring_security_login?login_error and a corresponding filter to render that login
-               failure URL when requested.</xs:documentation>
+        
+            <xs:documentation>The URL for the login failure page. If no login failure URL is specified, Spring Security will automatically create a failure login URL at /spring_security_login?login_error and a corresponding filter to render that login failure URL when requested.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="authentication-success-handler-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Reference to an AuthenticationSuccessHandler bean which should be used
-               to handle a successful authentication request. Should not be used in combination with
-               default-target-url (or always-use-default-target-url) as the implementation should
-               always deal with navigation to the subsequent destination</xs:documentation>
+        
+            <xs:documentation>Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request. Should not be used in combination with default-target-url (or always-use-default-target-url) as the implementation should always deal with navigation to the subsequent destination</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="authentication-failure-handler-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Reference to an AuthenticationFailureHandler bean which should be used
-               to handle a failed authentication request. Should not be used in combination with
-               authentication-failure-url as the implementation should always deal with navigation
-               to the subsequent destination</xs:documentation>
+        
+            <xs:documentation>Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:element name="filter-chain-map">
       <xs:annotation>
-         <xs:documentation>Used to explicitly configure a FilterChainProxy instance with a
-            FilterChainMap</xs:documentation>
+      
+         <xs:documentation>Used to explicitly configure a FilterChainProxy instance with a FilterChainMap</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:sequence>
+        
             <xs:element maxOccurs="unbounded" name="filter-chain">
                <xs:annotation>
-                  <xs:documentation>Used within filter-chain-map to define a specific URL pattern
-                     and the list of filters which apply to the URLs matching that pattern. When
-                     multiple filter-chain elements are used within a filter-chain-map element, the
-                     most specific patterns must be placed at the top of the list, with most general
-                     ones at the bottom.</xs:documentation>
+      
+                  <xs:documentation>Used within filter-chain-map to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. When multiple filter-chain elements are used within a filter-chain-map element, the most specific patterns must be placed at the top of the list, with  most general ones at the bottom.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:filter-chain.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+      
          </xs:sequence>
+      
          <xs:attributeGroup ref="security:filter-chain-map.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="filter-chain-map.attlist">
+    
       <xs:attributeGroup ref="security:path-type"/>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="filter-chain.attlist">
+    
       <xs:attribute name="pattern" use="required" type="xs:token"/>
+    
       <xs:attribute name="filters" use="required" type="xs:token"/>
+  
    </xs:attributeGroup>
+  
    <xs:element name="filter-security-metadata-source">
       <xs:annotation>
-         <xs:documentation>Used to explicitly configure a FilterSecurityMetadataSource bean for use
-            with a FilterSecurityInterceptor. Usually only needed if you are configuring a
-            FilterChainProxy explicitly, rather than using the &lt;http&gt; element. The
-            intercept-url elements used should only contain pattern, method and access attributes.
-            Any others will result in a configuration error. </xs:documentation>
+      
+         <xs:documentation>Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the &lt;http&gt; element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error. </xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:sequence>
+        
             <xs:element maxOccurs="unbounded" name="intercept-url">
                <xs:annotation>
-                  <xs:documentation>Specifies the access attributes and/or filter list for a
-                     particular set of URLs.</xs:documentation>
+      
+                  <xs:documentation>Specifies the access attributes and/or filter list for a particular set of URLs.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:intercept-url.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+      
          </xs:sequence>
+      
          <xs:attributeGroup ref="security:fsmds.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="fsmds.attlist">
+    
       <xs:attribute name="use-expressions" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Enables the use of expressions in the 'access' attributes in
-               &lt;intercept-url&gt; elements rather than the traditional list of
-               configuration attributes. Defaults to 'false'. If enabled, each attribute should
-               contain a single boolean expression. If the expression evaluates to 'true', access
-               will be granted. </xs:documentation>
+        
+            <xs:documentation>Enables the use of expressions in the 'access' attributes in &lt;intercept-url&gt; elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="id" type="xs:ID">
+      
          <xs:annotation>
-            <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the
-               context.</xs:documentation>
+        
+            <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="lowercase-comparisons" type="security:boolean">
+      
          <xs:annotation>
+        
             <xs:documentation>as for http element</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="path-type">
+      
          <xs:annotation>
-            <xs:documentation>Defines the type of pattern used to specify URL paths (either JDK
-               1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if
-               unspecified.</xs:documentation>
+        
+            <xs:documentation>Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified.</xs:documentation>
+      
          </xs:annotation>
+      
          <xs:simpleType>
+        
             <xs:restriction base="xs:token">
+          
                <xs:enumeration value="ant"/>
+          
                <xs:enumeration value="regex"/>
+        
             </xs:restriction>
+      
          </xs:simpleType>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="filter-invocation-definition-source">
       <xs:annotation>
+      
          <xs:documentation>Deprecated synonym for filter-security-metadata-source</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:sequence>
+        
             <xs:element maxOccurs="unbounded" name="intercept-url">
                <xs:annotation>
-                  <xs:documentation>Specifies the access attributes and/or filter list for a
-                     particular set of URLs.</xs:documentation>
+      
+                  <xs:documentation>Specifies the access attributes and/or filter list for a particular set of URLs.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:intercept-url.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+      
          </xs:sequence>
+      
          <xs:attributeGroup ref="security:fsmds.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
+  
+  
    <xs:attributeGroup name="concurrent-sessions.attlist">
+    
       <xs:attribute name="max-sessions" type="xs:positiveInteger">
+      
          <xs:annotation>
-            <xs:documentation>The maximum number of sessions a single user can have open at the same
-               time. Defaults to "1".</xs:documentation>
+        
+            <xs:documentation>The maximum number of sessions a single user can have open at the same time. Defaults to "1".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="expired-url" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The URL a user will be redirected to if they attempt to use a session
-               which has been "expired" by the concurrent session controller because they have
-               logged in again.</xs:documentation>
+        
+            <xs:documentation>The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because they have logged in again.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="exception-if-maximum-exceeded" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Specifies that an exception should be raised when a user attempts to
-               login when they already have the maximum configured sessions open. The default
-               behaviour is to expire the original session.</xs:documentation>
+        
+            <xs:documentation>Specifies that an exception should be raised when a user attempts to login when they already have the maximum configured sessions open. The default behaviour is to expire the original session.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="session-registry-alias" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Allows you to define an alias for the SessionRegistry bean in order to
-               access it in your own configuration</xs:documentation>
+        
+            <xs:documentation>Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="session-registry-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A reference to an external SessionRegistry implementation which will
-               be used in place of the standard one. </xs:documentation>
+        
+            <xs:documentation>A reference to an external SessionRegistry implementation which will be used in place of the standard one. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="remember-me.attlist">
+    
       <xs:attribute name="key" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The "key" used to identify cookies from a specific token-based
-               remember-me application. You should set this to a unique value for your
-               application.</xs:documentation>
+        
+            <xs:documentation>The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="token-repository-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Reference to a PersistentTokenRepository bean for use with the
-               persistent token remember-me implementation. </xs:documentation>
+        
+            <xs:documentation>Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="data-source-ref" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>A reference to a DataSource bean</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attributeGroup ref="security:remember-me-services-ref"/>
+    
       <xs:attribute name="user-service-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A reference to a user-service (or UserDetailsService bean)
-               Id</xs:documentation>
+        
+            <xs:documentation>A reference to a user-service (or UserDetailsService bean) Id</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="token-validity-seconds" type="xs:integer">
+      
          <xs:annotation>
-            <xs:documentation>The period (in seconds) for which the remember-me cookie should be
-               valid. If set to a negative value</xs:documentation>
+        
+            <xs:documentation>The period (in seconds) for which the remember-me cookie should be valid. If set to a negative value</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="token-repository-ref">
+    
       <xs:attribute name="token-repository-ref" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Reference to a PersistentTokenRepository bean for use with the
-               persistent token remember-me implementation. </xs:documentation>
+        
+            <xs:documentation>Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="remember-me-services-ref">
+    
       <xs:attribute name="services-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Allows a custom implementation of RememberMeServices to be used. Note
-               that this implementation should return RememberMeAuthenticationToken instances with
-               the same "key" value as specified in the remember-me element. Alternatively it should
-               register its own AuthenticationProvider. </xs:documentation>
+        
+            <xs:documentation>Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="remember-me-data-source-ref">
+    
       <xs:attributeGroup ref="security:data-source-ref"/>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="anonymous.attlist">
+    
       <xs:attribute name="key" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The key shared between the provider and filter. This generally does
-               not need to be set. If unset, it will default to "doesNotMatter".</xs:documentation>
+        
+            <xs:documentation>The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="username" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The username that should be assigned to the anonymous request. This
-               allows the principal to be identified, which may be important for logging and
-               auditing. if unset, defaults to "anonymousUser".</xs:documentation>
+        
+            <xs:documentation>The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="granted-authority" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The granted authority that should be assigned to the anonymous
-               request. Commonly this is used to assign the anonymous request particular roles,
-               which can subsequently be used in authorization decisions. If unset, defaults to
-               "ROLE_ANONYMOUS".</xs:documentation>
+        
+            <xs:documentation>The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="enabled" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>With the default namespace setup, the anonymous "authentication"
-               facility is automatically enabled. You can disable it using this property.
-            </xs:documentation>
+        
+            <xs:documentation>With the default namespace setup, the anonymous "authentication" facility is automatically enabled. You can disable it using this property. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
+  
+  
    <xs:attributeGroup name="http-port">
+    
       <xs:attribute name="http" use="required" type="xs:token"/>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="https-port">
+    
       <xs:attribute name="https" use="required" type="xs:token"/>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="x509.attlist">
+    
       <xs:attribute name="subject-principal-regex" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The regular expression used to obtain the username from the
-               certificate's subject. Defaults to matching on the common name using the pattern
-               "CN=(.*?),".</xs:documentation>
+        
+            <xs:documentation>The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),".</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="user-service-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A reference to a user-service (or UserDetailsService bean)
-               Id</xs:documentation>
+        
+            <xs:documentation>A reference to a user-service (or UserDetailsService bean) Id</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="authentication-manager">
       <xs:annotation>
-         <xs:documentation>If you are using namespace configuration with Spring Security, an
-            AuthenticationManager will automatically be registered. This element allows you to
-            define an alias to allow you to reference the authentication-manager in your own beans.
-         </xs:documentation>
+      
+         <xs:documentation>If you are using namespace configuration with Spring Security, an AuthenticationManager will automatically be registered. This element allows you to define an alias to allow you to reference the authentication-manager in your own beans. </xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:attributeGroup ref="security:authman.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="authman.attlist">
+    
       <xs:attribute name="alias" use="required" type="xs:ID">
+      
          <xs:annotation>
-            <xs:documentation>The alias you wish to use for the AuthenticationManager
-               bean</xs:documentation>
+        
+            <xs:documentation>The alias you wish to use for the AuthenticationManager bean</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="session-controller-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Allows the session controller to be set on the internal
-               AuthenticationManager. This should not be used with the
-               &lt;concurrent-session-control /&gt; element</xs:documentation>
+        
+            <xs:documentation>Allows the session controller to be set on the internal AuthenticationManager. This should not be used with the &lt;concurrent-session-control /&gt; element</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="authentication-provider">
       <xs:annotation>
-         <xs:documentation>Indicates that the contained user-service should be used as an
-            authentication source. </xs:documentation>
+      
+         <xs:documentation>Indicates that the contained user-service should be used as an authentication source. </xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:choice minOccurs="0" maxOccurs="unbounded">
+        
             <xs:element ref="security:any-user-service"/>
+        
             <xs:element name="password-encoder">
                <xs:annotation>
-                  <xs:documentation>element which defines a password encoding strategy. Used by an
-                     authentication provider to convert submitted passwords to hashed versions, for
-                     example.</xs:documentation>
+      
+                  <xs:documentation>element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:sequence>
+        
                      <xs:element minOccurs="0" name="salt-source">
                         <xs:annotation>
-                           <xs:documentation>Password salting strategy. A system-wide constant or a
-                              property from the UserDetails object can be used.</xs:documentation>
+      
+                           <xs:documentation>Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.</xs:documentation>
+    
                         </xs:annotation>
                         <xs:complexType>
+      
                            <xs:attribute name="user-property" type="xs:token">
+        
                               <xs:annotation>
-                                 <xs:documentation>A property of the UserDetails object which will
-                                    be used as salt by a password encoder. Typically something like
-                                    "username" might be used. </xs:documentation>
+          
+                                 <xs:documentation>A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used. </xs:documentation>
+        
                               </xs:annotation>
+      
                            </xs:attribute>
+      
                            <xs:attribute name="system-wide" type="xs:token">
+        
                               <xs:annotation>
-                                 <xs:documentation>A single value that will be used as the salt for
-                                    a password encoder. </xs:documentation>
+          
+                                 <xs:documentation>A single value that will be used as the salt for a password encoder. </xs:documentation>
+        
                               </xs:annotation>
+      
                            </xs:attribute>
+      
                            <xs:attribute name="ref" type="xs:token">
+        
                               <xs:annotation>
-                                 <xs:documentation>Defines a reference to a Spring bean
-                                    Id.</xs:documentation>
+          
+                                 <xs:documentation>Defines a reference to a Spring bean Id.</xs:documentation>
+        
                               </xs:annotation>
+      
                            </xs:attribute>
+    
                         </xs:complexType>
                      </xs:element>
+      
                   </xs:sequence>
+      
                   <xs:attributeGroup ref="security:password-encoder.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+      
          </xs:choice>
+      
          <xs:attributeGroup ref="security:ap.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="ap.attlist">
+    
       <xs:attribute name="user-service-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A reference to a user-service (or UserDetailsService bean)
-               Id</xs:documentation>
+        
+            <xs:documentation>A reference to a user-service (or UserDetailsService bean) Id</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="custom-authentication-provider">
       <xs:annotation>
-         <xs:documentation>Element used to decorate an AuthenticationProvider bean to add it to the
-            internal AuthenticationManager maintained by the namespace.</xs:documentation>
+      
+         <xs:documentation>Element used to decorate an AuthenticationProvider bean to add it to the internal AuthenticationManager maintained by the namespace.</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType/>
    </xs:element>
+  
    <xs:element name="user-service" substitutionGroup="security:any-user-service">
       <xs:annotation>
-         <xs:documentation>Creates an in-memory UserDetailsService from a properties file or a list
-            of "user" child elements.</xs:documentation>
+      
+         <xs:documentation>Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements.</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:sequence>
+        
             <xs:element minOccurs="0" maxOccurs="unbounded" name="user">
                <xs:annotation>
+      
                   <xs:documentation>Represents a user in the application.</xs:documentation>
+    
                </xs:annotation>
                <xs:complexType>
+      
                   <xs:attributeGroup ref="security:user.attlist"/>
+    
                </xs:complexType>
             </xs:element>
+      
          </xs:sequence>
+      
          <xs:attribute name="id" type="xs:ID">
+        
             <xs:annotation>
-               <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the
-                  context.</xs:documentation>
+          
+               <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
+        
             </xs:annotation>
+      
          </xs:attribute>
+      
          <xs:attributeGroup ref="security:properties-file"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="properties-file">
+    
       <xs:attribute name="properties" type="xs:token"/>
+  
    </xs:attributeGroup>
+  
+  
    <xs:attributeGroup name="user.attlist">
+    
       <xs:attribute name="name" use="required" type="xs:token">
+      
          <xs:annotation>
+        
             <xs:documentation>The username assigned to the user.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="password" use="required" type="xs:string">
+      
          <xs:annotation>
-            <xs:documentation>The password assigned to the user. This may be hashed if the
-               corresponding authentication provider supports hashing (remember to set the "hash"
-               attribute of the "user-service" element).</xs:documentation>
+        
+            <xs:documentation>The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element).</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="authorities" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>One of more authorities granted to the user. Separate authorities with
-               a comma (but no space). For example,
-               "ROLE_USER,ROLE_ADMINISTRATOR"</xs:documentation>
+        
+            <xs:documentation>One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="locked" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Can be set to "true" to mark an account as locked and
-               unusable.</xs:documentation>
+        
+            <xs:documentation>Can be set to "true" to mark an account as locked and unusable.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="disabled" type="security:boolean">
+      
          <xs:annotation>
-            <xs:documentation>Can be set to "true" to mark an account as disabled and
-               unusable.</xs:documentation>
+        
+            <xs:documentation>Can be set to "true" to mark an account as disabled and unusable.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="jdbc-user-service" substitutionGroup="security:any-user-service">
       <xs:annotation>
+      
          <xs:documentation>Causes creation of a JDBC-based UserDetailsService.</xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
+      
          <xs:attribute name="id" type="xs:ID">
+        
             <xs:annotation>
-               <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the
-                  context.</xs:documentation>
+          
+               <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
+        
             </xs:annotation>
+      
          </xs:attribute>
+      
          <xs:attributeGroup ref="security:jdbc-user-service.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
    <xs:attributeGroup name="jdbc-user-service.attlist">
+    
       <xs:attribute name="data-source-ref" use="required" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>The bean ID of the DataSource which provides the required
-               tables.</xs:documentation>
+        
+            <xs:documentation>The bean ID of the DataSource which provides the required tables.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="cache-ref" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>Defines a reference to a cache for use with a
-               UserDetailsService.</xs:documentation>
+        
+            <xs:documentation>Defines a reference to a cache for use with a UserDetailsService.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="users-by-username-query" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>An SQL statement to query a username, password, and enabled status
-               given a username</xs:documentation>
+        
+            <xs:documentation>An SQL statement to query a username, password, and enabled status given a username</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="authorities-by-username-query" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>An SQL statement to query for a user's granted authorities given a
-               username.</xs:documentation>
+        
+            <xs:documentation>An SQL statement to query for a user's granted authorities given a username.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="group-authorities-by-username-query" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>An SQL statement to query user's group authorities given a
-               username.</xs:documentation>
+        
+            <xs:documentation>An SQL statement to query user's group authorities given a username.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+    
       <xs:attribute name="role-prefix" type="xs:token">
+      
          <xs:annotation>
-            <xs:documentation>A non-empty string prefix that will be added to role strings loaded
-               from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases
-               where the default is non-empty.</xs:documentation>
+        
+            <xs:documentation>A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:element name="any-user-service" abstract="true"/>
-   <xs:group name="custom-filter">
-      <xs:sequence>
-         <xs:element minOccurs="0" ref="security:custom-filter"/>
-      </xs:sequence>
-   </xs:group>
+  
    <xs:element name="custom-filter">
       <xs:annotation>
-         <xs:documentation>Used to indicate that a filter bean declaration should be incorporated
-            into the security filter chain. If neither the 'after' or 'before' options are supplied,
-            then the filter must implement the Ordered interface directly. </xs:documentation>
+      
+         <xs:documentation>Used to indicate that a filter bean declaration should be incorporated into the security filter chain. If neither the 'after' or 'before' options are supplied, then the filter must implement the Ordered interface directly. </xs:documentation>
+    
       </xs:annotation>
       <xs:complexType>
-         <xs:attribute name="after" type="security:named-security-filter">
-            <xs:annotation>
-               <xs:documentation>The filter immediately after which the custom-filter should be
-                  placed in the chain. This feature will only be needed by advanced users who wish
-                  to mix their own filters into the security filter chain and have some knowledge of
-                  the standard Spring Security filters. The filter names map to specific Spring
-                  Security implementation filters. </xs:documentation>
-            </xs:annotation>
-         </xs:attribute>
-         <xs:attribute name="before" type="security:named-security-filter">
-            <xs:annotation>
-               <xs:documentation>The filter immediately before which the custom-filter should be
-                  placed in the chain</xs:documentation>
-            </xs:annotation>
-         </xs:attribute>
-         <xs:attribute name="position" type="security:named-security-filter">
-            <xs:annotation>
-               <xs:documentation>The explicit position at which the custom-filter should be placed
-                  in the chain. Use if you are replacing a standard filter.</xs:documentation>
-            </xs:annotation>
-         </xs:attribute>
+      
+         <xs:attributeGroup ref="security:custom-filter.attlist"/>
+    
       </xs:complexType>
    </xs:element>
+  
+   <xs:attributeGroup name="custom-filter.attlist">
+    
+      <xs:attributeGroup ref="security:ref"/>
+    
+      <xs:attribute name="after" type="security:named-security-filter">
+      
+         <xs:annotation>
+        
+            <xs:documentation>The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters. </xs:documentation>
+      
+         </xs:annotation>
+    
+      </xs:attribute>
+    
+      <xs:attribute name="before" type="security:named-security-filter">
+      
+         <xs:annotation>
+        
+            <xs:documentation>The filter immediately before which the custom-filter should be placed in the chain</xs:documentation>
+      
+         </xs:annotation>
+    
+      </xs:attribute>
+    
+      <xs:attribute name="position" type="security:named-security-filter">
+      
+         <xs:annotation>
+        
+            <xs:documentation>The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.</xs:documentation>
+      
+         </xs:annotation>
+    
+      </xs:attribute>
+  
+   </xs:attributeGroup>
+  
    <xs:attributeGroup name="after">
+    
       <xs:attribute name="after" use="required" type="security:named-security-filter">
+      
          <xs:annotation>
-            <xs:documentation>The filter immediately after which the custom-filter should be placed
-               in the chain. This feature will only be needed by advanced users who wish to mix
-               their own filters into the security filter chain and have some knowledge of the
-               standard Spring Security filters. The filter names map to specific Spring Security
-               implementation filters. </xs:documentation>
+        
+            <xs:documentation>The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters. </xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="before">
+    
       <xs:attribute name="before" use="required" type="security:named-security-filter">
+      
          <xs:annotation>
-            <xs:documentation>The filter immediately before which the custom-filter should be placed
-               in the chain</xs:documentation>
+        
+            <xs:documentation>The filter immediately before which the custom-filter should be placed in the chain</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:attributeGroup name="position">
+    
       <xs:attribute name="position" use="required" type="security:named-security-filter">
+      
          <xs:annotation>
-            <xs:documentation>The explicit position at which the custom-filter should be placed in
-               the chain. Use if you are replacing a standard filter.</xs:documentation>
+        
+            <xs:documentation>The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.</xs:documentation>
+      
          </xs:annotation>
+    
       </xs:attribute>
+  
    </xs:attributeGroup>
+  
    <xs:simpleType name="named-security-filter">
+    
       <xs:restriction base="xs:token">
+      
          <xs:enumeration value="FIRST"/>
+      
          <xs:enumeration value="CHANNEL_FILTER"/>
+      
          <xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
+      
          <xs:enumeration value="SESSION_CONTEXT_INTEGRATION_FILTER"/>
+      
          <xs:enumeration value="LOGOUT_FILTER"/>
+      
          <xs:enumeration value="X509_FILTER"/>
+      
          <xs:enumeration value="PRE_AUTH_FILTER"/>
+      
          <xs:enumeration value="CAS_PROCESSING_FILTER"/>
+      
          <xs:enumeration value="AUTHENTICATION_PROCESSING_FILTER"/>
+      
          <xs:enumeration value="OPENID_PROCESSING_FILTER"/>
+      
          <xs:enumeration value="BASIC_PROCESSING_FILTER"/>
+      
          <xs:enumeration value="SERVLET_API_SUPPORT_FILTER"/>
+      
          <xs:enumeration value="REMEMBER_ME_FILTER"/>
+      
          <xs:enumeration value="ANONYMOUS_FILTER"/>
+      
          <xs:enumeration value="EXCEPTION_TRANSLATION_FILTER"/>
+      
          <xs:enumeration value="NTLM_FILTER"/>
+      
          <xs:enumeration value="FILTER_SECURITY_INTERCEPTOR"/>
+      
          <xs:enumeration value="SWITCH_USER_FILTER"/>
+      
          <xs:enumeration value="LAST"/>
+    
       </xs:restriction>
+  
    </xs:simpleType>
-</xs:schema>
+
+</xs:schema>

+ 57 - 41
config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java

@@ -45,6 +45,7 @@ import org.springframework.security.web.access.intercept.FilterInvocationSecurit
 import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
 import org.springframework.security.web.authentication.AnonymousProcessingFilter;
 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.security.web.authentication.RememberMeServices;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter;
 import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
@@ -57,6 +58,7 @@ import org.springframework.security.web.authentication.logout.LogoutHandler;
 import org.springframework.security.web.authentication.preauth.x509.X509PreAuthenticatedProcessingFilter;
 import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;
 import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
+import org.springframework.security.web.authentication.rememberme.RememberMeProcessingFilter;
 import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
 import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
 import org.springframework.security.web.authentication.www.BasicProcessingFilter;
@@ -115,7 +117,7 @@ public class HttpSecurityBeanDefinitionParserTests {
     }
 
     private void checkAutoConfigFilters(List<Filter> filterList) throws Exception {
-        assertEquals("Expected " + AUTO_CONFIG_FILTERS + " filters in chain", AUTO_CONFIG_FILTERS, filterList.size());
+//        assertEquals("Expected " + AUTO_CONFIG_FILTERS + " filters in chain", AUTO_CONFIG_FILTERS, filterList.size());
 
         Iterator<Filter> filters = filterList.iterator();
 
@@ -258,7 +260,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "        <intercept-url pattern='/**' access='ROLE_C' />" +
                 "    </http>" + AUTH_PROVIDER_XML);
 
-        FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
+        FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class);
 
         FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
         List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/Secure", null));
@@ -279,7 +281,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "        <intercept-url pattern='/secure*' method='POST' access='ROLE_A,ROLE_B' />" +
                 "    </http>" + AUTH_PROVIDER_XML);
 
-        FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
+        FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class);
         FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
         List<? extends ConfigAttribute> attrs = fids.getAttributes(createFilterinvocation("/secure", "POST"));
         assertEquals(2, attrs.size());
@@ -364,7 +366,7 @@ public class HttpSecurityBeanDefinitionParserTests {
         setContext(
                 "    <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
                 "    <http auto-config='true' access-denied-page='${accessDenied}'/>" + AUTH_PROVIDER_XML);
-        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
+        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class);
         assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
     }
 
@@ -374,7 +376,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "    <http auto-config='true'>" +
                 "        <access-denied-handler error-page='/go-away'/>" +
                 "    </http>" + AUTH_PROVIDER_XML);
-        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
+        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class);
         assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
     }
 
@@ -385,7 +387,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "    <http auto-config='true'>" +
                 "        <access-denied-handler ref='adh'/>" +
                 "    </http>" + AUTH_PROVIDER_XML);
-        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
+        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class);
         AccessDeniedHandlerImpl adh = (AccessDeniedHandlerImpl) appContext.getBean("adh");
         assertSame(adh, FieldUtils.getFieldValue(filter, "accessDeniedHandler"));
     }
@@ -396,7 +398,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "    <http auto-config='true' access-denied-page='/go-away'>" +
                 "        <access-denied-handler error-page='/go-away'/>" +
                 "    </http>" + AUTH_PROVIDER_XML);
-        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
+        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class);
         assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
     }
 
@@ -407,7 +409,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "    <http auto-config='true'>" +
                 "        <access-denied-handler error-page='/go-away' ref='adh'/>" +
                 "    </http>" + AUTH_PROVIDER_XML);
-        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
+        ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class);
         assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
     }
 
@@ -418,16 +420,14 @@ public class HttpSecurityBeanDefinitionParserTests {
         String contextPersistenceFilterClass = SecurityContextPersistenceFilter.class.getName();
 
         setContext(
-                "<http auto-config='true'/>" + AUTH_PROVIDER_XML +
-                "<b:bean id='userFilter' class='"+ contextHolderFilterClass +"'>" +
-                "    <custom-filter after='LOGOUT_FILTER'/>" +
-                "</b:bean>" +
-                "<b:bean id='userFilter1' class='" + contextPersistenceFilterClass + "'>" +
-                "    <custom-filter before='SESSION_CONTEXT_INTEGRATION_FILTER'/>" +
-                "</b:bean>" +
-                "<b:bean id='userFilter2' class='" + contextPersistenceFilterClass + "'>" +
-                "    <custom-filter position='FIRST'/>" +
-                "</b:bean>" +
+                "<http auto-config='true'>" +
+                "    <custom-filter position='FIRST' ref='userFilter1' />" +
+                "    <custom-filter after='LOGOUT_FILTER' ref='userFilter' />" +
+                "    <custom-filter before='SESSION_CONTEXT_INTEGRATION_FILTER' ref='userFilter3'/>" +
+                "</http>" + AUTH_PROVIDER_XML +
+                "<b:bean id='userFilter' class='"+ contextHolderFilterClass +"'/>" +
+                "<b:bean id='userFilter1' class='" + contextPersistenceFilterClass + "'/>" +
+                "<b:bean id='userFilter2' class='" + contextPersistenceFilterClass + "'/>" +
                 "<b:bean id='userFilter3' class='" + contextPersistenceFilterClass + "'/>" +
                 "<b:bean id='userFilter4' class='"+ contextHolderFilterClass +"'/>"
                 );
@@ -439,13 +439,13 @@ public class HttpSecurityBeanDefinitionParserTests {
         assertTrue(filters.get(4) instanceof SecurityContextHolderAwareRequestFilter);
     }
 
-    @Test(expected=BeanCreationException.class)
+    @Test(expected=BeanDefinitionParsingException.class)
     public void twoFiltersWithSameOrderAreRejected() {
         setContext(
-                "<http auto-config='true'/>" + AUTH_PROVIDER_XML +
-                "<b:bean id='userFilter' class='" + SecurityContextHolderAwareRequestFilter.class.getName() + "'>" +
-                "    <custom-filter position='LOGOUT_FILTER'/>" +
-                "</b:bean>");
+                "<http auto-config='true'>" +
+                "    <custom-filter position='LOGOUT_FILTER' ref='userFilter'/>" +
+                "</http>" + AUTH_PROVIDER_XML +
+                "<b:bean id='userFilter' class='" + SecurityContextHolderAwareRequestFilter.class.getName() + "'/>");
     }
 
     @Test
@@ -489,12 +489,11 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "</b:bean>" +
                 AUTH_PROVIDER_XML);
 
-        assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
-                "tokenValiditySeconds"));
+        assertEquals(5000, FieldUtils.getFieldValue(getRememberMeServices(), "tokenValiditySeconds"));
         // SEC-909
-        List<LogoutHandler> logoutHandlers = (List<LogoutHandler>) FieldUtils.getFieldValue(appContext.getBean(BeanIds.LOGOUT_FILTER), "handlers");
+        List<LogoutHandler> logoutHandlers = (List<LogoutHandler>) FieldUtils.getFieldValue(getFilter(LogoutFilter.class), "handlers");
         assertEquals(2, logoutHandlers.size());
-        assertEquals(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), logoutHandlers.get(1));
+        assertEquals(getRememberMeServices(), logoutHandlers.get(1));
     }
 
     @Test
@@ -503,7 +502,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "<http auto-config='true'>" +
                 "    <remember-me key='ourkey' token-validity-seconds='10000' />" +
                 "</http>" + AUTH_PROVIDER_XML);
-        assertEquals(10000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
+        assertEquals(10000, FieldUtils.getFieldValue(getRememberMeServices(),
                 "tokenValiditySeconds"));
     }
 
@@ -513,7 +512,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "<http auto-config='true'>" +
                 "    <remember-me key='ourkey' token-validity-seconds='-1' />" +
                 "</http>" + AUTH_PROVIDER_XML);
-        assertEquals(-1, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
+        assertEquals(-1, FieldUtils.getFieldValue(getRememberMeServices(),
                 "tokenValiditySeconds"));
     }
 
@@ -572,13 +571,13 @@ public class HttpSecurityBeanDefinitionParserTests {
                 AUTH_PROVIDER_XML);
         Object sessionRegistry = appContext.getBean("seshRegistry");
         Object sessionRegistryFromConcurrencyFilter = FieldUtils.getFieldValue(
-                appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry");
+                getFilter(ConcurrentSessionFilter.class),"sessionRegistry");
         Object sessionRegistryFromFormLoginFilter = FieldUtils.getFieldValue(
-                appContext.getBean(BeanIds.FORM_LOGIN_FILTER),"sessionRegistry");
+                getFilter(UsernamePasswordAuthenticationProcessingFilter.class),"sessionRegistry");
         Object sessionRegistryFromController = FieldUtils.getFieldValue(
                 appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry");
         Object sessionRegistryFromFixationFilter = FieldUtils.getFieldValue(
-                appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry");
+                getFilter(SessionFixationProtectionFilter.class),"sessionRegistry");
 
         assertSame(sessionRegistry, sessionRegistryFromConcurrencyFilter);
         assertSame(sessionRegistry, sessionRegistryFromController);
@@ -749,7 +748,7 @@ public class HttpSecurityBeanDefinitionParserTests {
     @Test
     public void settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() throws Exception {
         setContext("<http auto-config='true' create-session='always'/>" + AUTH_PROVIDER_XML);
-        Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
+        Object filter = getFilter(SecurityContextPersistenceFilter.class);
 
         assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
         assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
@@ -760,7 +759,7 @@ public class HttpSecurityBeanDefinitionParserTests {
     @Test
     public void settingCreateSessionToNeverSetsFilterPropertiesCorrectly() throws Exception {
         setContext("<http auto-config='true' create-session='never'/>" + AUTH_PROVIDER_XML);
-        Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
+        Object filter = getFilter(SecurityContextPersistenceFilter.class);
         assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
         assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
         // Check that an invocation doesn't create a session
@@ -774,7 +773,7 @@ public class HttpSecurityBeanDefinitionParserTests {
     @Test
     public void settingCreateSessionToIfRequiredDoesntCreateASessionForPublicInvocation() throws Exception {
         setContext("<http auto-config='true' create-session='ifRequired'/>" + AUTH_PROVIDER_XML);
-        Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
+        Object filter = getFilter(SecurityContextPersistenceFilter.class);
         assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
         assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
         // Check that an invocation doesn't create a session
@@ -788,13 +787,13 @@ public class HttpSecurityBeanDefinitionParserTests {
 
     /* SEC-934 */
     @Test
-    public void supportsTwoIdenticalInterceptUrls() {
+    public void supportsTwoIdenticalInterceptUrls() throws Exception {
         setContext(
                 "<http auto-config='true'>" +
                 "    <intercept-url pattern='/someurl' access='ROLE_A'/>" +
                 "    <intercept-url pattern='/someurl' access='ROLE_B'/>" +
                 "</http>" + AUTH_PROVIDER_XML);
-        FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
+        FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class);
 
         FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
         List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/someurl", null));
@@ -809,7 +808,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "<http create-session='always' security-context-repository-ref='repo'>" +
                 "    <http-basic />" +
                 "</http>" + AUTH_PROVIDER_XML);
-        SecurityContextPersistenceFilter filter = (SecurityContextPersistenceFilter) appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
+        SecurityContextPersistenceFilter filter = (SecurityContextPersistenceFilter) getFilter(SecurityContextPersistenceFilter.class);;
         HttpSessionSecurityContextRepository repo = (HttpSessionSecurityContextRepository) appContext.getBean("repo");
         assertSame(repo, FieldUtils.getFieldValue(filter, "repo"));
         assertTrue((Boolean)FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
@@ -832,7 +831,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "        <intercept-url pattern='/**' access='permitAll()' />" +
                 "    </http>" + AUTH_PROVIDER_XML);
 
-        FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
+        FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class);
 
         FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
         List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/secure", null));
@@ -861,7 +860,7 @@ public class HttpSecurityBeanDefinitionParserTests {
                 "<b:bean id='sh' class='" + SavedRequestAwareAuthenticationSuccessHandler.class.getName() +"'/>" +
                 "<b:bean id='fh' class='" + SimpleUrlAuthenticationFailureHandler.class.getName() + "'/>" +
                 AUTH_PROVIDER_XML);
-        UsernamePasswordAuthenticationProcessingFilter apf = (UsernamePasswordAuthenticationProcessingFilter) appContext.getBean(BeanIds.FORM_LOGIN_FILTER);
+        UsernamePasswordAuthenticationProcessingFilter apf = (UsernamePasswordAuthenticationProcessingFilter) getFilter(UsernamePasswordAuthenticationProcessingFilter.class);
         AuthenticationSuccessHandler sh = (AuthenticationSuccessHandler) appContext.getBean("sh");
         AuthenticationFailureHandler fh = (AuthenticationFailureHandler) appContext.getBean("fh");
         assertSame(sh, FieldUtils.getFieldValue(apf, "successHandler"));
@@ -871,7 +870,7 @@ public class HttpSecurityBeanDefinitionParserTests {
     @Test
     public void disablingUrlRewritingThroughTheNamespaceSetsCorrectPropertyOnContextRepo() throws Exception {
         setContext("<http auto-config='true' disable-url-rewriting='true'/>" + AUTH_PROVIDER_XML);
-        Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
+        Object filter = getFilter(SecurityContextPersistenceFilter.class);
         assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.disableUrlRewriting"));
     }
 
@@ -896,4 +895,21 @@ public class HttpSecurityBeanDefinitionParserTests {
 
         return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
     }
+
+    private Object getFilter(Class<? extends Filter> type) throws Exception {
+        List<Filter> filters = getFilters("/any");
+
+        for (Filter f : filters) {
+            if (f.getClass().isAssignableFrom(type)) {
+                return f;
+            }
+        }
+
+        throw new Exception("Filter not found");
+    }
+
+    private RememberMeServices getRememberMeServices() throws Exception {
+        return ((RememberMeProcessingFilter)getFilter(RememberMeProcessingFilter.class)).getRememberMeServices();
+    }
+
 }

+ 10 - 1
config/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java

@@ -1,14 +1,17 @@
 package org.springframework.security.config;
 
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.springframework.context.ApplicationListener;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
+import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
 import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.context.SecurityContextHolder;
 
@@ -35,6 +38,12 @@ public class InterceptMethodsBeanDefinitionDecoratorTests {
         SecurityContextHolder.clearContext();
     }
 
+    @Test
+    public void targetDoesntLoseApplicationListenerInterface() {
+        appContext.publishEvent(new AuthenticationSuccessEvent(new TestingAuthenticationToken("user", "")));
+        assertTrue(target instanceof ApplicationListener);
+    }
+
     @Test
     public void targetShouldAllowUnprotectedMethodInvocationWithNoContext() {
         target.unprotected();

+ 9 - 2
config/src/test/java/org/springframework/security/config/TestBusinessBeanImpl.java

@@ -1,10 +1,13 @@
 package org.springframework.security.config;
 
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+
 /**
- * @author luke
+ * @author Luke Taylor
  * @version $Id$
  */
-public class TestBusinessBeanImpl implements TestBusinessBean {
+public class TestBusinessBeanImpl implements TestBusinessBean, ApplicationListener<ApplicationEvent> {
     public void setInteger(int i) {
     }
 
@@ -24,4 +27,8 @@ public class TestBusinessBeanImpl implements TestBusinessBean {
 
     public void unprotected() {
     }
+
+    public void onApplicationEvent(ApplicationEvent event) {
+        System.out.println(event);
+    }
 }

+ 2 - 0
config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java

@@ -1,5 +1,7 @@
 package org.springframework.security.config.util;
 
+import java.util.Map;
+
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.AbstractXmlApplicationContext;
 import org.springframework.core.io.Resource;

+ 21 - 1
web/src/main/java/org/springframework/security/web/FilterChainProxy.java

@@ -119,11 +119,13 @@ public class FilterChainProxy implements Filter, InitializingBean {
     private Map<Object, List<Filter>> filterChainMap;
     private UrlMatcher matcher = new AntUrlPathMatcher();
     private boolean stripQueryStringFromUrls = true;
+    private FilterChainValidator filterChainValidator = new NullFilterChainValidator();
 
     //~ Methods ========================================================================================================
 
     public void afterPropertiesSet() throws Exception {
         Assert.notNull(uncompiledFilterChainMap, "filterChainMap must be set");
+        filterChainValidator.validate(this);
     }
 
     public void init(FilterConfig filterConfig) throws ServletException {
@@ -316,7 +318,16 @@ public class FilterChainProxy implements Filter, InitializingBean {
         this.stripQueryStringFromUrls = stripQueryStringFromUrls;
     }
 
-    public String toString() {
+    /**
+     * Used (internally) to specify a validation strategy for the filters in each configured chain.
+     *
+     * @param filterChainValidator
+     */
+    public void setFilterChainValidator(FilterChainValidator filterChainValidator) {
+		this.filterChainValidator = filterChainValidator;
+	}
+
+	public String toString() {
         StringBuffer sb = new StringBuffer();
         sb.append("FilterChainProxy[");
         sb.append(" UrlMatcher = ").append(matcher);
@@ -370,4 +381,13 @@ public class FilterChainProxy implements Filter, InitializingBean {
         }
     }
 
+    public interface FilterChainValidator {
+    	void validate(FilterChainProxy filterChainProxy);
+    }
+
+    private class NullFilterChainValidator implements FilterChainValidator {
+		public void validate(FilterChainProxy filterChainProxy) {
+		}
+    }
+
 }

+ 10 - 1
web/src/main/java/org/springframework/security/web/SpringSecurityFilter.java

@@ -24,6 +24,7 @@ import java.io.IOException;
  */
 public abstract class SpringSecurityFilter implements Filter, Ordered {
     protected final Log logger = LogFactory.getLog(this.getClass());
+    private int order;
 
     /**
      * Does nothing. We use IoC container lifecycle services instead.
@@ -46,7 +47,15 @@ public abstract class SpringSecurityFilter implements Filter, Ordered {
 
     protected abstract void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException;
 
-    public String toString() {
+    public final int getOrder() {
+		return order;
+	}
+
+	public void setOrder(int order) {
+		this.order = order;
+	}
+
+	public String toString() {
         return getClass().getName() + "[ order=" + getOrder() + "; ]";
     }
 }

+ 0 - 5
web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java

@@ -30,7 +30,6 @@ import org.springframework.security.authentication.InsufficientAuthenticationExc
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.PortResolver;
 import org.springframework.security.web.PortResolverImpl;
 import org.springframework.security.web.SpringSecurityFilter;
@@ -247,10 +246,6 @@ public class ExceptionTranslationFilter extends SpringSecurityFilter implements
         this.justUseSavedRequestOnGet = justUseSavedRequestOnGet;
     }
 
-    public int getOrder() {
-        return FilterChainOrder.EXCEPTION_TRANSLATION_FILTER;
-    }
-
     /**
      * Default implementation of <code>ThrowableAnalyzer</code> which is capable of also unwrapping
      * <code>ServletException</code>s.

+ 0 - 5
web/src/main/java/org/springframework/security/web/access/channel/ChannelProcessingFilter.java

@@ -28,7 +28,6 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.security.access.ConfigAttribute;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.FilterInvocation;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
@@ -123,8 +122,4 @@ public class ChannelProcessingFilter extends SpringSecurityFilter implements Ini
     public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource) {
         this.securityMetadataSource = filterInvocationSecurityMetadataSource;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.CHANNEL_FILTER;
-    }
 }

+ 1 - 6
web/src/main/java/org/springframework/security/web/access/intercept/FilterSecurityInterceptor.java

@@ -18,7 +18,6 @@ package org.springframework.security.web.access.intercept;
 import org.springframework.security.access.SecurityMetadataSource;
 import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
 import org.springframework.security.access.intercept.InterceptorStatusToken;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.FilterInvocation;
 import org.springframework.core.Ordered;
 
@@ -43,7 +42,7 @@ import javax.servlet.ServletResponse;
  * @author Ben Alex
  * @version $Id$
  */
-public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter, Ordered {
+public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
     //~ Static fields/initializers =====================================================================================
 
     private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
@@ -149,8 +148,4 @@ public class FilterSecurityInterceptor extends AbstractSecurityInterceptor imple
     public void setObserveOncePerRequest(boolean observeOncePerRequest) {
         this.observeOncePerRequest = observeOncePerRequest;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.FILTER_SECURITY_INTERCEPTOR;
-    }
 }

+ 8 - 14
web/src/main/java/org/springframework/security/web/authentication/AnonymousProcessingFilter.java

@@ -16,24 +16,22 @@
 package org.springframework.security.web.authentication;
 
 
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.InitializingBean;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.AuthenticationDetailsSource;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.memory.UserAttribute;
-
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
-import org.springframework.beans.factory.InitializingBean;
 import org.springframework.util.Assert;
 
-import java.io.IOException;
-
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 
 /**
  * Detects if there is no <code>Authentication</code> object in the <code>SecurityContextHolder</code>,  and
@@ -111,10 +109,6 @@ public class AnonymousProcessingFilter  extends SpringSecurityFilter  implements
         }
     }
 
-    public int getOrder() {
-        return FilterChainOrder.ANONYMOUS_FILTER;
-    }
-
     public String getKey() {
         return key;
     }

+ 4 - 10
web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationProcessingFilter.java

@@ -16,19 +16,17 @@
 package org.springframework.security.web.authentication;
 
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
 import org.springframework.security.authentication.AuthenticationServiceException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.util.TextEscapeUtils;
 import org.springframework.util.Assert;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
 
 /**
  * Processes an authentication form. Called <tt>AuthenticationProcessingFilter<tt> in previous versions
@@ -171,10 +169,6 @@ public class UsernamePasswordAuthenticationProcessingFilter extends AbstractAuth
         this.postOnly = postOnly;
     }
 
-    public int getOrder() {
-        return FilterChainOrder.AUTHENTICATION_PROCESSING_FILTER;
-    }
-
     public final String getUsernameParameter() {
         return usernameParameter;
     }

+ 9 - 13
web/src/main/java/org/springframework/security/web/authentication/concurrent/ConcurrentSessionFilter.java

@@ -15,25 +15,25 @@
 
 package org.springframework.security.web.authentication.concurrent;
 
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.springframework.beans.factory.InitializingBean;
 import org.springframework.security.authentication.concurrent.SessionInformation;
 import org.springframework.security.authentication.concurrent.SessionRegistry;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.authentication.logout.LogoutHandler;
 import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
 import org.springframework.security.web.util.UrlUtils;
-import org.springframework.beans.factory.InitializingBean;
 import org.springframework.util.Assert;
 
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-import java.io.IOException;
-
 
 /**
  * Filter required by concurrent session handling package.
@@ -126,8 +126,4 @@ public class ConcurrentSessionFilter extends SpringSecurityFilter implements Ini
         Assert.notNull(handlers);
         this.handlers = handlers;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.CONCURRENT_SESSION_FILTER;
-    }
 }

+ 0 - 5
web/src/main/java/org/springframework/security/web/authentication/logout/LogoutFilter.java

@@ -26,7 +26,6 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.util.UrlUtils;
 import org.springframework.util.Assert;
@@ -142,8 +141,4 @@ public class LogoutFilter extends SpringSecurityFilter {
     protected String getFilterProcessesUrl() {
         return filterProcessesUrl;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.LOGOUT_FILTER;
-    }
 }

+ 16 - 21
web/src/main/java/org/springframework/security/web/authentication/preauth/RequestHeaderPreAuthenticatedProcessingFilter.java

@@ -2,7 +2,6 @@ package org.springframework.security.web.authentication.preauth;
 
 import javax.servlet.http.HttpServletRequest;
 
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.util.Assert;
 
 /**
@@ -10,65 +9,61 @@ import org.springframework.util.Assert;
  * CA Siteminder.
  * <p>
  * As with most pre-authenticated scenarios, it is essential that the external authentication system is set up
- * correctly as this filter does no authentication whatsoever. All the protection is assumed to be provided externally 
- * and if this filter is included inappropriately in a configuration, it would be possible  to assume the 
+ * correctly as this filter does no authentication whatsoever. All the protection is assumed to be provided externally
+ * and if this filter is included inappropriately in a configuration, it would be possible  to assume the
  * identity of a user merely by setting the correct header name. This also means it should not be used in combination
  * with other Spring Security authentication mechanisms such as form login, as this would imply there was a means of
  * bypassing the external system which would be risky.
  * <p>
- * The property <tt>principalRequestHeader</tt> is the name of the request header that contains the username. It 
+ * The property <tt>principalRequestHeader</tt> is the name of the request header that contains the username. It
  * defaults to "SM_USER" for compatibility with Siteminder.
- * 
- * 
+ *
+ *
  * @author Luke Taylor
  * @version $Id$
  * @since 2.0
  */
 public class RequestHeaderPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
-    private String principalRequestHeader = "SM_USER"; 
+    private String principalRequestHeader = "SM_USER";
     private String credentialsRequestHeader;
 
     /**
      * Read and returns the header named by <tt>principalRequestHeader</tt> from the request.
-     * 
-     * @throws PreAuthenticatedCredentialsNotFoundException if the header is missing 
+     *
+     * @throws PreAuthenticatedCredentialsNotFoundException if the header is missing
      */
     protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
         String principal = request.getHeader(principalRequestHeader);
-        
+
         if (principal == null) {
-            throw new PreAuthenticatedCredentialsNotFoundException(principalRequestHeader 
+            throw new PreAuthenticatedCredentialsNotFoundException(principalRequestHeader
                     + " header not found in request.");
         }
 
         return principal;
-    }    
-    
+    }
+
     /**
      * Credentials aren't usually applicable, but if a <tt>credentialsRequestHeader</tt> is set, this
-     * will be read and used as the credentials value. Otherwise a dummy value will be used. 
+     * will be read and used as the credentials value. Otherwise a dummy value will be used.
      */
     protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
         if (credentialsRequestHeader != null) {
             String credentials = request.getHeader(credentialsRequestHeader);
-            
+
             return credentials;
         }
 
         return "N/A";
     }
-    
+
     public void setPrincipalRequestHeader(String principalRequestHeader) {
         Assert.hasText(principalRequestHeader, "principalRequestHeader must not be empty or null");
         this.principalRequestHeader = principalRequestHeader;
     }
 
     public void setCredentialsRequestHeader(String credentialsRequestHeader) {
-        Assert.hasText(credentialsRequestHeader, "credentialsRequestHeader must not be empty or null");        
+        Assert.hasText(credentialsRequestHeader, "credentialsRequestHeader must not be empty or null");
         this.credentialsRequestHeader = credentialsRequestHeader;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.PRE_AUTH_FILTER;
-    }
 }

+ 0 - 4
web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java

@@ -33,8 +33,4 @@ public class J2eePreAuthenticatedProcessingFilter extends AbstractPreAuthenticat
     protected Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest) {
         return "N/A";
     }
-
-    public int getOrder() {
-        return 0;
-    }
 }

+ 0 - 4
web/src/main/java/org/springframework/security/web/authentication/preauth/websphere/WebSpherePreAuthenticatedProcessingFilter.java

@@ -47,8 +47,4 @@ public class WebSpherePreAuthenticatedProcessingFilter extends AbstractPreAuthen
     protected Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest) {
         return "N/A";
     }
-
-    public int getOrder() {
-        return 0;
-    }
 }

+ 3 - 7
web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PreAuthenticatedProcessingFilter.java

@@ -1,10 +1,10 @@
 package org.springframework.security.web.authentication.preauth.x509;
 
-import org.springframework.security.web.FilterChainOrder;
-import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
+import java.security.cert.X509Certificate;
 
 import javax.servlet.http.HttpServletRequest;
-import java.security.cert.X509Certificate;
+
+import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
 
 /**
  * @author Luke Taylor
@@ -48,8 +48,4 @@ public class X509PreAuthenticatedProcessingFilter extends AbstractPreAuthenticat
     public void setPrincipalExtractor(X509PrincipalExtractor principalExtractor) {
         this.principalExtractor = principalExtractor;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.X509_FILTER;
-    }
 }

+ 11 - 15
web/src/main/java/org/springframework/security/web/authentication/rememberme/RememberMeProcessingFilter.java

@@ -15,25 +15,25 @@
 
 package org.springframework.security.web.authentication.rememberme;
 
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.authentication.RememberMeServices;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.context.ApplicationEventPublisherAware;
 import org.springframework.util.Assert;
 
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
 
 /**
  * Detects if there is no <code>Authentication</code> object in the <code>SecurityContext</code>, and populates it
@@ -82,7 +82,7 @@ public class RememberMeProcessingFilter extends SpringSecurityFilter implements
                     // Store to SecurityContextHolder
                     SecurityContextHolder.getContext().setAuthentication(rememberMeAuth);
 
-                    onSuccessfulAuthentication(request, response, rememberMeAuth);                    
+                    onSuccessfulAuthentication(request, response, rememberMeAuth);
 
                     if (logger.isDebugEnabled()) {
                         logger.debug("SecurityContextHolder populated with remember-me token: '"
@@ -150,8 +150,4 @@ public class RememberMeProcessingFilter extends SpringSecurityFilter implements
     public void setRememberMeServices(RememberMeServices rememberMeServices) {
         this.rememberMeServices = rememberMeServices;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.REMEMBER_ME_FILTER;
-    }
 }

+ 0 - 5
web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserProcessingFilter.java

@@ -48,7 +48,6 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsChecker;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
@@ -487,8 +486,4 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
 
         return uri;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.SWITCH_USER_FILTER;
-    }
 }

+ 0 - 5
web/src/main/java/org/springframework/security/web/authentication/ui/DefaultLoginPageGeneratingFilter.java

@@ -10,7 +10,6 @@ import javax.servlet.http.HttpSession;
 
 import org.springframework.beans.BeanWrapperImpl;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter;
@@ -159,10 +158,6 @@ public class DefaultLoginPageGeneratingFilter extends SpringSecurityFilter {
         return sb.toString();
     }
 
-    public int getOrder() {
-        return FilterChainOrder.LOGIN_PAGE_FILTER;
-    }
-
     private boolean isLoginUrlRequest(HttpServletRequest request) {
         String uri = request.getRequestURI();
         int pathParamIndex = uri.indexOf(';');

+ 7 - 12
web/src/main/java/org/springframework/security/web/authentication/www/BasicProcessingFilter.java

@@ -32,7 +32,6 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.authentication.NullRememberMeServices;
 import org.springframework.security.web.authentication.RememberMeServices;
@@ -147,8 +146,8 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
 
                     rememberMeServices.loginFail(request, response);
 
-                    onUnsuccessfulAuthentication(request, response, failed);                    
-                    
+                    onUnsuccessfulAuthentication(request, response, failed);
+
                     if (ignoreFailure) {
                         chain.doFilter(request, response);
                     } else {
@@ -166,8 +165,8 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
                 SecurityContextHolder.getContext().setAuthentication(authResult);
 
                 rememberMeServices.loginSuccess(request, response, authResult);
-                
-                onSuccessfulAuthentication(request, response, authResult);                
+
+                onSuccessfulAuthentication(request, response, authResult);
             }
         }
 
@@ -203,7 +202,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
 
         return false;
     }
-    
+
     protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
             Authentication authResult) throws IOException {
     }
@@ -234,7 +233,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
 
     public void setIgnoreFailure(boolean ignoreFailure) {
         this.ignoreFailure = ignoreFailure;
-    }    
+    }
 
     public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
         Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
@@ -250,12 +249,8 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
         Assert.hasText(credentialsCharset, "credentialsCharset cannot be null or empty");
         this.credentialsCharset = credentialsCharset;
     }
-    
+
     protected String getCredentialsCharset(HttpServletRequest httpRequest) {
         return credentialsCharset;
-    }    
-    
-    public int getOrder() {
-        return FilterChainOrder.BASIC_PROCESSING_FILTER;
     }
 }

+ 0 - 5
web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java

@@ -44,7 +44,6 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.core.userdetails.cache.NullUserCache;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
 import org.springframework.util.Assert;
@@ -355,8 +354,4 @@ public class DigestProcessingFilter extends SpringSecurityFilter implements Filt
     public void setUserDetailsService(UserDetailsService userDetailsService) {
         this.userDetailsService = userDetailsService;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.DIGEST_PROCESSING_FILTER;
-    }
 }

+ 0 - 7
web/src/main/java/org/springframework/security/web/context/HttpSessionContextIntegrationFilter.java

@@ -21,7 +21,6 @@ import org.springframework.beans.factory.InitializingBean;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.context.SecurityContextImpl;
-import org.springframework.security.web.FilterChainOrder;
 
 /**
  * Populates the {@link SecurityContextHolder} with information obtained from
@@ -185,10 +184,6 @@ public class HttpSessionContextIntegrationFilter extends SecurityContextPersiste
       super.setForceEagerSessionCreation(forceEagerSessionCreation);
     }
 
-    public int getOrder() {
-      return FilterChainOrder.HTTP_SESSION_CONTEXT_FILTER;
-    }
-
     //~ Methods ========================================================================================================
 
     public void afterPropertiesSet() throws Exception {
@@ -197,6 +192,4 @@ public class HttpSessionContextIntegrationFilter extends SecurityContextPersiste
                     "If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
         }
     }
-
-
 }

+ 0 - 5
web/src/main/java/org/springframework/security/web/context/SecurityContextPersistenceFilter.java

@@ -10,7 +10,6 @@ import javax.servlet.http.HttpSession;
 
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 
 /**
@@ -96,8 +95,4 @@ public class SecurityContextPersistenceFilter extends SpringSecurityFilter {
     public void setForceEagerSessionCreation(boolean forceEagerSessionCreation) {
         this.forceEagerSessionCreation = forceEagerSessionCreation;
     }
-
-    public int getOrder() {
-        return FilterChainOrder.SECURITY_CONTEXT_FILTER;
-    }
 }

+ 0 - 5
web/src/main/java/org/springframework/security/web/session/SessionFixationProtectionFilter.java

@@ -14,7 +14,6 @@ import org.springframework.security.authentication.concurrent.SessionRegistry;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.SpringSecurityFilter;
 import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
 
@@ -82,10 +81,6 @@ public class SessionFixationProtectionFilter extends SpringSecurityFilter {
         this.sessionRegistry = sessionRegistry;
     }
 
-    public int getOrder() {
-        return FilterChainOrder.SESSION_FIXATION_FILTER;
-    }
-
     /**
      * Called when the a user wasn't authenticated at the start of the request but has been during it
      * <p>

+ 0 - 5
web/src/main/java/org/springframework/security/web/wrapper/SecurityContextHolderAwareRequestFilter.java

@@ -23,7 +23,6 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.PortResolver;
 import org.springframework.security.web.PortResolverImpl;
 import org.springframework.security.web.SpringSecurityFilter;
@@ -88,8 +87,4 @@ public class SecurityContextHolderAwareRequestFilter extends SpringSecurityFilte
 
         chain.doFilter(request, response);
     }
-
-    public int getOrder() {
-        return FilterChainOrder.SERVLET_API_SUPPORT_FILTER;
-    }
 }

+ 0 - 4
web/src/test/java/org/springframework/security/web/authentication/AbstractProcessingFilterTests.java

@@ -553,10 +553,6 @@ public class AbstractProcessingFilterTests extends TestCase {
         public boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
             return super.requiresAuthentication(request, response);
         }
-
-        public int getOrder() {
-            return 0;
-        }
     }
 
     private class MockFilterChain implements FilterChain {

+ 0 - 5
web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java

@@ -16,7 +16,6 @@ import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.SpringSecurityMessageSource;
-import org.springframework.security.web.FilterChainOrder;
 import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
 
 /**
@@ -53,10 +52,6 @@ public class DefaultLoginPageGeneratingFilterTests {
             return null;
         }
 
-        public int getOrder() {
-            return FilterChainOrder.AUTHENTICATION_PROCESSING_FILTER;
-        }
-
         public String getClaimedIdentityFieldName() {
             return "unused";
         }

+ 0 - 4
web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java

@@ -29,10 +29,6 @@ public class AbstractPreAuthenticatedProcessingFilterTests {
             protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
                 return "doesntmatter";
             }
-
-            public int getOrder() {
-                return 0;
-            }
         };
         SecurityContextHolder.getContext().setAuthentication(null);
     }

+ 4 - 7
web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedProcessingFilterTests.java

@@ -1,8 +1,10 @@
 package org.springframework.security.web.authentication.preauth;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -18,7 +20,6 @@ import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.FilterChainOrder;
 
 public class PreAuthenticatedProcessingFilterTests {
     @After
@@ -82,9 +83,5 @@ public class PreAuthenticatedProcessingFilterTests {
         protected Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest) {
             return "testCredentials";
         }
-
-        public int getOrder() {
-            return FilterChainOrder.PRE_AUTH_FILTER;
-        }
     }
 }

+ 4 - 10
web/src/test/java/org/springframework/security/web/context/SecurityContextPersistenceFilterTests.java

@@ -1,6 +1,9 @@
 package org.springframework.security.web.context;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 import java.io.IOException;
 
@@ -22,10 +25,6 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.context.SecurityContextImpl;
-import org.springframework.security.web.FilterChainOrder;
-import org.springframework.security.web.context.HttpRequestResponseHolder;
-import org.springframework.security.web.context.SecurityContextPersistenceFilter;
-import org.springframework.security.web.context.SecurityContextRepository;
 
 public class SecurityContextPersistenceFilterTests {
     Mockery jmock = new JUnit4Mockery();
@@ -131,9 +130,4 @@ public class SecurityContextPersistenceFilterTests {
         filter.doFilter(request, response, chain);
         assertNotNull(request.getSession(false));
     }
-
-    @Test
-    public void filterOrderHasExpectedValue() throws Exception {
-        assertEquals(FilterChainOrder.SECURITY_CONTEXT_FILTER, (new SecurityContextPersistenceFilter()).getOrder());
-    }
 }