Reputation: 619
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
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