2

If I write the following code:

static constraints = {      
    password blank: false, password: true , validator:{ val, obj -> 
        if (obj.password != obj.confirmarPassword)
            return 'usuario.password.dontmatch'
    }       
    confirmarPassword bindable: true
    }
}   

static transients = ['confirmarPassword']

The following error appears after introducing the same password in password and confirmarPassword:

null id in usuario.Usuario entry (don't flush the Session after an exception occurs)

I found out the root of the problem. It is the next comparison:

obj.password != obj.confirmarPassword

If I write the following code inside the validator:

println "password: ${obj.password}"
println "confirmarPassword: ${obj.confirmarPassword)}"

Eclipse prints:

password: testPassword
confirmarPassword: testPassword
password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: testPassword

As my second attempt I tried:

if (obj.password != obj.springSecurityService.encodePassword(obj.confirmarPassword))

The validation doesn't pass:

Property [password] of class [class usuario.Usuario] with value [testPassword] does not pass custom validation

And with:

println "password: ${obj.password}"
println "confirmarPassword: ${obj.springSecurityService.encodePassword(obj.confirmarPassword)}"

Eclipse prints:

password: testPassword
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb

For my third attempt I tried:

if (obj.springSecurityService.encodePassword(obj.password) != obj.springSecurityService.encodePassword(obj.confirmarPassword))

Again the same error:

null id in usuario.Usuario entry (don't flush the Session after an exception occurs)

The password looks encrypted twice the second time:

password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
password: e8c3cb111bf39f848b9a20e186f1663fd5acb0ae018ddf5763ae65bd6f45151e
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb

I'm running out of ideas. What about the client side? Would it be secure to perform this validation with Javascript?

This is my full domain class code:

package usuario

class Usuario implements Serializable {

    transient springSecurityService

    String username
    String password
    boolean enabled
    boolean accountExpired
    boolean accountLocked
    boolean passwordExpired

    String confirmarPassword
    String nombre
    String apellidos
    String email
    String telefono
    String documentoIdentificacion
    boolean aceptarPoliticaDeProteccionDeDatos = Boolean.FALSE

    static transients = ['confirmarPassword', 'aceptarPoliticaDeProteccionDeDatos']

    static constraints = {
        username blank: false, unique: true
        password blank: false, password: true 
        confirmarPassword bindable: true, blank:false, password: true, validator:{ val, obj -> 
            println "password: ${obj.password}"
            println "confirmarPassword: ${val}"     

            if ((obj.password != val))
                return 'usuario.password.dontmatch' 
        }

        nombre blank: false
        apellidos blank: false
        email blank: false, email:true
        telefono blank: false, matches: "[0-9 -+()]{3,15}"
        documentoIdentificacion blank: false
        aceptarPoliticaDeProteccionDeDatos bindable: true, validator:{ val, obj ->
            if (!obj.id && obj.aceptarPoliticaDeProteccionDeDatos != true) //> !obj.id: si el usuario ya no está creado. Si ya está creado es que lo está modificando y no es necesario que vuelva a aceptar la política.
                return 'usuario.politicaprotecciondatos.notaccepted'
        }
    }

    static mapping = {
        password column: '`password`'
    }

    Set<Rol> getAuthorities() {

            UsuarioRol.findAllByUsuario(this).collect { it.rol } as Set

    }

    def beforeInsert() {
        encodePassword()
    }

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

    protected void encodePassword() {
        password = springSecurityService.encodePassword(password)
    }
}
Servy
  • 202,030
  • 26
  • 332
  • 449
chelder
  • 3,819
  • 6
  • 56
  • 90
  • Is `val` in `validator` actually a spectator?? – dmahapatro Aug 22 '13 at 02:20
  • "null id in usuario.Usuario entry" -> your domain class id is assigned and is null?? Can you share the domain class entirely? –  Aug 22 '13 at 02:21
  • I don't understand what do you mean with _spectator_ @dmahapatro. – chelder Aug 22 '13 at 11:02
  • @sérgio, I'm quite sure the error is because a not null field is null when it try to be store in the database. It pass the validator in java code, but it doesn't pass the validator in the database? It is NOT the error posted [here](http://stackoverflow.com/questions/8636503/how-to-recover-from-dont-flush-the-session-after-an-exception-occurs-error) (as I thought at the beginning). – chelder Aug 22 '13 at 11:03
  • I posted the full domain class @SérgioMichels Thank you for everything :) – chelder Aug 22 '13 at 11:10
  • I think the root of this issue is that `confirmarPassword` is *transients* – chelder Aug 22 '13 at 11:19
  • `val` has not been used in your question anywhere in the `validator`. – dmahapatro Aug 22 '13 at 15:33
  • I use `val` here: `obj.password != val` and here: `println "confirmarPassword: ${val}"` – chelder Aug 22 '13 at 15:48

2 Answers2

1

Grails Spring Security Plugin encrypts your password before insert, but there is no need to invoke it unless you are actually comparing the current password to an old password. So a change password command object can have the following constraints:

static constraints = { 
    oldPassword validator: {val, obj ->
       def actual = obj.springSecurityService.encodePassword(val)
       if(actual != obj.secUser.password) 'old.password.must.match.current.password'
    }
    newPassword validator: {val, obj ->
       if(val == obj.oldPassword) 'new.password.must.differ.from.old'
    }
    confirmPassword validator: {val, obj ->
       if(val != obj.newPassword) 'confirm.password.must.match.new.password'
    }
}
Anatoly
  • 456
  • 5
  • 13
  • Thank you. This answer will be useful for me in the future for sure. But it doesn't solve the current issue :/ – chelder Aug 22 '13 at 10:54
1

If you are using spring security, you can try this:

class User{
String password

static mapping = {
    password column: '`password`'
}

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

def beforeInsert() {
    encodePassword()
}

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

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

It will hep you to save encoded password in database.

You can make a command object take a variable password and encode password like this:

@Validateable
class CommandObject implements Serializable {

String password
String confirmPassword

static constraints = {

    password nullable: false, blank: false
    confirmPassword nullable: false, blank: false, validator: { val, object ->
        if ((val != object.password)) {
            return 'passwordMismatch'
        }
        return true
    }        
 }
}
Servy
  • 202,030
  • 26
  • 332
  • 449
user1791574
  • 1,729
  • 2
  • 16
  • 30
  • I moved the validator from password to confirmPassword and changed `obj.password != obj.confirmarPassword` by `obj.password != val` (as these are the only differences I see with my code). The result is the same that the Attempt 1 :( – chelder Aug 22 '13 at 10:52
  • I cannot accept as answer because it doesn't work in my case. I think it is because `confirmPassword` is transients in my case as I don't want to store it in the database. – chelder Aug 22 '13 at 11:22
  • 1
    I also do not store confirm password in my database. I just compare it in command object,and save only password in database. or you want to say that you do not want to save you password in database. – user1791574 Aug 22 '13 at 12:19
  • Give me sometime to research what a command object is this afternoon :) – chelder Aug 22 '13 at 12:23
  • nope we are in just 3 hr 30 min difference. I think its evening at your side. – user1791574 Aug 22 '13 at 14:31
  • Well, it is 17:05 right now. I'm researching since one hour ago. Here, we usually say afternoon after lunch. We lunch around 2 or 3pm in Summer. It is quite different to the rest of the World, I know... – chelder Aug 22 '13 at 15:14
  • Comming back to programming, I added the `class CommandObject` inside `UsuarioController.groovy` and passed it as parameter (`def save(CommandObject cmd)`) as the [Grails documentation suggests](http://grails.org/doc/2.2.1/guide/single.html#commandObjects). But I was not able to pass the error message to the user yet (`return 'passwordMismatch'`). – chelder Aug 22 '13 at 15:15
  • I updated the answer to complete it. Thank you for everything! :) – chelder Aug 22 '13 at 22:56
  • Thanks Chaeder, I am happy that it help you. Good morning. – user1791574 Aug 23 '13 at 05:02
  • But why the update of the answer to complete it is removed? Did you remove it? :/ – chelder Aug 23 '13 at 12:55
  • No I did not remove any code. And I dont know how it remove from here. May be somebody reject it. – user1791574 Aug 23 '13 at 13:14
  • You're right. It has been rejected: http://meta.stackexchange.com/questions/194463/i-think-it-is-senseless-to-reject-the-edit-i-did – chelder Aug 23 '13 at 14:37
  • Thank you @user1791574. Anyway, the rest of the code to complete the answer is in this link: http://stackoverflow.com/review/suggested-edits/2776889 – chelder Aug 23 '13 at 16:58