Authentication

Authentication represents the token of an authentication request.

By default, these authentication token implementation types:

  • AnonymousAuthenticationToken
  • UsernamePasswordAuthenticationToken
  • PreAuthenticatedAuthenticationToken
  • RememberMeAuthenticationToken
  • JaasAuthenticationToken
  • RunAsUserToken

Authentication provider

A provider to handle the authentication when authentication token type is matched:

Authentication providers Supported authentication
AnonymousAuthenticationProvider AnonymousAuthenticationToken
AbstractUserDetailsAuthenticationProvider DaoAuthenticationProvider RemoteAuthenticationProvider UsernamePasswordAuthenticationToken
AbstractJaasAuthenticationProvider DefaultJaasAuthenticationProvider JaasAuthenticationProvider JaasAuthenticationToken
PreAuthenticatedAuthenticationProvider PreAuthenticatedAuthenticationToken
RememberMeAuthenticationProvider RememberMeAuthenticationToken
RunAsImplAuthenticationProvider RunAsUserToken

Here, AbstractUserDetailsAuthenticationProvider and its subclasses expect a UserDetailsService provided by us. RememberMeAuthenticationProvider expects a RememberMeServices provided by us.

SecurityFilterChain and FilterChainProxy

A filter chain is a list of filters with the order to perform the filtering task. They are defined as Spring FilterBean.

And the FilterChainProxy can include multiple filter chains,

FilterChainProxy is a servlet filter to perform the filter chains.

Irrespective of which filters you are actually using, the order should be as follows:

  • ChannelProcessingFilter, because it might need to redirect to a different protocol
  • SecurityContextPersistenceFilter, so a SecurityContext can be set up in the SecurityContextHolder at the beginning of a web request, and any changes to the SecurityContext can be copied to the HttpSession when the web request ends (ready for use with the next web request)
  • ConcurrentSessionFilter, because it uses the SecurityContextHolder functionality and needs to update the SessionRegistry to reflect ongoing requests from the principal
  • Authentication processing mechanisms - UsernamePasswordAuthenticationFilter, CasAuthenticationFilter, BasicAuthenticationFilter etc - so that the SecurityContextHolder can be modified to contain a valid Authentication request token
  • The SecurityContextHolderAwareRequestFilter, if you are using it to install a Spring Security aware HttpServletRequestWrapper into your servlet container
  • The JaasApiIntegrationFilter, if a JaasAuthenticationToken is in the SecurityContextHolder this will process the FilterChain as the Subject in the JaasAuthenticationToken
  • RememberMeAuthenticationFilter, so that if no earlier authentication processing mechanism updated the SecurityContextHolder, and the request presents a cookie that enables remember-me services to take place, a suitable remembered Authentication object will be put there
  • AnonymousAuthenticationFilter, so that if no earlier authentication processing mechanism updated the SecurityContextHolder, an anonymous Authentication object will be put there
  • ExceptionTranslationFilter, to catch any Spring Security exceptions so that either an HTTP error response can be returned or an appropriate AuthenticationEntryPoint can be launched
  • FilterSecurityInterceptor, to protect web URIs and raise exceptions when access is denied

The below is how a configurer in DSL configures relevant filters.

Configurer in DSL Involved filters
http.formLogin() UsernamePasswordAuthenticationFilter
http.rememberMe() RememberMeAuthenticationFilter
http.httpBasic() HttpBasicAuthenticationFilter
http.anonymous() AnonymousAuthenticationFilter
http.openid() OpenIDAuthenticationFilter
http.x509() x509AuthenticationFilter
http.logout() LogoutFilter
http.csrf() CsrfFilter
http.exceptionHandling() ExceptionTranslationFilter
http.authorizeRequests() FilterSecurityInterceptor
http.sessionManagement() SessionManagementFilter
http.headers() HeaderWriterFilter
http.cors() CorsFilter
http.requestCache() RequestCacheFilter()
http.servletApi() SecurityContextHolderAwareRequestFilter

For a minimal http security config, these are the filters:

Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CsrfFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]

Let’s see how authentication mechanism is supported by the required filters:

  • form login

use UsernamePasswordAuthenticationToken

Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CsrfFilter
  LogoutFilter
  UsernamePasswordAuthenticationFilter ⇦
  DefaultLoginPageGeneratingFilter     ⇦
  DefaultLogoutPageGeneratingFilter    ⇦
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]
  • http basic auth

use UsernamePasswordAuthenticationToken

Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CsrfFilter
  LogoutFilter
  BasicAuthenticationFilter   ⇦
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]
  • remember me

use RememberMeAuthenticationToken

Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CsrfFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  RememberMeAuthenticationFilter     ⇦ 
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]
  • oauth2 login

OAuth2LoginAuthenticationFilter

  • openid login

OpenIDAuthenticationFilter

  • JWT

You define you filter to insert into the filter chain (typically between LogoutFilter and RequestCacheAwareFilter):

  • extract JWT
  • verify it
  • set SecurtyContext if any
  • Custom authentication mechanism

Probably you should define authentication provider and your filters (maybe multiple) to support the flow.

An example implementation can be seen here:

https://github.com/chaoyangnz/email-service/tree/master/src/main/java/emailservice/entrypoint/rest/security

Important Filters

ExceptionTranslationFilter

This filter is normally registered at the very bottom. And what it is doing to catch errors thrown in filters after it (FilterSecurityInterceptor), and handling them. By default, it is using Http403ForbiddenEntryPoint and AccessDeniedHandlerImpl where it calls sendError() which is a redirection to WhiteLabel error page /error and show generic JSON/HTML page.

Sometime, if you don’t exclude /error to protected URLs. You would see a double calls of the filter chain, which you definitely don’t hope to see and hard to debug.

You can define AuthenticationEntryPoint and AccessDeniedHandler to customise the error handling.

In general, this filter is not that useful, as its order is too high, so that the errors thrown before it cannot be caught and by default directly handled by WhiteLabel error page.

I suggest you should disable it and create you own error handling filter.

FilterSecurityInterceptor

This filter is the last gate to check Authentication and apply authorizeRequests rules.

For example, if you config .anyRequest().authenticated(), it will check if Authentication is null and authenticated is true, etc.

From the design of Spring Security, normally it doesn’t hope you throw exception in your authentication mechanism, instead you only need to provide Authentication object and populate its fields.

AnonymousAuthenticationFilter

This is to create a AnonymousAuthention if there is no Authentication in earlier filter.

In general, it is not useful. If you keep it, you have to give it an extra care when you define authorizeRequests rules.

Custom Filter

  • Where I should add the filter and how it affects the order of default filter chain
  • Why you should disable the auto registration of a filter bean
  • multiple filter chains? possible?