Hi Paul,
On 2015-02-25, 2:07 AM, "Paul Hoadley" wrote:
Hello,
I have a User entity with a password attribute that contains a BCrypt-hashed password. So User has setPassword() and password() methods, and also cover methods setPlaintextPassword() that does the hashing (and then calls setPassword()) and plaintextPassword()
that returns null. It works fine.
There are a couple of things that I would normally do at the application level that I thought might be reasonably moved down to the regular validation system, but it doesn't seem straightforward.
1. Changing the password. A method User.changePassword(String oldPassword, String newPassword, String confirmPassword) would take those form values and do the obvious: change the password if oldPassword hashes correctly and newPassword == confirmPassword.
2. Validate the plaintext password (say, is it long enough). This could be done in setPlaintextPassword().
What I'd like is for it all to be part of the validation system, such that when saveChanges() is called, validateForSave() throws appropriate exceptions and messages could be sent to the view layer. But it's a bit hairy. Consider just setPlaintextPassword(). Say
the supplied string is too short and it fails the password length test. My naive solution was to create the ValidationException, but hang onto it until saveChanges() is called
If the value is not valid, the validatePlaintextPassword method MUST throw at that point. What usually happens (e.g. When takeValues is processed on an HTML page, is that validatePlaintextPassword() is called and then setPlaintextPassword() if it does
not throw. If the value is not valid, the validatePlaintextPassword method MUST throw at that point. If you want the validations to work you must change the value, valid or not.
—but, and you can see where this is leading, validateForSave() doesn't get called unless the password is actually changed (assuming nothing else on the User is changed), so I don't get to throw that exception I stashed earlier. In that case I might be
able to make the change to the too-short string, and do what I was planning, but the changePassword() method is another story.
Say changePassword() is called, but oldPassword doesn't hash correctly. Now what? Do I call setPlaintextPassword(newPassword) anyway to ensure validateForSave() is called? But then in that method, I throw the exception I stashed, sure, but the password
has now _changed_ even though the app reports it _hasn't_. So a subsequent call to changePassword() with the previous oldPassword value is going to fail. Again, naively, I considered maybe changing it _back_ to the snapshot value for that attribute in validateForSave()
before throwing the exception, but then BAM! EOF Commandment #4:
Don't modify any EO properties in validateFor...(...) methods
So I'm stumped. Does this sound possible, or should I give up and continue to handle this kind of thing outside the regular validation system?
That is probably your best bet, or have changePassword throw validation exceptions, and accumulate them and any from takeValues in the GUI layer. That way you don’t even call saveChanges() if things have not validated to that point. My presentation from
WOWODC 2009 might give you some ideas. No, of course I never finished it!
There are no files, you have to clone the repository.
Chuck
|