0
votes

I have a group domain object with 3 fields - username, password and email address Prior to saving the object, I obfuscate the email address so its not stored in plaintext in our database as its a business requirement

I noticed some strange behaviour when I call validate on the domain object. The constraints for the fields are as follows

    userName (nullable: false, unique: false,blank: false, size: 4..200,widget: "textField", matches: "[a-zA-Z0-9, .-@#~{}!£%&*^()-_]+")
    password (nullable: false, unique: false,blank: false, size: 4..200,widget: "textField", password: true, matches: "[a-zA-Z0-9, .-@#~{}!£%&*^()-_]+")
    emailAddress (nullable: false, unique: false,blank: false, size: 5..200,widget: "textField",email: true, matches: "[a-zA-Z0-9, .-@#~{}!£%&*^()-_]+")

For the object, I validate it to ensure all the values are as expected (emailAddress not obfuscated yet) If valid I obfuscate the email address and then call save with the value of validate: false

The strange behaviour is as follows If I fill in a valid email Address and a valid password - the object fails validation on the userName field as it cannot be blank

If I fill in a valid email Address and a valid username- the object fails validation on the password field as it cannot be blank and also on the email Address and it shows the obfuscated value of the email address in the message

I thought first that the obfuscation was causing the problem but it works fine in the case of the password field being entered Its the exact same code flow for both scenarios.

Is it possible that grails is calling the validate method for the scenario where the password field is not filled in after I obfuscate the email address?

The code flow is as follows

        def userLoginUserInstance = UserLoginUser.get(params.id)
        userLoginUserInstance.properties = params

        if (userLoginUserInstance.validate()) {
            //perform updates to database by obfuscating email address first - working fine
        } else {
                def newObfuscatedEmailAddress =  userLoginUserInstance.emailAddress.encodeAsBase64();

                userLoginUserInstance.setEmailAddress(newObfuscatedEmailAddress);

                render(view: "edit", model: [userLoginUserInstance: userLoginUserInstance])
        }

The reason the email address is obfuscated when validation fails is that the gsp reads a transient variable which has a getter than deObfuscates the email address. When the above code runs where a username is not set, it works fine and the email address shows as being ok. If the password is blank, the error for the password shows but also the obfuscated email address shows as being invalid.

On Further analysis, the validation problem is happening when I run the following line of code

 userLoginUserInstance.setEmailAddress(newObfuscatedEmailAddress);

I understand why this is happening as userLoginUserInstance is retrieved from the database. What confuses me is that this doesnt happen in all scenarios

2
show us how you obfuscate - Chris
I changed my obfuscation to just encode the email address and the issue still happens when I do that. - Damien
please clarify the error case - Chris
You really should show us your code processing the validation. It is very difficult to follow your story and not see code. - Gregg
By the way, that regex matches more than you think it does, because .-@ inside a square bracket expression means everything between Unicode 002E and 0040 inclusive (including <, >, = etc.). )-_ is the same but covering a wider range (0029 to 005F, which includes all the digits, upper case letters and many other symbols). - Ian Roberts

2 Answers

1
votes

The validation error is happening because you are trying to store a Base64 String into an attribute which has an email-constraint:

"[email protected]".encodeAsBase64()

results in

Zm9vQGJhci5jb20=

So now when your User entity is flushed to the database again of course another validation is happening, complaining that this is no valid email address.

The reason, why the validation errors are not raised in all scenarios may be, that you do not enforce a user.save() nor user.save(flush:true).

This means the email address is not updated ad-hock, but some time later. To see better what's going on add another validation block after the email is assigned.

0
votes

Sorry for not getting back to this sooner

I solved this by passing a new object back to the view and not the object from the database Because I have a requirement to obfuscate the email address it really overly complicated this use case

Thanks for your help with this one guys

Regards Damien