Rammohan
Rammohan

Reputation: 619

Unable to resolve Grails custom validator issue

I am using spring security core plugin in my grails project and the Person domain looks something like this.

class User {

transient springSecurityService

//Mandatory Fields
String employeeId
String firstName
String lastName
String password
String emailId

//Other Fields
String department
String extn

String mobileNumber
String address
String city
String zipCode
String country

User manager

static hasMany = [previousPasswords: String]

boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired

static transients = ['springSecurityService']

static constraints = {
    employeeId blank: false, unique: true
    firstName blank: false
    lastName blank: false
    password blank: false, password: true, validator: {val, obj ->
        if(obj.previousPasswords) {
            println "-----------------------1-------------------------"
            println "obj.previousPasswords: " + obj.previousPasswords
            println "val: " + val
            if (obj.isDirty('password')) {
                println "-----------------------2-------------------------"
                if(obj.previousPasswords.contains(val)) {
                    obj.errors.rejectValue(
                        'password',
                        'user.password.duplicated',
                        'Repeat passwords are not allowed')
                    return false
                }
                println "-----------------------3-------------------------"
                obj.addToPreviousPasswords(val)
                return true
            }
        } else {
            println "-----------------------4-------------------------"
            obj.addToPreviousPasswords(val)
            return true
        }
    }
    emailId blank: false, email: true

    department nullable: true
    extn nullable: true

    mobileNumber nullable: true
    address nullable: true
    city nullable: true
    zipCode nullable: true
    country nullable: true

    manager nullable: true
}

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

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

def beforeInsert() {
    println "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
    encodePassword()
}

def beforeUpdate() {
    if (isDirty('password')) {
        println "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
        encodePassword()
    }
}

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

I have to ensure that passwords are not repeated for which I have written a custom validator for 'password' field

My Integration test looks like this

void "Test if previous passwords can be re-used"() {
    given:
    def user = new User(employeeId: "empId1", firstName: "f_name", lastName: "l_name", password: "password", emailId: "[email protected]", mobileNumber: "(111) 111-1111", address: "350 Fifth Avenue, 34th floor", city: "New York", zipCode: "10007")
    println "&&&&&&&&&&&&&&&&&&&  1  &&&&&&&&&&&&&&&&&&&&&&"
    user.springSecurityService = springSecurityService
    println "&&&&&&&&&&&&&&&&&&&  2  &&&&&&&&&&&&&&&&&&&&&&"
    user.save(flush: true, failOnError: true)

    when: 'password is repeated'
    user.password = "password"
    println "&&&&&&&&&&&&&&&&&&&  3  &&&&&&&&&&&&&&&&&&&&&&"
    user.save(flush: true)

    then: 'validation fails'
    !user.validate()
    user.errors.getFieldError("password").codes.contains("validator.invalid")

    when: 'password is not repeated'
    user.password = "password@123"

    then: 'validation succeeds'
    println "&&&&&&&&&&&&&&&&&&&  4  &&&&&&&&&&&&&&&&&&&&&&"
    user.validate()
    println "&&&&&&&&&&&&&&&&&&&  5  &&&&&&&&&&&&&&&&&&&&&&"
    user.save(flush: true)
}

and the output I am getting is like this

&&&&&&&&&&&&&&&&&&&  1  &&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&  2  &&&&&&&&&&&&&&&&&&&&&&
-----------------------4-------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-----------------------1-------------------------
obj.previousPasswords: [password]
val: $2a$10$mxFM9S7mEoOdyRo6xJL9/uzVafUgc0.8r1rd4nzBYM45s2cE8TTDi
&&&&&&&&&&&&&&&&&&&  3  &&&&&&&&&&&&&&&&&&&&&&
-----------------------1-------------------------
obj.previousPasswords: [password]
val: password
-----------------------2-------------------------
-----------------------1-------------------------
obj.previousPasswords: [password]
val: password

If you carefully study the code and the output you would find that the validator function is called twice for every save operation.

Can anyone tell me what is the reason for this. Could this be due to the addTo method that I am using within validator?

Upvotes: 1

Views: 166

Answers (1)

Visme
Visme

Reputation: 983

Shall i tell another way.Remove custom validation.

When user change password, check whether this password already exists in previousPasswords.if exists, give message like already used.if not, save the user with new password and add it to previousPasswords.

 def changePassword(){
       def userIns = User.get(params.userId)
       def previousPasswords = userIns.previousPasswords()
       def exists = previousPasswords.find{it == params.newPassword}
       if(exists){
           msg = "Already Used. Give new"
           render changepassword screen
           return false
       }
       else{
           userIns.password = params.newPw
           userIns.addToPreviousPasswords(params.newPw)
           userIns.save(flush:true)
           msg = "successfully changed"
       }
    }

Upvotes: 1

Related Questions