Spring Security - Filter Chain

Created: 2020-07-03 | 5 min


After playing with few basic configurations of Spring Security, I noticed there is something important to understand before moving to check other features in the framework, which is its Filter Chain. This time I'll take a look at how Spring Security acts on the requests coming from the client, which involves a set of Filters, each of them with a very specific goal.

Note: This is not a tutorial, this is just some notes of what I understand (as of today) about Spring Security and its Filter Chain.

#Introduction

The most complete explanation I could find regarding how the Security Filter Chain is built in the entire architecture is in the official documentation in here: https://docs.spring.io/spring-security/site/docs/5.3.2.RELEASE/reference/html5/#servlet-architecture

I'll write down what I interpret from what I already interacted with the module in combination with what the documentation is trying to explain.

#Main Components

There are five pieces (in the documentation I pointed out in the previous section) that I want to visit here. They are:

#Filters

First of all, "Filters" (in the Servlet's world) came from the Java Specification Requests (JSR) #53. Look at this:

Filters are some pieces of code that do something before or after a Request gets processed by a Servlet. The web container (e.g. Tomcat) will know that.

Filters have multiple purposes, it is not only restricted to be for Security mechanisms. They are meant to read or write (any logic in general) with the Request. For example: one filter can print some audit logs, another one can add some headers to the request, and so on.

In the Spring Security's world, we have a set of Filters strategically ordered to prevent subsequent filters or the controller itself being called if they find the request not matching with the security configuration.

The most straightforward example may be, imagine a user entering a wrong password, there is one filter dedicated to verify whether the password is correct or not. If not, then the at some point of the Filter Chain, one of the Filters will reject the request and respond with a 401 status code to the client.

#DelegatingFilterProxy

DelegatingFilterProxy is a class registered as Standard Filter in the Container, but the container doesn't know anything about Spring Beans at this point. DelegatingFilterProxy is the support to establish communication between the Standard Filters and the Spring Application Context.

Notice that I didn't mention anything about Spring Security yet, that's because DelegatingFilterProxy is a class located in Spring Web and not Spring Security. Which is interesting because from there I interpret that this proxy can be used by something else not necessarily related to Spring Security.

#FilterChainProxy

FilterChainProxy is a filter located in Spring Security module.

It takes a list of filters and creates something called VirtualFilterChain (a private class within FilterChainProxy), which is going to take the list of the Security Filters and start the chain.

I want to point this out that seems to be pretty useful, quoting Spring Security docs:

First, it provides a starting point for all of Spring Security’s Servlet support. For that reason, if you are attempting to troubleshoot Spring Security’s Servlet support, adding a debug point in FilterChainProxy is a great place to start.

#SecurityFilterChain

SecurityFilterChain contains the list of all the filters involved in Spring Security. This interface expose a method List<Filter> getFilters() that returns all the filters such as the UsernamePasswordAuthenticationFilter or LogoutFilter.

In Spring Security, one or more SecurityFilterChains can be registered in the FilterChainProxy.

The following picture illustrates all the components I tried to explain so far:

SecurityFilterChain, by Spring Security Docs

#Security Filters

Finally, at the end of all this hierarchy (Standard Filter > DelegatingFilterProxy > FilterChainProxy > SecurityFilterChain), there is list of possible security filters that we can configure in our applications. I'll just mention the ones that I kind of interated so far:

In fact, everytime your Spring Boot application starts up, the list of filters are printed in the logs by default (in their corresponding order of execution). Example:

// Raw logs at startup time
// List of filters are printed there

2020-07-02 21:34:55.896  INFO 51095 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@7fe82967, org.springframework.security.web.context.SecurityContextPersistenceFilter@9596ce8, org.springframework.security.web.header.HeaderWriterFilter@26f46fa6, org.springframework.security.web.csrf.CsrfFilter@558756be, org.springframework.security.web.authentication.logout.LogoutFilter@80bfdc6, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@6edcad64, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@75ae4a1f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@476fe690, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@50850539, org.springframework.security.web.session.SessionManagementFilter@227a47, org.springframework.security.web.access.ExceptionTranslationFilter@3968bc60, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@2924f1d8]

// And this is the list of filters in a more readable way:

[
    1. org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5fa23c
    2. org.springframework.security.web.context.SecurityContextPersistenceFilter@73c9e8e8
    3. org.springframework.security.web.header.HeaderWriterFilter@59f93db8
    4. org.springframework.security.web.csrf.CsrfFilter@13d9261f
    5. org.springframework.security.web.authentication.logout.LogoutFilter@b606cb6
    6. org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@2a3194c6
    7. org.springframework.security.web.savedrequest.RequestCacheAwareFilter@de8039f
    8. org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@4b790d86
    9. org.springframework.security.web.authentication.AnonymousAuthenticationFilter@558756be
    10. org.springframework.security.web.session.SessionManagementFilter@1aabf50d
    11. org.springframework.security.web.access.ExceptionTranslationFilter@2e8a1ab4
    12. org.springframework.security.web.access.intercept.FilterSecurityInterceptor@51c959a4
]

So, any requests coming from the client will pass through the filter chain and in that order.

#Final thoughts

#Refs