Tuesday, June 26, 2012

Grails springsecurity core plugin 1.2.7.3 - BadCredentialsException

Problem:


I've recently upgraded to use the latest spring security plugin version 1.2.7.3.
After running s2-quickstart command as suggested in the documentation, the User, Role and UserRole domain objects were created.

I wanted to prepopulate the database with a default user by adding the following in Bootstrap.groovy:

Bootstrap.groovy
    def init = { servletContext ->                
        
        User existingUser = User.findByUsername('bob')
        
        if (existingUser == null) {                                    
            User u = new User(username: 'bob', enabled: true, password: 'password')          
            boolean saved = u.save(flush:true)
        }
        
    }


I started up the application and tried to login.
However when I try to authenticate I got a BadCredentialsException:

Investigation:


After a few hours of debugging, I noticed the way in which passwords were encoded have changed.
In the User domain class we see the following methods:

User.groovy
    def beforeInsert() {        
        encodePassword()
    }

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

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

As you can see, immediately before the User object is inserted to the database it will replace the password with an encoded password. 

I decided to log how the password was being encoded by modifying the encodePassword method as follows:


    protected void encodePassword() {
        System.out.println("encoding password: "+password)
        password = springSecurityService.encodePassword(password)
        System.out.println("to "+this.password)
    }

After running the application, I could see that the encodePassword method was being called twice!! In other words, it was re-encoding an already encoded password. Hence when I try to login I get the BadCredentialsException.

Solution:

 I modified the User.groovy class to remove any automated encoding of the password, and I manually set the encoded password myself.