After answering a question on stackoverflow about how to configure Spring Security with your own authentication mechanism I’d like to go into more details in this post. I’ll implement a simple use case where the actual authentication is done by reading the username and password from the header of a request.
The example method we implement in this post is NOT a secure way of implementing authentication. I just choose it for the sake of simplicity to demonstrate how to register your own authentication in Spring Security.
A working example can be found on Github
Let’s first have a look in a successful test to understand how we do our authentication:
The flow we want to implement is the following:
When a request to a secured endpoint is received by our server the
AuthenticationFilter should be processed and decide, based on the sent headers, if the associated user is authenticated to access the endpoint.
Our DemoController doesn’t do anything interesting and is simply for demonstration purpose:
Spring Security Configuration
Spring Security provides the tools to secure specific endpoints precisely. This is done by implementing a WebSecurityConfigurerAdapter:
Within this configuration we are able to add custom
Filter that gets registered by Spring Security in the Servlet Container. Spring already registers a bunch of security filters which are executed in a specific order:
- 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
Within this chain we need to put our own
Filter to a proper position. In this example we put it after the
ConcurrentSessionFilter. That way we support session handling but if that’s not successful we authenticate by our own mechanism.
Our CustomAuthenticationFilter extends from
GenericFilterBean which is registered as a bean automatically as soon as an implementation is found by Spring Boot. That bean gives us the possibility to execute code and our goal is to call
SecurityContextHolder.getContext().setAuthentication(authentication) with a valid authentication. By doing so the request is authenticated. Keep in mind that this authentication is only valid for this very request and therefore a valid authentication must be set for every other request as well. That’s why we send the necessary header to authenticate with every request on a secured endpoint.
In our example we check if the user with the given credentials is present in our custom
InMemoryUserStore and if so we set the authentication in the
And that’s it. You now successfully authenticated the request and it will be processed by Spring MVC. For a full example don’t forget to checkout the example project on Github.