Spring Security - Understanding Spring Security Configuration and components

[Updated: Aug 25, 2017, Created: Jul 16, 2017]

In this tutorial will walk-through the Spring Security configuration and at the same time we will get familiar with different high level security components.

AbstractSecurityWebApplicationInitializer

This class implements Spring's WebApplicationInitializer. That means the concrete implementations of this abstract class will be initialized by SpringServletContainerInitializer given that the spring-web module is on classpath.

The onStartup() method of this class, creates an instance of AnnotationConfigWebApplicationContext which registers client side @Configuration classes with it and bootstraps Spring container.

Following implementation of this class (in its basic form) should be included in the Spring application:

public class AppSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
  public AppSecurityInitializer() {
      super(MyAppConfig.class);
  }
}

Note that, it's not necessary to call super(MyAppConfig.class) from the constructor, if our configuration class is already registered via DispatcherServlet (if it's Spring MVC application)

AbstractSecurityWebApplicationInitializer also registers an instance of DelegatingFilterProxy. The DelegatingFilterProxy#targetBeanName property is set with bean name "springSecurityFilterChain".

The bean named "springSecurityFilterChain" is registered in the configuration imported by @EnableWebSecurity (next section).

@EnableWebSecurity

This annotation is used on our configuration class to important necessary Spring security configuration. Following is the typical usage of the annotation:

@Configuration
@EnableWebSecurity
public class MyAppConfig{
    ....
}

Let's see how the annotation @EnableWebSecurity is defined:

 ..
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
 ....
}

Let's understand what WebSecurityConfiguration and SpringWebMvcImportSelector configuration classes do.

Configurations imported by WebSecurityConfiguration

WebSecurityConfiguration creates a Filter and registers it as a bean by name "springSecurityFilterChain" (same bean name we saw above in section 1). Following is the bean registration snippet.

@Configuration
public class WebSecurityConfiguration implements .... {
    ....
    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = webSecurityConfigurers != null
                && !webSecurityConfigurers.isEmpty();
        if (!hasConfigurers) {
            WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
                    .postProcess(new WebSecurityConfigurerAdapter() {
                    });
            webSecurity.apply(adapter);
        }
        return webSecurity.build();
    }
    ....
}

In above snippet, following things are important to know:

  • The returned Filter is an instance of FilterChainProxy.
  • WebSecurityConfigurerAdapter(s) (injected as 'webSecurityConfigurers' collection in the above class) is extended by our @Configuration class for customization. But if we don't extend it then a default one is used with no methods implemented.
  • webSecurity.build() builds an instance of FilterChainProxy and during building process it eventually calls our WebSecurityConfigurerAdapter implemented methods (in our @Configuration class) allowing for customization. WebSecurity instance (webSecurity), is basically a builder for FilterChainProxy.
  • The returned Filter is also registered as bean by the name: AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME = "springSecurityFilterChain". As seen in section 1 above, DelegatingFilterProxy#targetBeanName is set with the same name.

Now we will understand above components quickly.

FilterChainProxy

As the name suggests this Filter bean is another proxy (within DelegatingFilterProxy) which delegates to a list of Spring-managed filter beans (they also implement Filter interface). Here's a list of those filters in a FilterChainProxy instance (spring security version 4.2.3.RELEASE):

Above screenshot is taken by setting a debug break point in doFilter() method of FilterChainProxy source code. We don't have to understand each filters in above list right now. We will need to understand one of them if we will do some advance configurations or customizations, which we will be exploring in future spring security tutorials.

WebSecurity and HttpSecurity

As we saw in section 3, WebSecurity is nothing but builder to create an instance of FilterChainProxy. Its another sibling-class HttpSecurity allows configuring web based security for specific http requests. We will see in the next section how it is used.

WebSecurityConfigurerAdapter

As we discussed a little about this class in section 3, it is implemented by the client application (usually by @Configuration class) to customize WebSecurity and HttpSecurity. It is an adapter implementation of WebSecurityConfigurer. Its init() method creates an instance of HttpSecurity which is responsible to add all the Filters we saw in the screenshot in section 4. We will be gradually learning what method can be overridden for customizations in this series of tutorials.

SpringWebMvcImportSelector

EnableWebSecurity also imports SpringWebMvcImportSelector (as seen in section 2), which conditionally imports WebMvcSecurityConfiguration when the DispatcherServlet is present on the classpath.

This configuration class registers RequestDataValueProcessor bean which is used to provide data integrity, e.g. by protected against CSRF attacks.

@EnableGlobalAuthentication

The annotation @EnableWebSecurity (section 2) is also meta-annotated with @EnableGlobalAuthentication which imports AuthenticationConfiguration. This configuration register beans for authentication process.

With this import we can configure a global instance of AuthenticationManagerBuilder. For example:

@Configuration
@EnableWebSecurity
public class MyAppConfig extends WebSecurityConfigurerAdapter {

  @Override
  public void configure(AuthenticationManagerBuilder builder)
          throws Exception {
      builder.inMemoryAuthentication()
             .withUser("joe")
             .password("123")
             .roles("ADMIN");
  }
  ........
}

See Also