0

I have the following problem: I have default User and Role domains and I use spring security plugin. There is a special requirement which says that if admin deletes User with USER_ROLE and this user is authenticated at the moment then this user should be kicked out of application immediately. Is it possible to programmatically make logout for the user if we have this user's object instance? Somethig like

def(User user) {

    someSpringService.forceLogout(user)

}

Thank you!

Andrey Yaskulsky
  • 2,458
  • 9
  • 39
  • 81
  • 1
    Take a look at some of the answers here, they will lead you to how to do this: http://stackoverflow.com/questions/11247495/ra-authenticate-changed-user-in-grails-application – Joshua Moore Jan 20 '15 at 18:00
  • @JoshuaMoore thanks, but unfortunately it doesn't help :((( – Andrey Yaskulsky Jan 21 '15 at 11:46
  • Why not? It clearly shows how to setup a session registry, find the session for a given user, and invalidate (e.g. logout) the user. What's missing? – Joshua Moore Jan 21 '15 at 11:52
  • @JoshuaMoore Yeap, I did all like explained and even found some misses - it's not possible to use sessionRegistry.getAllSession with User object but one should use Principal object instead. But that's not a problem. For some reason sessionInformation.expireNow() doesn't make any effect. May be that's because ConcurrentSessionControlStrategy is deprecated, I tried to replace it by ConcurrentSessionControlAuthenticationStrategy (which is new version) but it doesn't work. – Andrey Yaskulsky Jan 21 '15 at 12:00
  • When you say "it doesn't work" what do you mean? Does the session not get expired? Does it not find the session? – Joshua Moore Jan 21 '15 at 12:02
  • @JoshuaMoore Let's say we have USER and ADMIN both authenticated at the moment (lets say we use different browsers for it). ADMIN deletes USER (while user uses application) which invokes sessionRegistry to expire all USER's sessions (and all session are found in sessionRegistry and expireNow() is invoked on them). But after that USER still can use application until he clicks logout (next time he can't login). But I expect that USER will not be able to use application - after he goes on next page authorization error should be shown. – Andrey Yaskulsky Jan 21 '15 at 12:14
  • @JoshuaMoore found out that expiring the session is not as strong as invalidating - expired session will be invalidated by Spring some time after – Andrey Yaskulsky Jan 21 '15 at 15:17

1 Answers1

1

I am a newbie to grails. Recently I had the task of force logging out a user on change of his privileges by admin. So,After some research here is my solution. I am keeping track of the users sessions and once his session is changed I simply expire his active sessions.

In web.xml file, add this listener

<listener>
<listener-class>    
    org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>

In resources.groovy

import org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy
import org.springframework.security.web.session.ConcurrentSessionFilter
import org.springframework.security.core.session.SessionRegistryImpl
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy

beans = {
// bind session registry
    sessionRegistry(SessionRegistryImpl)
    sessionAuthenticationStrategy(ConcurrentSessionControlStrategy,sessionRegistry){ 
        maximumSessions = -1 }
    concurrentSessionFilter(ConcurrentSessionFilter){
    sessionRegistry = sessionRegistry
    expiredUrl = '/login/auth?f=true'
    }
}

In controller

def expireSession(User user) {
    log.info("Process to expire session begins")
    def orginalUser = springSecurityService?.principal.username
    log.info("session infos for all principals: ${sessionRegistry.getAllPrincipals()}")
    sessionRegistry.getAllPrincipals()?.each { princ ->
        def allSessions = sessionRegistry.getAllSessions(princ, true);
        log.info("all sessions: ${allSessions}")
        log.info("principal: $princ; email: ${user?.email}; username: ${princ?.username}")
        if(princ?.username?.equals(user?.email)) {      //killing sessions only for user (test@app.com)
            sessionRegistry.getAllSessions(princ, true)?.each { sess ->
                log.info("session: ${sess}; expiring it")
                if(sess.expireNow())
                    log.info("----session expired----")
                springSecurityService?.reauthenticate(user?.email)
                springSecurityService?.reauthenticate(orginalUser)
            }

        }
    }
}

In RequestFilters.groovy, where on each request we test if the session is valid or expired

class RequestFilters {

def springSecurityService
def sessionRegistry

def filters = {
    all(controller:'*', action:'*') {
        before = {
            log.info(controllerName + '/' + actionName +  " : " + params)
            log.info("request ${request}; session: ${request?.session}")
            def sessInfo = sessionRegistry.getSessionInformation(request?.session?.id)
            log.info("sessionRegistry: ${sessionRegistry}")
            log.info("Session Id: ${request?.session?.id}")
            log.info("session info: ${sessInfo}; is expired: ${sessInfo?.expired}")
            if(sessInfo?.expired==true)
                response.sendRedirect(grailsApplication.config.grails.serverURL+"/j_spring_security_logout");

        }
        after = { Map model ->

        }
        afterView = { Exception e ->

        }
    }     
}
Shabnam
  • 91
  • 1
  • 7