1
votes

I have installed the grails Spring-Security plugin:

plugins {
    compile ':spring-security-core:2.0-RC2'
}

Then I used the grails s2-quickstart com.jane Person Role command to create the needed domain classes.

As I have my own User class I refactored the code to use my User class:

package com.jane

class User {

    transient springSecurityService

    String email
    String name
    String password
    Boolean isAgreeTerms = false
    Date agreeTermsDt
    Boolean isActive = false
    Boolean isBlocked = false

    Date dateCreated
    Integer createdBy = 0
    Date lastUpdated
    Integer modifiedBy = 0

    static transients = [ 'springSecurityService' ]
    static hasMany = [ userProductTier: UserProductTier ]
    static mapping = {
        id          column: "userID"
        dateCreated column: 'createdDt'
        lastUpdated column: 'modifiedDT'
    }

    static constraints = {
        email       blank: false, email: true, unique: true, size: 5..100
        name        blank: false, size: 3..50
        password    blank: false
    }

    void beforeInsert() {
        if ( isAgreeTerms ) {
            agreeTermsDt = new Date()
        }
        encodePassword()
    }

    def beforeUpdate() {
        if (isDirty('password')) {
            encodePassword()
       }
    }

    protected void encodePassword() {
        password = springSecurityService.encodePassword(password)
    }
}

I then modified the config.groovy file to:

grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.jane.User'
grails.plugin.springsecurity.userLookup.usernamePropertyName = 'email'
grails.plugin.springsecurity.userLookup.enabledPropertyName = 'isActive'
grails.plugin.springsecurity.userLookup.accountExpiredPropertyName = 'isBlocked'
grails.plugin.springsecurity.userLookup.accountLockedPropertyName = 'isBlocked'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.jane.UserRole'
grails.plugin.springsecurity.authority.className = 'com.jane.Role'

I can create users fine, verify they are in the database, have verified that encodePassword is called once. But every time I try to login I get the following error:

Sorry, we were not able to find a user with that username and password.

And here is the service method to create users:

User createTeamLeader( String name, String email, String password, Boolean isAgreeTerms, Integer productTierId ) {
    User user = new User( name: name, email: email, password: password, isAgreeTerms: isAgreeTerms, isActive: true)
    UserProductTier userProductTier = new UserProductTier( productTierId: productTierId )
    user.addToUserProductTier( userProductTier )
    user.save()
    UserRole.create( user, Role.findByAuthority('ROLE_USER'), true )
    UserRole.create( user, Role.findByAuthority('ROLE_LEAD'), true )
    user
}
1
Can you show the code you used to create the user and grant roles? It's usually helpful when seeing issues like this to crank up the logging - Spring Security logs a lot at the debug level. Add debug 'org.springframework.security' to the log4j block in Config.groovyBurt Beckwith
I added the function from my service above.Sam Farmer
I did add the debug information. And, to an untrained eye, this seems the most relevant section: Hibernate: select this_.userID ... from User this_ where (this_.email=?) limit ? 2013-12-08/21:57:18.259 [http-bio-127.0.0.1-8080-exec-9] DEBUG rememberme.TokenBasedRememberMeServices - Interactive login attempt was unsuccessful. 2013-12-08/21:57:18.259 [http-bio-127.0.0.1-8080-exec-9] DEBUG rememberme.TokenBasedRememberMeServices - Cancelling cookie 2013-12-08/21:57:18.264 [http-bio-127.0.0.1-8080-exec-9] DEBUG web.DefaultRedirectStrategy - Redirecting to '/jane/login/authfail?login_error=1'Sam Farmer
What should I be looking for in the logs to help debug?Sam Farmer

1 Answers

3
votes

Often adding debug logging helps, since Spring Security logs a lot at the debug level:

log4j = {
   ...
   debug 'org.springframework.security'
}

In this case it didn't show the problem, so I added an event listener to see if there was information in the failure event:

grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.onAbstractAuthenticationFailureEvent = { e, appCtx ->
   println "\nERROR auth failed for user $e.authentication.name: $e.exception.message\n"
}

That displayed this:

ERROR auth failed for user [email protected]: No such property: authorities for class: com.jane.User

When you made changes in the class, you removed the getAuthorities method that was in the original version, and is used by the UserDetailsService to determine granted roles during authentication. Adding it back got things working:

Set<Role> getAuthorities() {
   UserRole.findAllByUser(this).collect { it.role } as Set
}