mirror of https://github.com/django/django.git
Refs #34429 -- Created `SetPasswordMixin` to reuse password validation logic in auth forms.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
This commit is contained in:
parent
31314980be
commit
f64c528c17
|
@ -89,27 +89,65 @@ class UsernameField(forms.CharField):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class BaseUserCreationForm(forms.ModelForm):
|
class SetPasswordMixin:
|
||||||
"""
|
"""
|
||||||
A form that creates a user, with no privileges, from the given username and
|
Form mixin that validates and sets a password for a user.
|
||||||
password.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_messages = {
|
error_messages = {
|
||||||
"password_mismatch": _("The two password fields didn’t match."),
|
"password_mismatch": _("The two password fields didn’t match."),
|
||||||
}
|
}
|
||||||
password1 = forms.CharField(
|
|
||||||
label=_("Password"),
|
@staticmethod
|
||||||
strip=False,
|
def create_password_fields(label1=_("Password"), label2=_("Password confirmation")):
|
||||||
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
password1 = forms.CharField(
|
||||||
help_text=password_validation.password_validators_help_text_html(),
|
label=label1,
|
||||||
)
|
strip=False,
|
||||||
password2 = forms.CharField(
|
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
||||||
label=_("Password confirmation"),
|
help_text=password_validation.password_validators_help_text_html(),
|
||||||
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
)
|
||||||
strip=False,
|
password2 = forms.CharField(
|
||||||
help_text=_("Enter the same password as before, for verification."),
|
label=label2,
|
||||||
)
|
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
||||||
|
strip=False,
|
||||||
|
help_text=_("Enter the same password as before, for verification."),
|
||||||
|
)
|
||||||
|
return password1, password2
|
||||||
|
|
||||||
|
def validate_passwords(
|
||||||
|
self, password1_field_name="password1", password2_field_name="password2"
|
||||||
|
):
|
||||||
|
password1 = self.cleaned_data.get(password1_field_name)
|
||||||
|
password2 = self.cleaned_data.get(password2_field_name)
|
||||||
|
if password1 and password2 and password1 != password2:
|
||||||
|
error = ValidationError(
|
||||||
|
self.error_messages["password_mismatch"],
|
||||||
|
code="password_mismatch",
|
||||||
|
)
|
||||||
|
self.add_error(password2_field_name, error)
|
||||||
|
|
||||||
|
def validate_password_for_user(self, user, password_field_name="password2"):
|
||||||
|
password = self.cleaned_data.get(password_field_name)
|
||||||
|
if password:
|
||||||
|
try:
|
||||||
|
password_validation.validate_password(password, user)
|
||||||
|
except ValidationError as error:
|
||||||
|
self.add_error(password_field_name, error)
|
||||||
|
|
||||||
|
def set_password_and_save(self, user, password_field_name="password1", commit=True):
|
||||||
|
user.set_password(self.cleaned_data[password_field_name])
|
||||||
|
if commit:
|
||||||
|
user.save()
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
class BaseUserCreationForm(SetPasswordMixin, forms.ModelForm):
|
||||||
|
"""
|
||||||
|
A form that creates a user, with no privileges, from the given username and
|
||||||
|
password.
|
||||||
|
"""
|
||||||
|
|
||||||
|
password1, password2 = SetPasswordMixin.create_password_fields()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
|
@ -123,34 +161,21 @@ class BaseUserCreationForm(forms.ModelForm):
|
||||||
"autofocus"
|
"autofocus"
|
||||||
] = True
|
] = True
|
||||||
|
|
||||||
def clean_password2(self):
|
def clean(self):
|
||||||
password1 = self.cleaned_data.get("password1")
|
self.validate_passwords()
|
||||||
password2 = self.cleaned_data.get("password2")
|
return super().clean()
|
||||||
if password1 and password2 and password1 != password2:
|
|
||||||
raise ValidationError(
|
|
||||||
self.error_messages["password_mismatch"],
|
|
||||||
code="password_mismatch",
|
|
||||||
)
|
|
||||||
return password2
|
|
||||||
|
|
||||||
def _post_clean(self):
|
def _post_clean(self):
|
||||||
super()._post_clean()
|
super()._post_clean()
|
||||||
# Validate the password after self.instance is updated with form data
|
# Validate the password after self.instance is updated with form data
|
||||||
# by super().
|
# by super().
|
||||||
password = self.cleaned_data.get("password2")
|
self.validate_password_for_user(self.instance)
|
||||||
if password:
|
|
||||||
try:
|
|
||||||
password_validation.validate_password(password, self.instance)
|
|
||||||
except ValidationError as error:
|
|
||||||
self.add_error("password2", error)
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
user = super().save(commit=False)
|
user = super().save(commit=False)
|
||||||
user.set_password(self.cleaned_data["password1"])
|
user = self.set_password_and_save(user, commit=commit)
|
||||||
if commit:
|
if commit and hasattr(self, "save_m2m"):
|
||||||
user.save()
|
self.save_m2m()
|
||||||
if hasattr(self, "save_m2m"):
|
|
||||||
self.save_m2m()
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
@ -383,48 +408,27 @@ class PasswordResetForm(forms.Form):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SetPasswordForm(forms.Form):
|
class SetPasswordForm(SetPasswordMixin, forms.Form):
|
||||||
"""
|
"""
|
||||||
A form that lets a user set their password without entering the old
|
A form that lets a user set their password without entering the old
|
||||||
password
|
password
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_messages = {
|
new_password1, new_password2 = SetPasswordMixin.create_password_fields(
|
||||||
"password_mismatch": _("The two password fields didn’t match."),
|
label1=_("New password"), label2=_("New password confirmation")
|
||||||
}
|
|
||||||
new_password1 = forms.CharField(
|
|
||||||
label=_("New password"),
|
|
||||||
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
|
||||||
strip=False,
|
|
||||||
help_text=password_validation.password_validators_help_text_html(),
|
|
||||||
)
|
|
||||||
new_password2 = forms.CharField(
|
|
||||||
label=_("New password confirmation"),
|
|
||||||
strip=False,
|
|
||||||
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, user, *args, **kwargs):
|
def __init__(self, user, *args, **kwargs):
|
||||||
self.user = user
|
self.user = user
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def clean_new_password2(self):
|
def clean(self):
|
||||||
password1 = self.cleaned_data.get("new_password1")
|
self.validate_passwords("new_password1", "new_password2")
|
||||||
password2 = self.cleaned_data.get("new_password2")
|
self.validate_password_for_user(self.user, "new_password2")
|
||||||
if password1 and password2 and password1 != password2:
|
return super().clean()
|
||||||
raise ValidationError(
|
|
||||||
self.error_messages["password_mismatch"],
|
|
||||||
code="password_mismatch",
|
|
||||||
)
|
|
||||||
password_validation.validate_password(password2, self.user)
|
|
||||||
return password2
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
password = self.cleaned_data["new_password1"]
|
return self.set_password_and_save(self.user, "new_password1", commit=commit)
|
||||||
self.user.set_password(password)
|
|
||||||
if commit:
|
|
||||||
self.user.save()
|
|
||||||
return self.user
|
|
||||||
|
|
||||||
|
|
||||||
class PasswordChangeForm(SetPasswordForm):
|
class PasswordChangeForm(SetPasswordForm):
|
||||||
|
@ -462,52 +466,27 @@ class PasswordChangeForm(SetPasswordForm):
|
||||||
return old_password
|
return old_password
|
||||||
|
|
||||||
|
|
||||||
class AdminPasswordChangeForm(forms.Form):
|
class AdminPasswordChangeForm(SetPasswordMixin, forms.Form):
|
||||||
"""
|
"""
|
||||||
A form used to change the password of a user in the admin interface.
|
A form used to change the password of a user in the admin interface.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_messages = {
|
|
||||||
"password_mismatch": _("The two password fields didn’t match."),
|
|
||||||
}
|
|
||||||
required_css_class = "required"
|
required_css_class = "required"
|
||||||
password1 = forms.CharField(
|
password1, password2 = SetPasswordMixin.create_password_fields()
|
||||||
label=_("Password"),
|
|
||||||
widget=forms.PasswordInput(
|
|
||||||
attrs={"autocomplete": "new-password", "autofocus": True}
|
|
||||||
),
|
|
||||||
strip=False,
|
|
||||||
help_text=password_validation.password_validators_help_text_html(),
|
|
||||||
)
|
|
||||||
password2 = forms.CharField(
|
|
||||||
label=_("Password (again)"),
|
|
||||||
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
|
||||||
strip=False,
|
|
||||||
help_text=_("Enter the same password as before, for verification."),
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, user, *args, **kwargs):
|
def __init__(self, user, *args, **kwargs):
|
||||||
self.user = user
|
self.user = user
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields["password1"].widget.attrs["autofocus"] = True
|
||||||
|
|
||||||
def clean_password2(self):
|
def clean(self):
|
||||||
password1 = self.cleaned_data.get("password1")
|
self.validate_passwords()
|
||||||
password2 = self.cleaned_data.get("password2")
|
self.validate_password_for_user(self.user)
|
||||||
if password1 and password2 and password1 != password2:
|
return super().clean()
|
||||||
raise ValidationError(
|
|
||||||
self.error_messages["password_mismatch"],
|
|
||||||
code="password_mismatch",
|
|
||||||
)
|
|
||||||
password_validation.validate_password(password2, self.user)
|
|
||||||
return password2
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
"""Save the new password."""
|
"""Save the new password."""
|
||||||
password = self.cleaned_data["password1"]
|
return self.set_password_and_save(self.user, commit=commit)
|
||||||
self.user.set_password(password)
|
|
||||||
if commit:
|
|
||||||
self.user.save()
|
|
||||||
return self.user
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def changed_data(self):
|
def changed_data(self):
|
||||||
|
|
Loading…
Reference in New Issue