Add Spring Security Custom Filter

author-image  By Dhiraj, 01 January, 2019   3K
spring-security

While dealing with the security of a web application, every application tends to provide their custom authentication process. Based on the level of security required, the authentication process varies. Any application on the web is required to have an encrypted password flow from a client to a server. Sometimes authentication exception response needs to be altered. But if we are using spring security to secure our app then we have some pre-defined ways of handling these things. But good thing is that spring security provides flexible implementation to extend and customize this behavior as per our requirement by adding custom filters in the spring security filter chain in the order we want.

In this tutorial, we will discuss how can we create a spring security custom filter and plug it in the filter chain to be invoked by FilterChainProxy in the order we want. But before adding any security filter in the chain, it makes sense to first know about the different exisiting filters. Once we get a brief idea of it then it will be simpler and easier to design our custom filter and plug it in proper order.

There are 2 main aspects while we discuss about security of an application i.e. Authentication and Authorization. Spring security provides both the aspects of it. While discussing Authorization, Spring Boot Security provides method level security, as well as URL level security and that, covers almost every kind of applications. But the authentication process varies from app to app. For example, in some cases, Http Basic Authentication is enough and sometimes Form-based Authentication. Even in form-based authentication, sometimes a client is required to send AES encrypted password and if that is the case our authentication process changes. But we can deal with those variations by adding our custom Filter in the filter chain.

We have discussed a lot about spring security authorization in my previous articles and you can view them all here - Spring Security Tutorials

Spring Security Filters

To know about the different spring security filters, let us first create a very simple spring boot security application with below dependencies and simply run it as a spring boot app.

pom.xml
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

After running the application, we find the below INFO logs in the console.

2019-01-01 22:06:00.363  INFO 708 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@7d44a19, org.springframework.security.web.context.SecurityContextPersistenceFilter@5af8bb51, org.springframework.security.web.header.HeaderWriterFilter@2aff9dff, org.springframework.security.web.csrf.CsrfFilter@59072e9d, org.springframework.security.web.authentication.logout.LogoutFilter@a098d76, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@3d4e405e, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@32e54a9d, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@1fb2d5e, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@4e1a46fb, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2e66bc32, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@712cfb63, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1716e8c5, org.springframework.security.web.session.SessionManagementFilter@1aad0b1, org.springframework.security.web.access.ExceptionTranslationFilter@6c3659be, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@7640a5b1]

By default, spring has enabled BasicAuthenticationFilter and this is removed from the chain once we add formLogin() in the http.

@Override
protected void configure(HttpSecurity http) throws Exception {
	http.csrf().and().authorizeRequests()
			.antMatchers("/dashboard").hasRole("USER").and().formLogin();
}

But the point to notice here is all the Filters in the logs are the filters that are by default added in the FilterChainProxy in a spring security app in the given order and of course, DelegatingFilterProxy invokes the FilterChainProxy class which in turn invokes the chain of filters that are defined above. The functionality of each filter is beyond the scope of this article but we will definitely discuss about these in our next article.

Now, once we got to know the order of filters, it will be easier for us to add our custom filter at the order we want. In this example, we will take a look into how we can add our custom filter before UsernamePasswordAuthenticationFilter as we want our authentication process to be based on the username and encrypted password.

Spring Security Configuration to Add Custom Filter

The custom filters are configured inside configure(HttpSecurity http) of WebSecurityConfigurerAdapter. Below is the snippet to add a CustomLoginFilter before UsernamePasswordAuthenticationFilter.

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().and().authorizeRequests()
                .antMatchers("/welcome").hasRole("USER").and()
                .addFilterBefore(new CustomLoginFilter("/login-user", authenticationManager()), UsernamePasswordAuthenticationFilter.class);
    }

Below is our CustomLoginFilter that extends AbstractAuthenticationProcessingFilter and overrides it's abstract method attemptAuthentication(). In the implementation, you can have your custom logic to validate user credentilas.

package com.devglan.springsecuritydemo;

import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CustomLoginFilter extends AbstractAuthenticationProcessingFilter {

    public CustomLoginFilter(String url, AuthenticationManager authenticationManager) {
        super(new AntPathRequestMatcher(url, HttpMethod.POST.name()));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        return null;
    }
}

If you look into HttpSecurity class, you can find below methods to add your custom filter.

  1. public HttpSecurity addFilterAfter(Filter filter, Class afterFilter)
  2. public HttpSecurity addFilterBefore(Filter filter, Class beforeFilter)
  3. public HttpSecurity addFilter(Filter filter)
  4. public HttpSecurity addFilterAt(Filter filter, Class atFilter)

Conclusion

In this article, we discussed about adding custom filter in spring security filter chain and demonstrated an example of adding Custom Login FIlter before UsernamePasswordAuthenticationFilter class.

About The Author

author-image

Further Reading on Spring Security

1. Spring Oauth2 Role Based Authorization

2. Spring Boot Oauth2 Angular

3. Jwt Role Based Authorization

4. Angular Jwt Authentication

5. Spring Boot Jwt Auth

6. Spring Security Ldap Authentication

7. Spring Boot Security Oauth2 Example