Spring Security — The Security Filter Chain
In this article, we are going to learn about the Spring Scerity Filter Chain. Underneath of code of Spring, Security is going to be using a security chain. Spring Security’s web infrastructure is based entirely on standard servlet filters. It doesn’t use servlets or any other servlet-based frameworks (such as Spring MVC) internally, so it has no strong links to any particular web technology. It deals in HttpServletRequest
s and HttpServletResponse
s and doesn't care whether the requests come from a browser, a web service client, an HttpInvoker
or an AJAX application.
Spring Security maintains a filter chain internally where each of the filters has a particular responsibility and filters are added or removed from the configuration depending on which services are required. The ordering of the filters is important as there are dependencies between them. If you have been using namespace configuration, then the filters are automatically configured for you and you don’t have to define any Spring beans explicitly but 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 customized versions of classes.
First of all, look at this diagram given below we first send an HTTP request to our server what is going to happen is it will go through a set of Security Filters. They are just chains of filters that you use to do or perform certain actions on Spring Security.
It is almost like a Middleware and it has the name of FilterChain because of the chain of responsibility pattern. The HTTP request going to pass through it and the response also passes through the filters based on the way that it is going. Then finally the request is routed to the controllers by this servlet. Servlet takes the HTTP request and does some kind of action to it depending on the Java code.
The name chain
suggests that you have a sequence of filters, with each filter doing some processing and then passing on to the next in sequence, so each object has a chain
member to point to the next filter in the sequence, which gets called after the filter has performed its processing. The last in the sequence will then probably have null
as the chain
value or it knows on its own that it is the last one in the sequence.
This process internally invokes doFilter
of the next filter in the filter chain, and, when the chain is over, it invokes the target servlet. All filters are chained (in the order of their definition in web.xml). The chain.doFilter()
proceeds to the next element in the chain. The last element of the chain is the target resource/servlet.
What’s happening here is Spring Scerity provides a deligating Fiter Proxy and we called it Bean Filter. It allows us to just look at the request, so the servlet is going to get a request and response. Then these filters will be applied to those requests. This is a very important concept of architecture. These filters get applied and you can have different security filter chains that allow you to have one endpoint that’s ominous and another one that requires authentication. Some could just say, “Okay, well just using a remember me cookie is just fine.” So it gives you a lot of flexibility in your architecture as to how you work with Spring Security. So Spring Security has been around for a long time. It's very mature, so you can do a lot of capabilities with it as to how you configure it. So the key takeaway I want you to have from this article is that Spring Security is setting up a filter chain and there os multiple filter chains based on your configurations. Those filters get applied to the request and response ahead of or behind the Soring Security Dispatcher Servlet.
Now, let’s look at the core components that take part in the filter chain:
- DelegatingFilterProxy It is a servlet filter provided by Spring that acts as a bridge between the Servlet container and the Spring Application Context. The
DelegatingFilterProxy
class is responsible for wiring any class that implementsjavax.servlet.Filter
into the filter chain. - FilterChainProxy Spring security internally creates a
FilterChainProxy
bean namedspringSecurityFilterChain
wrapped inDelegatingFilterProxy
. TheFilterChainProxy
is a filter that chains multiple filters based on the security configuration. Thus, theDelegatingFilterProxy
delegates request theFilterChainProxy
which determines the filters to be invoked. - SecurityFilterChain: The security filters in the
SecurityFilterChain
are beans registered withFilterChainProxy
. An application can have multipleSecurityFilterChain
.FilterChainProxy
uses theRequestMatcher
interface onHttpServletRequest
to determine whichSecurityFilterChain
needs to be called
Let’s implement this logic to get a perfect idea of what is a Security Filter Chain. Now create a folder called security in your project and create a class called SecurityConfig.
This is the class we use to add our filter chain. Now add the annotation @Configuration to let the spring boot this is a configuration class and this needs to be added to the Bean Context. In the previous versions, we have used WebSecurityConfigurerAdapter to implement this and now WebSecurityConfigurerAdapter is deprecated. In Spring Security 5.7.0-M2 they deprecated the WebSecurityConfigurerAdapter
, as they encourage users to move towards a component-based security configuration. To assist with the transition to this new style of configuration, they have compiled a list of common use cases and suggested alternatives going forward. In the examples below we follow best practices by using the Spring Security lambda DSL and the method HttpSecurity#authorizeHttpRequests
to define our authorization rules. If you are new to the lambda DSL you can read about it in this blog post. If you would like to learn more about why we chose to use HttpSecurity#authorizeHttpRequests
you can check out the reference documentation.
Configuring HttpSecurity
In Spring Security 5.4 they introduced the ability to configure HttpSecurity
by creating a SecurityFilterChain
bean.
Below is an example configuration using the WebSecurityConfigurerAdapter
that secures all endpoints with HTTP Basic:
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
Going forward, the recommended way of doing this is to register a SecurityFilterChain
bean:
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
return http.build();
}
}
You can add any security chain expressions here like.
- org.springframework.security.web.csrf.CsrfFilter : This filter applies for CSRF protection by default to all REST endpoints.
- org.springframework.security.web.authentication.logout.LogoutFilter : This filter gets called when the user logs out of the application. The default registered instances
LogoutHandler
are called that are responsible for invalidating the session and clearing theSecurityContext
. Next, the default implementation ofLogoutSuccessHandler
redirects the user to a new page (/login?logout
). - org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter : Validates the username and password for the URL (
/login
) with the default credentials provided at startup. - org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter : Generates the default login page html at
/login
- org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter : Generates the default logout page html at
/login?logout
- org.springframework.security.web.authentication.www.BasicAuthenticationFilter : This filter is responsible for processing any request that has an HTTP request header of Authorization, Basic Authentication scheme, Base64 encoded username-password. On successful authentication, the
Authentication
object will be placed in theSecurityContextHolder
. - org.springframework.security.web.authentication.AnonymousAuthenticationFilter : If no
Authentication
the object is found in theSecurityContext
, it creates one with the principalanonymousUser
and roleROLE_ANONYMOUS
. - org.springframework.security.web.access.ExceptionTranslationFilter : Handles
AccessDeniedException
andAuthenticationException
thrown within the filter chain. ForAuthenticationException
instance ofAuthenticationEntryPoint
are required to handle responses. For, this filter will delegate toAccessDeniedHandler
whose default implementation isAccessDeniedHandlerImpl
. - org.springframework.security.web.access.intercept.FilterSecurityInterceptor : This filter is responsible for authorizing every request that passes through the filter chain before the request hits the controller.
Additional Notes on Spring Security Chain
- The default fallback filter chain in a Spring Boot application has a request matcher
/**
, meaning it will apply to all requests. - The default filter chain has a predefined
@Order
SecurityProperties.BASIC_AUTH_ORDER. - We can exclude this complete filter chain by setting security.basic.enabled=false.
- We can define the ordering of multiple filter chains. For instance, to call a custom filter chain before the default one, we need to set a lower
@Order
. Example@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
. - We can plugin a custom filter within the existing filter chain (to be called at all times or for specific URL patterns) using the
FilterRegistrationBean
or by extendingOncePerRequestFilter
. - For the defined custom filter, if no @Order is specified, it is the last in the security chain. (Has the default order
LOWEST_PRECEDENCE
.) - We can also use methods
addFilterAfter()
,addFilterAt()
andaddFilterBefore()
to have more control over the ordering of our defined custom filter.
In this article, we looked at the basic concept that applies to spring security. As we have seen, spring provides a lot of flexibility and allows us to customize security for complex applications. See you in another article.
Thank You!