Filters

Spring Security uses many filters, as referred to throughout the remainder of this reference guide. If you are using namespace configuration, then the you don't usually have to declare the filter beans explicitly. There may be times when you want full control over the security filter chain, either because you are using features which aren't supported in the namespace, or you are using your own customized versions of classes.

In this case, you have a choice in how these filters are added to your web application, in that you can use either Spring's DelegatingFilterProxy or FilterChainProxy. We'll look at both below.

When using DelegatingFilterProxy, you will see something like this in the web.xml file:

    <filter>
        <filter-name>myFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
      <filter-name>myFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
        

Notice that the filter is actually a DelegatingFilterProxy, and not the filter that will actually implement the logic of the filter. What DelegatingFilterProxy does is delegate the Filter's methods through to a bean which is obtained from the Spring application context. This enables the bean to benefit from the Spring web application context lifecycle support and configuration flexibility. The bean must implement javax.servlet.Filter and it must have the same name as that in the filter-name element.

There is a lifecycle issue to consider when hosting Filters in an IoC container instead of a servlet container. Specifically, which container should be responsible for calling the Filter's "startup" and "shutdown" methods? It is noted that the order of initialization and destruction of a Filter can vary by servlet container, and this can cause problems if one Filter depends on configuration settings established by an earlier initialized Filter. The Spring IoC container on the other hand has more comprehensive lifecycle/IoC interfaces (such as InitializingBean, DisposableBean, BeanNameAware, ApplicationContextAware and many others) as well as a well-understood interface contract, predictable method invocation ordering, autowiring support, and even options to avoid implementing Spring interfaces (eg the destroy-method attribute in Spring XML). For this reason we recommend the use of Spring lifecycle services instead of servlet container lifecycle services wherever possible. Read the Javadoc for DelegatingFilterProxy for more information

Rather than using DelegatingFilterProxy, we strongly recommend that you use FilterChainProxy instead. Whilst DelegatingFilterProxy is a very useful class, the problem is that the number of lines of code required for <filter> and <filter-mapping> entries in web.xml explodes when using more than a few filters. To overcome this issue, Spring Security provides a FilterChainProxy class. It is wired using a DelegatingFilterProxy (just like in the example above), but the target class is org.springframework.security.util.FilterChainProxy. The filter chain is then declared in the application context, using code such as this:

<bean id="filterChainProxy" class="org.springframework.security.util.FilterChainProxy">
  <sec:filter-chain-map path-type="ant">
     <sec:filter-chain pattern="/webServices/**" 
         filters="httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor"/>
     <sec:filter-chain pattern="/**" 
         filters="httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor"/>
  </sec:filter-chain-map>
</bean>
         
    

You may notice similarities with the way FilterSecurityInterceptor is declared. Both regular expressions and Ant Paths are supported, and the most specific URIs appear first. At runtime the FilterChainProxy will locate the first URI pattern that matches the current web request and the list of filter beans specified by the filters attribute will be applied to that request. The filters will be invoked in the order they are defined, so you have complete control over the filter chain which is applied to a particular URL.

You may have noticed we have declared two HttpSessionContextIntegrationFilters in the filter chain (ASC is short for allowSessionCreation, a property of HttpSessionContextIntegrationFilter). As web services will never present a jsessionid on future requests, creating HttpSessions for such user agents would be wasteful. If you had a high-volume application which required maximum scalability, we recommend you use the approach shown above. For smaller applications, using a single HttpSessionContextIntegrationFilter (with its default allowSessionCreation as true) would likely be sufficient.

In relation to lifecycle issues, the FilterChainProxy will always delegate init(FilterConfig) and destroy() methods through to the underlaying Filters if such methods are called against FilterChainProxy itself. In this case, FilterChainProxy guarantees to only initialize and destroy each Filter once, irrespective of how many times it is declared by the FilterInvocationDefinitionSource. You control the overall choice as to whether these methods are called or not via the targetFilterLifecycle initialization parameter of the DelegatingFilterProxy that proxies DelegatingFilterProxy. As discussed above, by default any servlet container lifecycle invocations are not delegated through to DelegatingFilterProxy.

You can use the attribute filters = "none" in the same way that you do when using namespace configuration to build the FilterChainProxy. This will omit the request pattern from the security filter chain entirely. Note that anything matching this path will then have no authentication or authorization services applied and will be freely accessible.

The order that filters are defined in web.xml is very important. Irrespective of which filters you are actually using, the order of the <filter-mapping>s should be as follows:

  1. ChannelProcessingFilter, because it might need to redirect to a different protocol

  2. ConcurrentSessionFilter, because it doesn't use any SecurityContextHolder functionality but needs to update the SessionRegistry to reflect ongoing requests from the principal

  3. HttpSessionContextIntegrationFilter, so a SecurityContext can be setup in the SecurityContextHolder at the beginning of a web request, and any changes to the SecurityContext can be copied to the HttpSession when the web request ends (ready for use with the next web request)

  4. Authentication processing mechanisms - AuthenticationProcessingFilter, CasProcessingFilter, BasicProcessingFilter, HttpRequestIntegrationFilter, JbossIntegrationFilter etc - so that the SecurityContextHolder can be modified to contain a valid Authentication request token

  5. The SecurityContextHolderAwareRequestFilter, if you are using it to install a Spring Security aware HttpServletRequestWrapper into your servlet container

  6. RememberMeProcessingFilter, so that if no earlier authentication processing mechanism updated the SecurityContextHolder, and the request presents a cookie that enables remember-me services to take place, a suitable remembered Authentication object will be put there

  7. AnonymousProcessingFilter, so that if no earlier authentication processing mechanism updated the SecurityContextHolder, an anonymous Authentication object will be put there

  8. ExceptionTranslationFilter, to catch any Spring Security exceptions so that either an HTTP error response can be returned or an appropriate AuthenticationEntryPoint can be launched

  9. FilterSecurityInterceptor, to protect web URIs

All of the above filters use DelegatingFilterProxy or FilterChainProxy. It is recommended that a single DelegatingFilterProxy proxy through to a single FilterChainProxy for each application, with that FilterChainProxy defining all of Spring Security filters.

If you're using SiteMesh, ensure Spring Security filters execute before the SiteMesh filters are called. This enables the SecurityContextHolder to be populated in time for use by SiteMesh decorators