Security filter chain in Spring Security

The first article from this category covers the subject of Spring Security ACL features. But we can still use Spring Security without the roles management. And to do it correctly, we should be familiar with a concept calling security chain.

In this article we'll cover a very important topic of Spring Security project: security filter chain. At the begin we'll discover how Spring Security handles authentication and authorization requests. After that we'll start to talking about available security filters.

Authentication and authorization handling in Spring Security

Authentication and authorization process in Spring Security project are handled with filters technology. javax.servlet.Filter objects are standard part of Java Servlet API. They're objects which can be invoked on every request (independently on requested resource's type: static or dynamic). They all have 3 methods:
- init(FilterConfig config): called by servlet container after the filter is instantiated. This method is called only once and can be used, for example, to configure filter object with specified parameters. These parameters are retrieved from FilterConfig instance.
- doFilter(ServletRequest request, ServletResponse response, FilterChain chain): this is working method which makes some filtering operations on request and response objects. It's here for, for example, examine ServletRequest object and check if demanded resource is allowed to user making the request.
- destroy(): as the name indicates, this method is called when filter is taken out of service.

Filter are defined in web.xml descriptor file within tag. Filters can be mapped to specific URLs thanks to tag. Spring Security exploits a possibility to chain filters. Thanks to that, web.xml remains readable, even when we implement a lot of security filters. Object responsible for chaining filters is org.springframework.security.web.FilterChainProxy. With it, we can simply define one filter in web.xml, as in below sample:

<filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

It may look strangely that we are supposed to use FilterChainProxy but we are defining DelegatingFilterProxy in web.xml. But is not. Let's take a look on DelegatingFilterProxy class to see what it does. This object comes from Spring web project and helps to dispatch request catched by filter mapping to appropriate Spring bean. This strategy allows to take full advantage of Spring environment because filters invoked by servlet containers are Spring-managed beans and not detached objects, difficult to plug to Spring's application context. The name of bean to invoke is defined in targetBeanName parameter. If this parameter is absent, DelegatingFilterProxy uses filter name to find appropriate bean. As you can see in our example, bean used to execute security requests will be called springSecurityFilterChain and it corresponds to already mentioned FilterChainProxy.

One mystery is solved. Now we can focus on another one, FilterChainProxy. This class extends org.springframework.web.filter.GenericFilterBean. Through this inheritance, it also implements javax.servlet.Filter interface, so it can be treated as standard filter with doFilter method implemented. Content of method used to filter the requests looks like:

show doFilter implementation

As you can see, it filters against FirewalledRequest which is a secured version of ServletRequest object. This secured version allows to deal with normalized requests objects. Normalization process consists on translate received path on the path that will always be able to match security patterns. For example, it can resolve multiple forward slashes (//) into one slash and do not break security strategy with incorrectly formatted request. After the normalization, FilterChainProxy gets a list of filters, wrapps them into inner class VirtualFilterChain and executes through it. How does FilterChainProxy know about filters to call ? It's able to resolve this situation thanks to its constructors:

private List<SecurityFilterChain> filterChains;

public FilterChainProxy(SecurityFilterChain chain) {
  this(Arrays.asList(chain));
}

public FilterChainProxy(List<SecurityFilterChain> filterChains) {
  this.filterChains = filterChains;
}
We can specify these parameters with a simple bean definition:
<-- bean definition here-->
  <constructor-arg>
    <list>
      <spring-security:filter-chain pattern="/secure/**", filters="filter1, filter2" />
      <spring-security:filter-chain pattern="/no-secure/**", filters="filter3" />
    </list>
  </constructor-arg>
<-- end of bean definition here -->

If you compare doFilter with bean's XML definition, you will see that filters are executed in the order of definition (ie. filter1 before filter2). However, the order of definition is important and some filters shouldn't be executed before or after others, ie:

  1. ChannelProcessingFilter: to redirect the request to another protocol
  2. SecurityContextPersistenceFilter: to allow copy security details to HttpSession
  3. ConcurrentSessionFilter: because it uses functionalities of objects manipulated in previous step (SecurityContextHolder) and updates session informations
  4. UsernamePasswordAuthenticationFilter, CasAuthenticationFilter, BasicAuthenticationFilter and other authentication mechanisms: to update security context created at the 2nd step with details of authenticated user.
  5. SecurityContextHolderAwareRequestFilter: if we want to install HttpServletRequestWrapper into servlet container
  6. JaasApiIntegrationFilter: executed when JaasAuthenticationToken is present in SecurityContextHolder.
  7. RememberMeAuthenticationFilter: if authentication wasn't processed and a remember-me cookie is present in the request.
  8. AnonymousAuthenticationFilter: when user is not authenticated, neither by authentication mechanism nor by remember-me cookie.
  9. ExceptionTranslationFilter: to catch all Spring Security exceptions.
  10. FilterSecurityInterceptor: to handle ACL and raise exceptions when access is denied for given URL.

Spring Security filters

We already know the main purposes of majority of filters. But we haven't implemented them yet. We'll do this in this article.

In this article we discovered one of key concepts of Spring Security - filter security chain. At the first part we explained this idea more globally by reminding the definition of filters. After that, we focused more on Spring Security filters and presented some of important filters of this project.

If you liked it, you should read:

The comments are moderated. I publish them when I answer, so don't worry if you don't see yours immediately :)

📚 Newsletter Get new posts, recommended reading and other exclusive information every week. SPAM free - no 3rd party ads, only the information about waitingforcode!