Home » JVM Languages » Groovy » Grails Custom AuthenticationProvider

About Kali Kallin

Grails Custom AuthenticationProvider

In order to tighten up security in our new Grails app I went about implementing the Spring Security Plugin. Getting it up and running with a standard username/password scenario was simple, as that is all wired up automagically by the plugin. That solved half of my problem, but we also need to support authentication with SAML, and there were no clear examples of how to do that. I’d like to share what I built in case anyone has a similar requirement. I won’t focus on the SAML specifics, but rather on how to build any custom authentication provider in grails.
You can map a URL to a filter by extending AbstractAuthenticationProcessingFilter and registering it with Spring. Then you can provide that URL for custom authentication. In my case it looked something like this:
class SamlAuthenticationFilter extends AbstractAuthenticationProcessingFilter  {

    public SamlAuthenticationFilter() {
        super("/somecustomauth")
    }

    @Override
    Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod())
        }

        String accessToken = request.getParameter("sometoken")
        return this.getAuthenticationManager().authenticate(new SamlAuthenticationToken(accessToken));
    }

}

The filter is then setup as a Spring bean, along with an authentication provider which I’ll discuss shortly:

import SamlAuthenticationFilter
import SamlAuthenticationProvider

beans = {
    samlAuthenticationFilter(SamlAuthenticationFilter) {
        authenticationManager = ref('authenticationManager')
        sessionAuthenticationStrategy = ref('sessionAuthenticationStrategy')
        authenticationSuccessHandler = ref('authenticationSuccessHandler')
        authenticationFailureHandler = ref('authenticationFailureHandler')
        rememberMeServices = ref('rememberMeServices')
        authenticationDetailsSource = ref('authenticationDetailsSource')
    }

    samlAuthenticationProvider(SamlAuthenticationProvider) {
        sAMLAuthenticationService = ref('SAMLAuthenticationService')
        sAMLSettingsService = ref('SAMLSettingsService')
        userDetailsService = ref('userDetailsService')
        passwordEncoder = ref('passwordEncoder')
        userCache = ref('userCache')
        saltSource = ref('saltSource')
        preAuthenticationChecks = ref('preAuthenticationChecks')
        postAuthenticationChecks = ref('postAuthenticationChecks')
    }
}

And the bean is then registered as a filter in the Bootstrap:

import org.codehaus.groovy.grails.plugins.springsecurity.SecurityFilterPosition
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils

class BootStrap {

    def init = { servletContext ->
        SpringSecurityUtils.clientRegisterFilter('samlAuthenticationFilter', SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order + 10)
    }

    def destroy = {
    }
}

We also need to create the Token class that is used by the Filter and the Authentication Provider:

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.userdetails.UserDetails

class SamlAuthenticationToken extends UsernamePasswordAuthenticationToken {

    String token

    public SamlAuthenticationToken(String token) {
        super(null, null);
        this.token = token;
    }

    public SamlAuthenticationToken(UserDetails principal, String samlResponse) {
        super(principal, samlResponse, principal.getAuthorities())
    }

}

And finally the AuthenticationProvider itself:

import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.core.Authentication
import sonicg.authentication.SAMLAuthenticationService

class SamlAuthenticationProvider extends DaoAuthenticationProvider {

    @Override
    Authentication authenticate(Authentication authentication) {
        def token = (SamlAuthenticationToken) authentication

        def user = // define user if credentials check out

        if (user){
            def userDetails = userDetailsService.loadUserByUsername(user.username)
            def token1 = new SamlAuthenticationToken(userDetails, token.samlResponse)
            return token1
        }else{
            return null
        }

    }

    @Override
    public boolean supports(Class authentication) {
        return (SamlAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

The last piece of the puzzle is to tell Spring to try using this authentication provider before the other standard three in Config.groovy:

grails.plugins.springsecurity.providerNames = [
        'samlAuthenticationProvider',
        'daoAuthenticationProvider',
        'anonymousAuthenticationProvider',
        'rememberMeAuthenticationProvider']
In this case it’s important that the custom filter goes first, as it’s Token is a subclass of UsernamePasswordAuthenticationToken. If the DAO provider was first it would try to authenticate the custom token before our filter gets a chance.
That’s it! Hopefully this proves useful to someone. It’s also just a first draft, and perhaps once the security requirements evolve I can refine the implementation and share what I’ve learned.

Reference: Custom AuthenticationProvider with Grails from our JCG partner Kali Kallin at the Kallin Nagelberg’s journey into the west blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

and many more ....

 

Leave a Reply

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

*


Want to take your Java Skills to the next level?
Grab our programming books for FREE!
  • Save time by leveraging our field-tested solutions to common problems.
  • The books cover a wide range of topics, from JPA and JUnit, to JMeter and Android.
  • Each book comes as a standalone guide (with source code provided), so that you use it as reference.
Last Step ...

Where should we send the free eBooks?

Good Work!
To download the books, please verify your email address by following the instructions found on the email we just sent you.