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.
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.
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>
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With