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
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.
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 one field that can hold the interceptor so no more than one interceptor can be held by
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.
ServletRequests and decides whether a current user has permission to proceed or not. The
FilterSecurityInterceptoruses 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.
MethodSecurityInterceptorintercepts method calls similarly to
FilterSecurityInterceptor. Uses Spring's proxies.
MethodSecurityInterceptorwith support of
FilterSecurityInterceptor is based on information 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
Thymeleaf-Spring Security integration gets the
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.
Update 2020: Changes in Spring Boot 2.x
Even though ths article aims at Spring Boot 1.5, in the latest versions of Spring Security there has been some changes worth mentioning.
@EnableWebSecurityannotation won't disable the security auto-configurations.
In Spring Boot 2.x, the custom implementations of the
WebSecurityConfigurationAdapterabstract class or the
SecurityFilterChaininterface will disable default web security auto-configuration.
Spring Boot 2.4.0 also introduced the
@ConditionalOnDefaultWebSecuritywhich is applied to bunch of security auto-configurations, simplifying previous auto-configuration conditionals. This annotation makes sure security auto-configurations are disabled. You can check its usage to see which configurations are being affected.
@EnableWebSecurityannotation will be added automatically if it is missing in your configuration.
The annotation imports a few configurers, which makes sure your security is properly configured.
Spring Boot introduced
WebSecurityEnablerConfigurationwhich will add the annotation if it is present on a classpath, and it hasn't been configured yet.
Changes in Spring Boot 2.x makes sure that problem described in this article won't happen anymore. Due to that the security configuration is a bit more straightforward and easier to do.