apache / apache/grails-core

user->group->role validation fails and user cant be validated - defect in code plugin code I think

Open
#15,871 1 comment 0 reactions 0 assignees View on GitHub
relates-to:spring-security type: improvement
Dominant language
Groovy
Stars
2.9k
Forks
975
Avg merge
1d 22h
Merged PRs (30d)
92

Description

i think there is a bug in GormUserDetailsService.groovy:92, in the V3.1.1 plugin i'm using. I noted this on stackoverflow here [stackoverlow ref ](http://stackoverflow.com/questions/42460249/bug-in-grails-spring-security-when-using-user-groups-and-roles-cant-authentic).

essentially i wanted to use user groups and roles. i did the following to get started.

`grails s2-quickstart org.softwood.security User Role --groupClassName=UserGroup`

I used UserGroup as Group was getting mixed up with sql syntax and naming of tables. Avoided it by changing the domain class name.

i configured some users with a mixture of ROLE_ADMIN, and ROLE_USER in boostrap.groovy to give me some test data - you can see the details in my demo project on github here [coffeShopApp](https://github.com/woodmawa/coffeeShopApp)

id did a bunch of asserts and checks an i think i set this all up - and dbconsole shows correct entries in tables.

i the created a a secureTest controller, with an open index() url, and protected secure url.

`class SecureTestController {

def index() {
render "hello Will you passed the permit_any"
}

@Secured ('ROLE_ADMIN')
def secure () {
render "hello Will you passed the ROLE_ADMIN"

}
}`

when i fire up the browser and connect to /secreTest/secure, the login screen is thrown and when i will in will/password it fails and you get stacktrace in the console

when i trawl through that and look in the code the thing i think is failing is this construct in the plugin

` if (useGroups) {
if (authorityGroupPropertyName) {
authorities = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique().collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }
}
`

i copied this out and put manually in my bootsrap.groovy so i could debug/walkthrough the steps. I also expanded the line in multiple calls so i could see which bit was failing like this in my boostrap

` if (useGroups) {
if (authorityGroupPropertyName) {
//userAuthorities returns Set
println """ debug
authoritiesPropertyName = $authoritiesPropertyName
authorityPropertyName = $authorityPropertyName
authorityGroupPropertyName = $authorityGroupPropertyName
userAuthorities returns $userAuthorities of type ${userAuthorities.getClass()}

"""
def roles = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique()

authorities = roles.collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }`

If i have understand what this tries to do it calls on userAuthorities=userWill.authorities (), to get a HashSet, which is getting the Set from the groups the users is joined to.

(PS my implementation is getting the roles from groups, and any individual roles assigned directly to a user, from this in User.getAuthorities()
` Set getAuthorities() {
//orig UserUserGroupBroken.findAllByUser(this)*.userGroup

Set individualRoles = UserToRole.findAllByUser(this)*.role
Set groups = UserToUserGroup.findAllByUser(this)*.group
Set groupRoles = groups.collect{it.getAuthorities() }
Set aggregateRoles = new HashSet()
aggregateRoles.addAll (groupRoles.flatten())
aggregateRoles.addAll (individualRoles.flatten())
aggregateRoles
}`
)

The key here is that the return from User class is HashSet. my asserts this worked as i expected in bootstrap.

the problem seems to me in the first part of the login authication code at line GormUserDeatilsService:92

` def roleNames = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique()`

what that looks like to me is that with the returned set of roles, its building a Collection of strings of each Role in the set, flattens it and makes it unique. in the debugger this shows as an ArrayList of strings. when i look at this list it has my three three role names assigned to this user. the problem then comes in the last part of code

`authorities = rolesNames.collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }`

this bit takes that arrayList of string and trys to read `it."$authorityPropertyName"` on it. but `it` is a string and doesnt have that property and so fails.

however i muck about with application.groovy settings this code construct doesn't work.

in my local copy i have 'fixed' the problem by writing and this returns a HashSet

`authorities = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique().collect { new SimpleGrantedAuthority(it) }`

i'm stuck with the plugin at the mo - because this validation logic appears to be in error. Not brave enough to try and fix the plugin myself at this point - so reporting the issue/defect for the team to assess.

Contributor guide

Open the contributing guide

Research direction

Start with GormUserDetailsService.groovy around line 92 and reproduce the failure using the User, UserGroup, Role setup described in the issue or the linked coffeeShopApp project. Check the group-derived and directly assigned roles during authentication; done means a user can log in and access the secured controller action without the reported stack trace.

Written by the indexing model from the issue text.

Assessment

Tech stack
groovy
Domain
authentication, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.