Custom Authentication with the Grails Spring Security Core Plugin

@burtbeckwith did a great job making Spring Security easily customizable and cake to work with in Grails via the Spring Security Core Plugin. However, authentication requirements can emerge that don’t fit any of its current implementations, so it’s nice to know what’s going on under the hood so you can plug in your own.

The Smart Notes Application
To demonstrate custom authentication with the plugin, I’ll build an incredibly simple note-taking application for a scientist and all his friends, called “Smart Notes”. The reason this needs to be custom made – He doesn’t care who accesses this application, as long as they are smart enough. Instead of managing usernames/passwords for everyone, he just wants to prompt the user with a very hard math problem, and if they get it right they’re in.

I’ll show snippets of some of the code, but the whole project is out on my github for following along.

<!–more–>

– NOTICE: For the sake of time, I wrote minimum viable code to get this application working. For real world custom authentication, I would suggest looking at the default/similar implementations in Spring/Grails and use them as a guide. Throughout this post I will point at the source of good examples to follow. Long live open source.

The AuthenticationEntryPoint
When a user tries to access a protected resource and Spring Security (SS from now on) determines they aren’t authenticated, an implementation of AuthenticationEntryPoint is called. The AuthenticationEntryPoint is basically what starts the authentication process. The most common implementation is LoginUrlAuthenticationEntryPoint which simply redirects the user to a login page so they can enter credentials. The default implementation used by Grails extends LoginUrlAuthenticationEntryPoint, called AjaxAwareAuthenticationEntryPoint.

For this application I’ll just use the default (AjaxAwareAuthenticationEntryPoint) and configure it to point to mathLogin.gsp instead of the usual auth.gsp:

In config.groovy:
grails.plugins.springsecurity.auth.loginFormUrl = ‘/login/mathLogin’
– NOTE: there are tons of things you can configure this way. Here is the full list.

in LoginController.groovy:
– Create a mathLogin controller action (see smart-notes).

But what if the requirement called for more than just a simple redirect within the application? What if scientist needs the application to redirect to an external application that will handle authentication and send the user back? You could create your own implementation of AuthenticationEntryPoint, called say, ExternalAuthenticationEntryPoint that contains something like:

redirectStrategy.sendRedirect(httpServletRequest, httpServletResponse, redirectUrl)

Then all you have to do is register it in resources.groovy. The easiest way to register it so the application will use it by default is to override the already registered implementation like this:

authenticationEntryPoint(ExternalAuthenticationEntryPoint) {
redirectUrl = grailsApplication.config.com.objectpartners.loginUrl
}

– NOTE: the above pulls the url of the external authentication site from an external config file (recommended) that you would have to set up, but you could also just hardcode it.
– SECOND NOTE: Look here to see all the bean configurations for the Grails Spring Security Plugin. This will tell you which implementations are configured by default.

Security Filters
When a user enters credentials (or in our case a guess to a question), the form submits to the action specified. Each request gets passed down a chain of security filters which look at the request URI, and if a filter matches what it is looking for to that action value, it will know to execute on that request. The default filter that handles logins is the UsernamePasswordAuthenticationFilter. Take a look at its constructor:

public UsernamePasswordAuthenticationFilter() {
super(“/j_spring_security_check”);
}

The value “/j_spring_security_check” is what this filter is looking for in the URI of incoming requests. When the filter sees this value in the URI of a request, it will try to authenticate with the information in the request, otherwise it will pass it off to the next filter in the chain. If you look at LoginController.groovy:

String postUrl = “${request.contextPath}${config.apf.filterProcessesUrl}”

The postUrl variable is what the login form uses as its action. Looking again at the default security configuration, we see that apf.filterProcessesUrl is set to “/j_spring_security_check”. This means that when the login form on auth.gsp is submitted, it will contain the value “/j_spring_security_check” that was given to it from the LoginController. When this request gets passed down the security filter chain, most of the filters will not be looking for that value and pass it down the line. Once it gets to UsernamePasswordAuthenticationFilter, it will see that value and know it should try to authenticate the user with that request.

The cool thing about using filters like this is that we can register many different filters to enable multiple ways of authentication, as long as they look for different values in the URL. Our application won’t be tied to just math login, we can still enable username and password login if we wish.

Looking at UsernamePasswordAuthenticationFilter, it doesn’t really fit what we are trying to accomplish with math-solving authentication, so we better create a new filter and put it in the chain.

Custom Authentication Filter
UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter , but I’ve found the best way to create a custom security filter is by extending GenericFilterBean and modeling it after AbstractAuthenticationProcessingFilter instead of extending it. For our math-solving authentication, I created MathAuthenticationFilter.

What this filter will do:

  1. Check to see if the request URL contains “j_spring_security_math_check”. If it doesn’t, it will call the next filter in the chain. If it does, the rest of the steps will execute.
  2. It will build an Authentication object (discussed later).

  3. It will pass that Authentication object to the AuthenticationManager (discussed later) to try and authenticate the user.

  4. If it’s successful (that is, if no AuthenticationException is thrown),  it will set the returned Authentication object in the SecurityContextHolder (discussed later). Whenever there is an Authentication object in the SecurityContextHolder, it means that user is authenticated in the application.

  5. It calls the success handler that will redirect to the appropriate place.

Looking at the MathAuthenticationFilter, some of the pieces won’t make much sense now, but I will get to them. First we have to register this filter to be part of the chain.

Registering the Filter
Looking at the documentation, an easy way to register your filter in the chain is by placing something like this in BootStrap.groovy:

SpringSecurityUtils.clientRegisterFilter(‘mathAuthenticationFilter’, SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order + 10)

So what is happening here? And what does [SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order + 10] mean?

Looking here tells you how the chain is ordered by default and where you should put your filter. The filters registered by the plugin have an “order” number associated with them that are in increments of 100. This means that if you would like your filter to be behind the SECURITY_CONTEXT_FILTER, adding any number < 100 will do the trick. In my example, since SECURITY_CONTEXT_FILTER has an order number of 300, our filter will get registered with an order of 310 and be next in line.

The Authentication Object
In our MathAuthenticationFilter, we need to create an object of type Authentication to pass to the AuthenticationManager. The Authentication object is basically just an object that holds information about the request, user trying to authenticate, and whether they are currently authenticated. I have created an implementation called MathAuthenticationToken for our needs. In the filter, once this object is populated, we send it to an implementation of AuthenticationManagerto continue the authentication process. The default Authentication implementation used by Spring is UsernamePassworkAuthenticationToken.

The AuthenticationManager
The default implementation of AuthenticationManager in SS is ProviderManager, which will work just fine for what we are trying to accomplish. It is the ProviderManager’s job to try and pass our Authentication object to all of its registered providers, and once it finds a provider that can handle that type of Authentication object, it will continue with the authentication process. This is another way that SS allows you to have multiple forms of authentication.

Say you have an application where you want to support both Twitter and Facebook authentication. All you have to do is create a provider for each, register them with the ProviderManager, and it will take care of routing each request to the right authentication process.

Since we will use the default ProviderManager, we won’t have to create any new implementations. However, we will need to register a new provider with ProviderManager to handle our math-based authentication. Here’s how:

In config.groovy:
grails.plugins.springsecurity.providernames = [‘OUR_FUTURE_MATH_AUTHENTICATION_PROVIDER’]

– NOTE: if you only register your provider, none of the other providers that are included in the framework will be available such as: daoAuthenticationProvider, anonymousAuthenticationProvider, and rememberMeAuthenticationProvider. If you want any of these providers to be available, you will have to register them in the list. Check out the documentation for more on that.

For our application, I’m only going to register the provider we make in the next section, because I don’t want any of those other functionalities for now

Providers
Once the filter intercepts an authentication request and an Authentication object is created from it, the provider is what really takes that object and orchestrates the actual authentication process.

The default provider for Spring/Grails is DaoAuthenticationProvider, which does the following:

  1. Checks to see if it can handle the type of Authentication object coming in. If it can’t, the ProviderManager will try the next provider that is registered.

  2. Retrieves the username that was stored in the Authentication object.

  3. Uses an implementation of UserDetailsService to load the user. If the user is found, this service creates an implementation of UserDetails that holds all of the relevant information that was stored in the application’s database about the user.

  4. Does some checking on the user data stored in this UserDetails object, such as if the user’s account is active, the credentials have expired, etc.

  5. Builds and returns an Authentication object to the filter that will be placed into the SecurityContextHolder (at that point the user is authenticated within the application).

You will notice that for Smart Notes, the data in the request doesn’t include a username and password that we must check against our stored data. We don’t store data about users at all. As a result, we have no need for implementations of UserDetailsService or UserDetails, and our provider will be much simpler. I created a provider called MathAuthenticationProvider, and here’s what it does:

  1. Checks to see if the Authentication object is of type MathAuthenticationToken. If it isn’t, the ProviderManager will try the next provider that is registered.

  2. Rerieves the question’s id and guess input from the Authentication object.

  3. Uses the MathAuthenticatorService to check the inputted answer vs the answer stored in our database.

  4. Builds and returns an Authentication object (MathAuthenticationToken) to the filter that will be placed into the SecurityContextHolder.

UserDetailsService and UserDetails
In the last section I briefly mentioned UserDetailsService and UserDetails, but I’m not going to elaborate on them since they aren’t valid in our application. It is somewhat common to need custom implementations of these objects in Grails while authenticating stored users, and as a result there are a handful of nice blogs about it already out there.

The SecurityContextHolder
I probably should have started this post by discussing SecurityContextHolder, but I feel it is easier to grasp its importance once you have seen how it is populated (by MathAuthenticationFilter) and what it will hold when a user is logged in (MathAuthenticationToken). The documentation does an awesome job explaining it, so check that out.

Recap
Speaking of the Spring Security documentation, it is really well written and does a much better job explaining the roles and processes of all the components then I could in this post. I would highly recommend reading through it and building a custom authentication scheme (even if it’s as useless as Smart Notes). Go ahead and clone Smart Notes and give it a run. It is a very a contrived example, but hopefully gives a good idea of the different parts that should be considered for custom authentication.

The key to understanding the Grails Spring Security Core Plugin is getting familiar with it on Github. Looking at the source will save many headaches.

 

One thought on “Custom Authentication with the Grails Spring Security Core Plugin

  1. You might also check out http://burtbeckwith.com/blog/?p=1090 where I did a talk about how things work under the hood, and showed an example in the sample code of how to do a custom authenticator.

  2. gerald says:

    Hi Jacob. I’ve been trying to get this working for almost a week now without success. Its been really frustrating. I’m using grails 2.3.0 with ggts 3.3.0. Do you have any code sample that works with this versions?

    1. I may have time to upgrade the example later – are there any specific errors you running into?

  3. Aurélien says:

    Thanks for this tutorial !
    it really helped me to understand spring security concepts. And i managed to custom authentification with a home made provider.

  4. @Aurelien Great! Glad it helped 🙂

  5. Excellent resource Jacob, thank you! Even with minimal Spring Security experience I was able to get things done. 🙂

  6. @Vahid Thanks for the feedback 🙂 Happy it could be use

  7. David says:

    I was getting a “No bean named ‘MyAuthenticationFilter’ is defined” error until I added the filter to the list of beans in grails-app/conf/spring/resources.groovy. Not sure if this tut mentions that.

  8. @David – you’re right, I don’t think I explicitly mentioned wiring up the filter. However, it is shown in the sample project at https://github.com/JacobASeverson/smart-notes/blob/master/grails-app/conf/spring/resources.groovy

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*