mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-24 00:24:48 +00:00
Run Django password validators against populated user models
Previously the validators were run against empty user models, which made the UserAttributeSimilarityValidator accept passwords that would otherwise have been rejected. Tests have been added to ensure the validator run correctly.
This commit is contained in:
parent
0d4f324d27
commit
9d8563a744
2 changed files with 88 additions and 3 deletions
|
|
@ -133,10 +133,26 @@ class UserForm(UsernameForm):
|
|||
code='password_mismatch',
|
||||
))
|
||||
|
||||
if password1:
|
||||
return password2
|
||||
|
||||
def validate_password(self):
|
||||
"""
|
||||
Run the Django password validators against the new password. This must
|
||||
be called after the user instance in self.instance is populated with
|
||||
the new data from the form, as some validators rely on attributes on
|
||||
the user model.
|
||||
"""
|
||||
password1 = self.cleaned_data.get("password1")
|
||||
password2 = self.cleaned_data.get("password2")
|
||||
if password1 and password2 and password1 == password2:
|
||||
validate_password(password1, user=self.instance)
|
||||
|
||||
return password2
|
||||
def _post_clean(self):
|
||||
super()._post_clean()
|
||||
try:
|
||||
self.validate_password()
|
||||
except forms.ValidationError as e:
|
||||
self.add_error('password2', e)
|
||||
|
||||
def _clean_fields(self):
|
||||
super()._clean_fields()
|
||||
|
|
|
|||
|
|
@ -200,6 +200,40 @@ class TestUserCreateView(TestCase, WagtailTestUtils):
|
|||
users = get_user_model().objects.filter(username='testuser')
|
||||
self.assertEqual(users.count(), 0)
|
||||
|
||||
@override_settings(
|
||||
AUTH_PASSWORD_VALIDATORS=[
|
||||
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
|
||||
],
|
||||
)
|
||||
def test_create_with_password_validation(self):
|
||||
"""
|
||||
Test that the Django password validators are run when creating a user.
|
||||
Specifically test that the UserAttributeSimilarityValidator works,
|
||||
which requires a full-populated user model before the validation works.
|
||||
"""
|
||||
# Create a user with a password the same as their name
|
||||
response = self.post({
|
||||
'username': "testuser",
|
||||
'email': "test@user.com",
|
||||
'first_name': "Example",
|
||||
'last_name': "Name",
|
||||
'password1': "example name",
|
||||
'password2': "example name",
|
||||
})
|
||||
|
||||
# Should remain on page
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'wagtailusers/users/create.html')
|
||||
|
||||
# Password field should have an error
|
||||
errors = response.context['form'].errors.as_data()
|
||||
self.assertIn('password2', errors)
|
||||
self.assertEqual(errors['password2'][0].code, 'password_too_similar')
|
||||
|
||||
# Check that the user was not created
|
||||
users = get_user_model().objects.filter(username='testuser')
|
||||
self.assertEqual(users.count(), 0)
|
||||
|
||||
def test_create_with_missing_password(self):
|
||||
"""Password should be required by default"""
|
||||
response = self.post({
|
||||
|
|
@ -603,7 +637,7 @@ class TestUserEditView(TestCase, WagtailTestUtils):
|
|||
self.assertEqual(user.first_name, 'Edited')
|
||||
self.assertTrue(user.check_password('password'))
|
||||
|
||||
def test_validate_password(self):
|
||||
def test_passwords_match(self):
|
||||
"""Password fields should be validated if supplied"""
|
||||
response = self.post({
|
||||
'username': "testuser",
|
||||
|
|
@ -625,6 +659,41 @@ class TestUserEditView(TestCase, WagtailTestUtils):
|
|||
self.assertEqual(user.first_name, 'Original')
|
||||
self.assertTrue(user.check_password('password'))
|
||||
|
||||
@override_settings(
|
||||
AUTH_PASSWORD_VALIDATORS=[
|
||||
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
|
||||
],
|
||||
)
|
||||
def test_edit_with_password_validation(self):
|
||||
"""
|
||||
Test that the Django password validators are run when editing a user.
|
||||
Specifically test that the UserAttributeSimilarityValidator works,
|
||||
which requires a full-populated user model before the validation works.
|
||||
"""
|
||||
# Create a user with a password the same as their name
|
||||
response = self.post({
|
||||
'username': "testuser",
|
||||
'email': "test@user.com",
|
||||
'first_name': "Edited",
|
||||
'last_name': "Name",
|
||||
'password1': "edited name",
|
||||
'password2': "edited name",
|
||||
})
|
||||
|
||||
# Should remain on page
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'wagtailusers/users/edit.html')
|
||||
|
||||
# Password field should have an error
|
||||
errors = response.context['form'].errors.as_data()
|
||||
self.assertIn('password2', errors)
|
||||
self.assertEqual(errors['password2'][0].code, 'password_too_similar')
|
||||
|
||||
# Check that the user was not edited
|
||||
user = get_user_model().objects.get(pk=self.test_user.pk)
|
||||
self.assertEqual(user.first_name, 'Original')
|
||||
self.assertTrue(user.check_password('password'))
|
||||
|
||||
def test_edit_and_deactivate(self):
|
||||
response = self.post({
|
||||
'username': "testuser",
|
||||
|
|
|
|||
Loading…
Reference in a new issue