Reputation: 85
I have a simple Grails app with Spring Security Core plugin installed and working fine. However, I haven't found any solution to the problem with updating a logged in user's authorities in the security context. I am not talking about updating the current user's details (i.e. springSecurityService.reauthenticate).
My problem is: I have a simple user management app with ROLE_ADMIN and ROLE_USER authorities used. Now, I have 2 administrators logged in at the same time (with ROLE_ADMIN authority) from different computers, and one admin decides to change the other admin's authority from ROLE_ADMIN to ROLE_USER.
How can I update the user and role so that the modified user (with new ROLE_USER role) cannot perform any ROLE_ADMIN level actions and is immediately redirected to ROLE_USER level pages? Is there a way to update the security context so I don't have to do additional checking in all the controller actions whether the logged in user's authorities have been changed? Can I use the cahceUsers property for that somehow? I haven't modified the cacheUsers and in my understanding, it's false by default. Please, correct me if I'm wrong.
EDIT: The sequence that's causing the problem is
Administrator "A" modifies administrator "B" and sets a new role (ROLE_USER) for administrator "B"
the code calls PersonRole.removeAll(personInstanceB) and
PersonRole.create(personInstanceB, roleAdmin)
and everything is updated normally
at the same time Administrator "B" is already logged in when their authorities are modified. Administrator "B" can continue working on ROLE_ADMIN restricted pages until he/she logs out and does a new login. Only then the authorities are updated and Administrator "B" has the new role (ROLE_USER)
I want Administrator "B" to be redirected to the ROLE_USER pages when the user is updated with the new role and not only after logout/login
calling springSecurityService.reauthenticate personInstanceB.username)
causes Administrator "A" to be "logged in" as Administrator "B" so this does not work.
Any ideas would be very welcome. I may have missed something simple here but I have no idea what the solution would be.
Cheers, mizzzto
Upvotes: 8
Views: 5406
Reputation: 570
I have solved this problem by reauthenticating twice:
Save the name of the administrator who is demoting the other user:
def originalUserName = springSecurityService.principal.name
springSecurityService.reauthenticate user.username
springSecurityService.reauthenticate originalUserName
Upvotes: 7
Reputation: 7926
This is untested but give it a try
In your controller/service class,
...
User user = User.get(springSecurityService.principal.id) //get the user
Role adminRole = //get or create the admin Role
UserRole.remove user, role // remove admin Role
Role userRole = // get or create the user Role
UserRole.create user, role //add the user Role
...
if (!user.hasErrors() && user.save(flush: true)) {
springSecurityService.reauthenticate user.username // refresh the users security deatils
}
....
That is a lot clearer now.
What I would do off the top of my head is use the switch user function. see Switch User
useSwitchUserFilter
attribute to true
ROLE_SWITCH_USER
) for this priviledge.in your admin page somewhere,
<sec:ifAllGranted roles='ROLE_SWITCH_USER'>
<form action='/j_spring_security_switch_user' method='POST'>
Switch to user: <input type='text' name='j_username'/> <br/>
<input type='submit' value='Switch'/>
</form>
</sec:ifAllGranted>
adminToUser()
method below(for example)-- You can use the code form the first answer to create a method in your controller or service that take a userInstance and changes thier role from admin to user.
def adminToUser(user, adminRole, userRole){
UserRole.remove user, adminRole
UserRole.create user, userRole
if (!user.hasErrors() && user.save(flush: true)) {
springSecurityService.reauthenticate user.username
}
}
Upvotes: 11