Custom Authentication Schemes with Grails and JSecurity

In my current software project a requirement is an authentication scheme consisting not of the usual user name an password, but user name, password and a store number. Each user name should be unique in for a store but could occur multiple times for all stores.

For several reasons I decided to implement authentication with JSecurity. The Grails plugin is a great help and the quickstart brings you up to speed pretty fast.

As the JSecurity documentation is pretty scarce on the topic of custom authentication schemes, I’m posting my findings here in my blog. Perhaps it is useful to other developers as well (actually i would love to see some comments on this :-) .

You’ll need a working grails application and the JSecurity plugin. You can install simply by typing grails install-plugin jsecurity. After that you should call grails quickstart, which is a script that creates among other a couple of domain classes and controllers.

Before we start some terms:

AuthenticationToken: holds authentication information for an authentication request; this is the container that holds your username/password pair, your PGP key, whatever.

Realm: acts as the part of the authentication system that decides whether a given AuthenticationToken is confirmed and granted access.

The trick for the custom authentication scheme is to create a custom AuthenticationToken and a customized Realm. A customized token could look like this (don’t tell me its ugly code – its not meant to be a cut’n'paste solution; it’s just to get the idea!):

class CustomToken implements AuthenticationToken {
  String username
  String password
  Integer storeNumber

  public Object getPrincipal() {
    "${storeNumber}:${username}" // This could be done nicer, however i do not know how... yet ;-)
  }
  public Object getCredentials() {
    password
  }
  // ... left out uninteressting methods.
}

So much for the token. That was straight forward. Now to the realm which requires some more coding. Of course you can write you realm from scratch, implementing the interface. That, however, is quite a piece of work, so simple modified the JsecDbRealm created by the quickstart script (again, only the important parts):

class JsecDbRealm {
  // We need this to tell JSecurity that this realm is responsible for our custom tokens:
  static authTokenClass = de.jakusys.example.CustomToken

  def authenticate(authToken) {
    def username = authToken.username
    // In addition to the username we need the store number for retrieval from the database:
    def storeNumber = authToken.storeNumber 

    // Null username is invalid
    if (username == null) {
      throw new AccountException('Null usernames are not allowed by this realm.')
    }
    // We need to check the format of the store number as well:
    try {
      storeNumber = Integer.parseInt(storeNumber)
    } catch (NumberFormatException ex) {
       throw new AccountException('Invalid store number.')
    }

    // Fetch the appropriate row from the database:
    def user = JsecUser.findByUsernameAndStoreNumber(username, storeNumber)
    if (!user) {
      throw new UnknownAccountException("No account found for user [${authToken.storeNumber}:${username}]")
    }

    // From here one you can re-use the code generated by the quickstart script...
  }

  // ... more uninteresting stuff ...
}

This is a most basic implementation that uses the default SimpleAccount class which could be considered ugly, as it does not know anything about the store number. Depending on your needs you can create your own implementation of Account or stick to the pre-implemented variant (I still have to check wether this has any security implications).

With the CustomToken and the modified realm in place, the only thing to be done is modifying the login form and the AuthenticationController, but that’s a piece of cake now. :-)

I mope my notes are of any use to you. I so, leave a comment.

Tags:

10 Responses to “Custom Authentication Schemes with Grails and JSecurity”

  1. Kapil says:

    Thanks for this tip. I create a custom authentication token and a realm. The configuration I am looking for (and was thinking would work) is that I can have multiple tokens and multiple realms for e.g.

    JsecDbRealm has a token UsernameToken
    JsecMyRealm has a token MyauthToken

    Now in the AuthController, UsernameToken is constructed and passed to the jsecSecurityManager.login() method. I was hoping that only JsecDbRealm will be called but I get an AuthenticationException and do not see code entering neither in JsecDbRealm or JsecMyRealm

    Would appreciate if you could guide what I may be doing wrong. In brief I would like to support multiple tokens and multiple relams. One token type for one realm.

    Thanks
    Kapil

  2. Kapil says:

    I got it working. It seems like the default authentication strategy is that the token would be passed to all realms and all should succeed (which means token should be same).

    In the my config I specified

    jsecurity.authentication.strategy = new org.jsecurity.authc.pam.AtLeastOneSuccessfulModularAuthenticationStrategy()

    and this made it work. This means that the multiple token types and realms does not work.

  3. Hey Kapil,
    I think you are right about the token being passed around to all realms; I think they are trying to mimic PAM style authentication.
    I’m not sure about multiple realms, my understanding is that all realms in grails-app/realms get registered at application startup and are queried for authentication tokens. So if you have different AuthenticationTokens, you’ll need different Realms that are responsible for them and perhaps a CredentialsMatcher.

    If i find some time, I’ll write another post about this stuff.

    Cheers,
    Jakob

  4. Peter Ledbrook says:

    Hi,

    First, nice post Jakob! Note that you could have the username and store number as separate principals, or combine the two into a single principal as you have already done. The principal can be any class.

    Recently the JSecurity API has changed a fair bit around this area, so there is now a PrincipalCollection class. I think the latest plugin has this since it uses a beta version of 0.9.0. I also need to update the plugin for the 0.9.0 RC1 release.

    Kapil, that looks like a bug. If a realm does not support a particular authentication token, it should not be queried during authentication. If you can, please raise an issue and attach an example project.

    Cheers,

    Peter

  5. Kapil says:

    Hi Peter,

    I am very new to Grails (3 days) and do not yet know where exactly to submit the issues etc. Will it be http://jira.codehaus.org/browse/GRAILS ? or you have some issue tracker of your own for jsecurity. Pardon my lack of awareness.

    Regards
    Kapil

  6. Kapil says:

    Never mind I found out that there is Grails-Plugins project and this is where I would post. Thanks

  7. Custom Authentication Schemes with Grails and JSecurity…

    [...]In my current software project a requirement is an authentication scheme consisting not of the usual user name an password, but user name, password and a store number. Each user name should be unique in for a store but could occur multiple times f…

  8. Hi Kapil,

    Good write-up! Thanks for taking the time to do it.

    If you get a chance, please feel free to take what you’ve written and add it to the Grails wiki – it depends on nice folks like you to help make Grails life better for everyone ;)

    Best regards,

    Les

  9. asc Een plaatje zegt alles, toch ? cjb Het volledige rapport is hier te vinden. Lees natuurlijk o de blogposting. t u
    Thanks for interesting post! fat
    [url=http://skuper.ru]ламинат купить[/url] 7w

  10. Alex says:

    Your blog is interesting!

    Keep up the good work!

Leave a Reply