Search code examples
authenticationgrailsspring-securitygrails3

Grails 3 - springSecurity reauthenticate and SessionRegistry


My Grails application (powered with Spring Security plugin) has in place a very basic support a 'quick login' feature, basically prompting users to type only their password to login while userId is stored in an encrypted cookie.

So in my controller I'm using springSecurityService.reauthenticate(userid)
to authenticate the user manually.

My application has also the requirement of not allowing concurrent sessions. So, along with the previous line, I added

def authentication = SecurityContextHolder.context.authentication
def sessions = sessionRegistry.getAllSessions(authentication.getPrincipal(), false)
// [L]
sessions.each {
    it.expireNow()
}

The issue is that these reauthentications do not reflect in an entry in sessionRegistry, and that's an issue with the above code, as among sessions I wouldn't find any session for that user.

The problem I'm not currently able to resolve is:

  • user [U] logs in to location [A]
  • [U] logs in to location [B] => session [A] is forced to expire
  • [U] keeps on navigating/refreshes [A], and is prompted to quick login
  • [U] logs in again to [A] => reauthenticate is triggered, nothing is added to sessionRegistry
  • [U] keeps on navigating/refreshes [B], and is prompted to quick login
  • [U] logs in again to [B]
  • [U] is logged on both [A] and [B]

I also tried to add
sessionRegistry.registerNewSession(newSessionId, authentication.getPrincipal())
in [L] position, but this session and the regenerated one seem to be not related in any way.

Any suggestion is welcome! Thanks in advance.

Config

  • Grails 3.2.4
  • Spring Security Plugin (core) 3.1.1

Solution

  • After a few attempts I came up with a working solution

    // injected dependencies
    AuthenticationManager authenticationManager
    SessionAuthenticationStrategy sessionAuthenticationStrategy
    
    // code
    Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.email, params.password))
    SecurityContextHolder.context.authentication = authResult   // need to reassign to context, otherwise onAuthentication fails (wrong password)
    sessionAuthenticationStrategy.onAuthentication(authResult, request, response)
    

    The trick seems to be calling onAuthentication, triggering all the defined request filters, on which relies the my concurrency session management.