views:

109

answers:

1

We're developing an app (using Grails Spring Security (formerly Acegi)) in which we'll have thousands of users that span 10-15 discreet user types. In the current system, each user type equates to a "group", and the specific roles and permissions are tied to the group. The user gets all their "roles" from the group.

For example, we might have two user groups:

CLOWN: roles = ride_clown_car, toot_horn, receive_applause ACROBAT: roles = do_flip, walk_tightrope, receive_applause

We have three users, one assigned to the CLOWN group, one assigned to the ACROBAT group, and one assigned to both (has union of CLOWN and ACROBAT roles).

If we change permissions, we do so at the group level. For example, if we add a swing_on_trapeze permission to the ACROBAT group, all acrobats will automatically inherit it.

In Grails terms, the permissions on the controllers would still be at the role level. So an action with @Secured (['toot_horn']) would allow users in the CLOWN group but not in the ACROBAT group. @Secured (['receive_applause']) would allow both CLOWNS and ACROBATS.

How would I do this in Spring Security given the two-tiered nature of the model (user, role)? Do I need to implement my own custom authentication to collect roles based via groups?

Thanks!

+3  A: 

You should be using the new Spring Security Core plugin since the Acegi plugin isn't being developed and is basically deprecated.

But either way, both plugins just expect that there's something like a getAuthorities() method in your user class that returns role instances. In a scenario like this where the user has many groups, just collect all of the groups' roles:

class User {
   ...
   def getAllRoles() {
      Set allRoles = []
      groups.each { allRoles.addAll it.roles }
      allRoles
   }
}

This assumes that you have a many-to-many between User and Group:

static hasMany = [groups: Group]

and Group has a many-to-many with Role:

static hasMany = [roles: Role]

To use this set the 'relationalAuthorities' property to 'allRoles' in SecurityConfig.groovy so it uses that instead of the many-to-many between user and role:

relationalAuthorities='allRoles'

There's no configuration required for the Spring Security core plugin since it depends on an application-defined getAuthorities method already, so just use something like this in your User class:

Set<Role> getAuthorities() {
   Set allRoles = []
   groups.each { allRoles.addAll it.roles }
   allRoles
}
Burt Beckwith
Ah- it hadn't occurred to me that Spring Security doesn't access Roles directly - only via the aggregator method on User. Thanks for posting this simple, elegant solution so quickly! Appreciate it. And thanks for all of your work on the plugin itself!
ecodan