Grails spring role and security group

I set up spring protection to work with groups.

I used this script to create domain classes:

grails s2-quickstart com.yourapp User Role --groupClassName=RoleGroup 

I suggested that a user can have many groups, where a group can have many roles

This is what the generated method looks like in the User class:

 Set<RoleGroup> getAuthorities() { UserRoleGroup.findAllByUser(this).collect { it.roleGroup } } 

But now I saw that the script also created the UserRole class, which is the association between the user and the role. So the user can also have many roles directly?

I tried and it is saved in the database. I changed the method as follows:

 def getAuthorities() { def authorities = UserRoleGroup.findAllByUser(this).collect { it.roleGroup } authorities.addAll(UserRole.findAllByUser(this).collect { it.role }) return authorities } 

Now, when I create a database record in the User Role association. I can no longer enter. I get the default message using spring security basically saying no credentials were found.

When I delete the entry manually, I can log in again. I think this is because the method returns only RoleGroup objects.

My questions:

a) Can I also assign roles directly when I set up the groups

b) if not, why does the script create this class

c) if yes, how to do it?

+8
spring-security grails
source share
3 answers

I don’t think that one would expect Role be attached to Role when you use Groups .

Assign Group user, and Role - Group .

I think the presented code structure may be useful when "downgrading" your application

use only User and Roles without breaking your current set of rules.

+2
source share

This is just my opinion: the script created UserRole because it is just an optimization class, for example, if you get Role from db and tried to find some kind of user hibernate, you should have received all users from the proxy. This is just an optimization class. If you need one role for each user, you can configure it in UserRole.create () Add a constraint, and it should work. I hope you understand me, and I understood you correctly. A good day

+1
source share

A little old, but can come to your hands for all the other groups:

In the User class:

 Set<RoleGroup> getAuthorities() { (UserRoleGroup.findAllByUser(this) as List<UserRoleGroup>)*.roleGroup as Set<RoleGroup> } Set<Role> getRoles() { (UserRoleGroup?.findAllByUser(this)?.roleGroup?.authorities.collect{it}?.flatten() ?: oldRoles) as Set<Role> } List<String> getRoleNames() { (UserRoleGroup?.findAllByUser(this)?.roleGroup?.collect{it.authorities.authority}?.flatten()?: oldRoles.authority) as List<String> } //Above will look up from userRoleGroup roleGroup.authorities = UserRole below Set<Role> getOldRoles() { (UserRole.findAllByUser(this) as List<Role>)*.role as Set<Role> } 

I used roles, although the groups were enabled and authenticated against the old oldRoles method:

 import grails.plugin.springsecurity.userdetails.GormUserDetailsService import grails.transaction.Transactional import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UsernameNotFoundException class MySpringSecurityAuthenticator extends GormUserDetailsService{ UserDetails loadUserByUsername(String username, boolean loadRoles) throws UsernameNotFoundException { return loadUserByUsername(username) } @Transactional UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //enable login with either username or password User user = User.find { username == username || attributes.emailAddress == username || userCode == username } //if (!user) throw new UsernameNotFoundException('User not found', username) if (!user) throw new UsernameNotFoundException('User not found') return loadUserByUsername( user) } @Transactional UserDetails loadUserByUsername(User user) throws UsernameNotFoundException { if (!user) throw new UsernameNotFoundException('User not found') //UserDetails.withNewSession { //getAuthorities(user.oldRoles) UserDetails userDetails = new org.springframework.security.core.userdetails.User(user.username, user.password, user.enabled, !user.accountExpired, !user.passwordExpired, !user.accountLocked,getAuthoritiesFromGroup(user.authorities) ) Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()) SecurityContextHolder.getContext().setAuthentication(authentication) return userDetails //} } public static List<GrantedAuthority> getAuthoritiesFromGroup(Set<RoleGroup> roles) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>() roles?.each { role -> println "-- role = ${role} vs ${role.getClass()}" authorities.add(new SimpleGrantedAuthority(role.name)) } return authorities } public static List<GrantedAuthority> getAuthorities(Set<Role> roles) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>() roles?.each { role -> println "-- role = ${role} vs ${role.getClass()}" authorities.add(new SimpleGrantedAuthority(role.authority)) } return authorities } } 

and in my spring / resources.groovy:

 userDetailsService(MySpringSecurityAuthenticator){ grailsApplication = ref('grailsApplication') } 

What has been done so far, returned to user ROLES and added them to the authentication handler via .. getAuthorities (user.oldRoles)

Now I have changed the above method for reading in group names via getAuthoritiesFromGroup (user.authorities)

It simply analyzes the names of groups that, as a side (effect) of the version used, should also include the word ROLE_GROUPNAME

So if create

 @Transactional def grantPermission(User user, String role='ROLE_ADMIN', String group='ROLE_SUPERGROUP') { def adminRole = Role.findByAuthority(role) if (!adminRole) { adminRole = new Role(authority: role).save(flush: true) } UserRole.create user, adminRole, true def adminRoleGroup = RoleGroup.findByName(group) if (!adminRoleGroup) { adminRoleGroup = new RoleGroup(name: group).save(flush: true) } def adminRoleGroupRole = RoleGroupRole.findByRole(adminRole) if (!adminRoleGroupRole) { adminRoleGroupRole = new RoleGroupRole(role: adminRole, roleGroup: adminRoleGroup).save(flush: true) } def alreadyDone = UserRoleGroup.findByUserAndRoleGroup(user,adminRoleGroup) if (!alreadyDone) { new UserRoleGroup(user: user, roleGroup: adminRoleGroup).save(flush: true) } } 

I expect authentication against group names, not user roles, so in short, I had to change my controller to

 @Secured("hasAnyRole('ROLE_SUPERGROUP')") 

Hope this makes sense, has to be straightforward to follow, it just takes time to plunge into it all.

At this moment I am still playing around, and I will not use it as a specific answer, as I would like to crack it to say that my groups were my authorities, and if I wanted me to add another hook To go further each of these groups and each of its actual roles also - the uncertainty that this will produce - at the moment

I want to change it to requestMaps and move it to db so that a lot will change, and will decide whether I should go back or use groups that I know in this way, I can configure less names over controllers and rely on group names ..

In any case, this is under the hood of all this and gives you a clear idea for several years, but it can come in handy for others.

Update So I decided to go with:, ,getAuthorities(user.roles)

Where Set<Role> getRoles() { method inside the specified code bit

The reason is pretty simple:

 results?.each { it.user=User.get(it.id) println "-- \n${it.id}:${it.user.roles} \n${it.id}:${it.user.oldRoles}" 7:[Role(authority:ROLE_ADMIN), Role(authority:ROLE_ADMINAHHA)] 7:[Role(authority:ROLE_ADMIN)] 

As you can see, I added a new user using getOldRoles. I see only 1 role on getRoles. I get 2 roles. I added a user with two roles.

So, now he will analyze all user roles and add them to the List<GrantedAuthority> , authentication will still be through the actual ROLE names generated earlier.

It just means that when I disconnect the group from the user, it should stop downloading this permission for this user.

this is what the model should do

0
source share

All Articles