Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ra-authenticate Changed User in Grails Application

I would like to immediately propagate user changes (change of user roles) in my Grails application (I'm using Spring Security Plugin).

I've found this:

springSecurityService.reauthenticate(userName)

but this works for currently logged user, not for the change one!

Is there any easy solution for this (even force logout of changed users will suffice me).

The use-case for this is when the admin change some other user role. If the changed user is logged in, the role change isn't seen immediately in the context of Spring Security.

like image 505
kuceram Avatar asked Jun 28 '12 15:06

kuceram


3 Answers

I think you have to declare a spring security SessionRegistry. Take a look here concurrent-sessions and here list-authenticated-principals.

Then you can list and access authenticated users and modify them.

like image 21
Fabiano Taioli Avatar answered Nov 16 '22 01:11

Fabiano Taioli


Thanks to Fabiano I've came with following solution which works:

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

// Place your Spring DSL code here
beans = {
    // bind session registry
    sessionRegistry(SessionRegistryImpl)

    sessionAuthenticationStrategy(ConcurrentSessionControlStrategy, sessionRegistry) {
        maximumSessions = -1
    }

    concurrentSessionFilter(ConcurrentSessionFilter){
        sessionRegistry = sessionRegistry
        expiredUrl = '/login/concurrentSession'
    }
}

MyService.groovy

def sessionRegistry

def expireSession(User user) {
        def userSessions = sessionRegistry.getAllSessions(user, false)
        // expire all registered sessions
        userSessions.each {
            log.debug "Expire session [$it] of the user [$user]"
            it.expireNow()
        }
}

Pretty easy :-)

Update:

Also don't forget to register HttpSessionEventPublisher and add concurrentSessionFilter to Config.groovy using different ways according to Filter Documentations.

web.xml

<listener>
    <listener-class>
       org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>
like image 137
kuceram Avatar answered Nov 16 '22 03:11

kuceram


Spent a long time browsing Internet on the same problem. Proposed solutions didn't work (may be I was'nt so lucky :). So here's my way

First we create a Grails service like this:

class SecurityHelperService {
    final Set<String> userUpdates = new HashSet<String>()

    public void markUserUpdate(String username) {
        synchronized (userUpdates) {
            userUpdates.add(username)
        }
    }

    public boolean clearUserUpdate(String username) {
        synchronized (userUpdates) {
            return userUpdates.remove(username) != null
        }
    }

    public boolean checkUserUpdate() {
        def principal = springSecurityService.principal

        if (principal instanceof org.springframework.security.core.userdetails.User) {
            synchronized (userUpdates) {
                if (!userUpdates.remove(principal.username)) {
                    return true
                }
            }

            springSecurityService.reauthenticate(principal.username)

            return false
        }

        return true
    }
}

In the grails-app/conf directory we create a Grails filter to check if current user permissions have been changed, for example

class MyFilters {
    SecurityHelperService securityHelper

    def filters = {
        userUpdateCheck(controller: '*', action: '*') {
            before = {
                if (!securityHelper.checkUserUpdate()) {
                    redirect url: '/'

                    return false
                }

                return true
            }
        }
    }
}

That's all. Every time when updating user permissions in code we call service method

securityHelper.markUserUpdate('username')

When the online user next time visits a page, his/her permissions are automatically checked and reloaded. No manual logout required.

Optionally we clear previous user update on a new login to avoid an unnecessary redirect in the filter

Hope this helps

like image 1
Vladimir Avatar answered Nov 16 '22 01:11

Vladimir