Hi,
I've found some inconsistent behavior in how password validation via the `UserAttributeSimilarityValidator` is handled by `contrib/auth`. I did not find any mention of this in Trac or on the mailing list, but apologies if this has already been discussed.
AFAICT: When creating a user, the password is only checked in similarity to the `username` field. When changing a password, the password is checked in similarity to `username`, `first_name`, `last_name`, and `email`.
This seems undesirable - it is possible to set a password at creation time that might be rejected if set during a password change.
In short:
When `SetPasswordForm` calls password validation, it has all of the fields on the `User` instance, but when `UserCreationForm` does so, it manually adds the one field being checked.
In depth:
In `django/contrib/auth/forms.py`, the `SetPasswordForm` and `UserCreationForm` both call `password_validation.validate_password()` in the `clean_password2()` method. In both instances, the forms pass `password2` and `self.instance`. In the `UserCreationForm`, the `ModelForm` hasn't yet created the `User` instance. `UserCreationForm` manually adds `username` to the empty `User` instance on line 105 to allow for user attribute validation.
Rather than check the validity of the passwords in the `password2` clean method, it seems like it would be better to wait until the `User` instance has been created. We can use the `ModelForm` `_post_clean()` hook to achieve this.
def _post_clean(self):
super()._post_clean() # creates self.instance
password = self.cleaned_data.get("password1")
if password:
try:
password_validation.validate_password(password, self.instance)
except ValidationError as error:
self.add_error("password1", error)
This keeps the two forms' behaviors consistent. Note that I've opted to use `password1` instead of `password2` because it feels more logical to show the problem above both passwords, rather than between the two fields.
Is there a reason *not* to make this change? Are there specific reasons for why we are only checking the `username` field during creation?
Feedback appreciated. If others approve of this, I will open a PR.
Andrew
http://jambonsw.com
http://django-unleashed.com