2017-02-12

How not to get confused by Spring Boot web security auto-configuration

In my project (Spring Boot + Security + Thymeleaf) I wanted to configure custom web security as is described in "getting started" article on the Spring's official web. I've followed steps in the article and created my custom configuration. But I forgot to add a @EnableWebSecurity annotation. Everything seemed to work fine. Except for Thymeleaf's sec:authorize-url attribute.

What happened?

By not specifying @EnableWebSecurity annotation I didn't disable Spring Boot's default security auto-configuration in SpringBootWebSecurityConfiguration.ApplicationWebSecurityConfigurerAdapter. This creates a security configuration (HttpSecurity object) that disables all access to application for unauthorised users, except for some static resources, and creates a user with a role ROLE_USER and generates some random password for testing purposes.

My configuration also created HttpSecurity object with my own security configuration and my own user repository.

Both HttpSecurity configurations has been passed to WebSecurity which is responsible for creating Spring Security Filter Chain. As you may know a security request goes through this chain until one of the filters "catches" it and process it.

Because my custom configuration bean had a higher priority, it was located "on a higher place" in security filter chain. So all requests has been caught and processed by my filter and not by the filter created by Spring Boot auto-configuration. So far so good.

Problem with two HttpSecurity configurations

When configured, the WebSecurity object holds an instance of FilterSecurityInterceptor. There is only a single filed that can hold the interceptor so no more than one interceptor can be held by WebSecurity object.

The FilterSecurityInterceptor is the crucial part of the Spring Security project. Actually it is its parent class AbstractSecurityInterceptor and its implementations that makes Spring Security breath.

  • FilterSecurityInterceptor intercepts ServletRequests and decides whether a current user has permission to proceed or not. The FilterSecurityInterceptor uses a help of other classes like SecurityContextHolder (holds information about current user, his security context), AccessDecisionManager (evaluates a request against a current security context) and so on.
  • MethodSecurityInterceptor intercepts method calls similarly to FilterSecurityInterceptor. Uses Spring's proxies.
  • AspectJMethodSecurityInterceptor similar to MethodSecurityInterceptor with support of AspectJ.

The FilterSecurityInterceptor is based on information in HttpSecurity. In WebSecurityConfigurerAdapter.init method, the Spring populates WebSecurity by the FilterSecurityInterceptor instance. If more than one FilterSecurityInterceptor are created later overwrites interceptor that is already present in WebSecurity!

Thymeleaf-Spring Security integration gets the FilterSecurityInterceptor from WebSecurity and uses it to evaluate value of sec:authorize-url attribute. Obviously, in this case it gets Spring Boot's default configuration which is not what I wanted.

So, don't forget to disable default configuration by adding @EnableWebSecurity annotation to your security configuration class.