diff options
| author | Erik Romijn <eromijn@solidlinks.nl> | 2015-03-08 15:07:57 +0100 |
|---|---|---|
| committer | Erik Romijn <eromijn@solidlinks.nl> | 2015-06-07 19:31:20 +0200 |
| commit | 1daae25bdcd735151de394a5578c22257e3e5dc7 (patch) | |
| tree | 5d03536fe9cf69bf0fcf1a1997db713ce52a880b /tests/auth_tests/test_validators.py | |
| parent | f4416b1a8b92e492707a6261b7a1132f8550457f (diff) | |
Fixed #16860 -- Added password validation to django.contrib.auth.
Diffstat (limited to 'tests/auth_tests/test_validators.py')
| -rw-r--r-- | tests/auth_tests/test_validators.py | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/tests/auth_tests/test_validators.py b/tests/auth_tests/test_validators.py new file mode 100644 index 0000000000..543e520e8f --- /dev/null +++ b/tests/auth_tests/test_validators.py @@ -0,0 +1,162 @@ +from __future__ import unicode_literals + +import os + +from django.contrib.auth.models import User +from django.contrib.auth.password_validation import ( + CommonPasswordValidator, MinimumLengthValidator, NumericPasswordValidator, + UserAttributeSimilarityValidator, get_default_password_validators, + get_password_validators, password_changed, + password_validators_help_text_html, password_validators_help_texts, + validate_password, +) +from django.core.exceptions import ValidationError +from django.test import TestCase, override_settings + + +@override_settings(AUTH_PASSWORD_VALIDATORS=[ + {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, + {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': { + 'min_length': 12, + }}, +]) +class PasswordValidationTest(TestCase): + def test_get_default_password_validators(self): + validators = get_default_password_validators() + self.assertEqual(len(validators), 2) + self.assertEqual(validators[0].__class__.__name__, 'CommonPasswordValidator') + self.assertEqual(validators[1].__class__.__name__, 'MinimumLengthValidator') + self.assertEqual(validators[1].min_length, 12) + + def test_get_password_validators_custom(self): + validator_config = [{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}] + validators = get_password_validators(validator_config) + self.assertEqual(len(validators), 1) + self.assertEqual(validators[0].__class__.__name__, 'CommonPasswordValidator') + + self.assertEqual(get_password_validators([]), []) + + def test_validate_password(self): + self.assertIsNone(validate_password('sufficiently-long')) + msg_too_short = 'This password is too short. It must contain at least 12 characters.' + + with self.assertRaises(ValidationError, args=['This password is too short.']) as cm: + validate_password('django4242') + self.assertEqual(cm.exception.messages, [msg_too_short]) + + with self.assertRaises(ValidationError) as cm: + validate_password('password') + self.assertEqual(cm.exception.messages, ['This password is too common.', msg_too_short]) + + self.assertIsNone(validate_password('password', password_validators=[])) + + def test_password_changed(self): + self.assertIsNone(password_changed('password')) + + def test_password_validators_help_texts(self): + help_texts = password_validators_help_texts() + self.assertEqual(len(help_texts), 2) + self.assertTrue('12 characters' in help_texts[1]) + + self.assertEqual(password_validators_help_texts(password_validators=[]), []) + + def test_password_validators_help_text_html(self): + help_text = password_validators_help_text_html() + self.assertEqual(help_text.count('<li>'), 2) + self.assertTrue('12 characters' in help_text) + + +class MinimumLengthValidatorTest(TestCase): + def test_validate(self): + expected_error = "This password is too short. It must contain at least %d characters." + self.assertIsNone(MinimumLengthValidator().validate('12345678')) + self.assertIsNone(MinimumLengthValidator(min_length=3).validate('123')) + + with self.assertRaises(ValidationError) as cm: + MinimumLengthValidator().validate('1234567') + self.assertEqual(cm.exception.messages, [expected_error % 8]) + + with self.assertRaises(ValidationError) as cm: + MinimumLengthValidator(min_length=3).validate('12') + self.assertEqual(cm.exception.messages, [expected_error % 3]) + + def test_help_text(self): + self.assertEqual( + MinimumLengthValidator().get_help_text(), + "Your password must contain at least 8 characters." + ) + + +class UserAttributeSimilarityValidatorTest(TestCase): + def test_validate(self): + user = User.objects.create( + username='testclient', first_name='Test', last_name='Client', email='testclient@example.com', + password='sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161', + ) + expected_error = "The password is too similar to the %s." + + self.assertIsNone(UserAttributeSimilarityValidator().validate('testclient')) + + with self.assertRaises(ValidationError) as cm: + UserAttributeSimilarityValidator().validate('testclient', user=user), + self.assertEqual(cm.exception.messages, [expected_error % "username"]) + + with self.assertRaises(ValidationError) as cm: + UserAttributeSimilarityValidator().validate('example.com', user=user), + self.assertEqual(cm.exception.messages, [expected_error % "email address"]) + + with self.assertRaises(ValidationError) as cm: + UserAttributeSimilarityValidator(user_attributes=['first_name'], max_similarity=0.3).validate('testclient', user=user), + self.assertEqual(cm.exception.messages, [expected_error % "first name"]) + + self.assertIsNone( + UserAttributeSimilarityValidator(user_attributes=['first_name']).validate('testclient', user=user) + ) + + def test_help_text(self): + self.assertEqual( + UserAttributeSimilarityValidator().get_help_text(), + "Your password can't be too similar to your other personal information." + ) + + +class CommonPasswordValidatorTest(TestCase): + def test_validate(self): + expected_error = "This password is too common." + self.assertIsNone(CommonPasswordValidator().validate('a-safe-password')) + + with self.assertRaises(ValidationError) as cm: + CommonPasswordValidator().validate('godzilla') + self.assertEqual(cm.exception.messages, [expected_error]) + + def test_validate_custom_list(self): + path = os.path.dirname(os.path.realpath(__file__)) + '/common-passwords-custom.txt' + validator = CommonPasswordValidator(password_list_path=path) + expected_error = "This password is too common." + self.assertIsNone(validator.validate('a-safe-password')) + + with self.assertRaises(ValidationError) as cm: + validator.validate('from-my-custom-list') + self.assertEqual(cm.exception.messages, [expected_error]) + + def test_help_text(self): + self.assertEqual( + CommonPasswordValidator().get_help_text(), + "Your password can't be a commonly used password." + ) + + +class NumericPasswordValidatorTest(TestCase): + def test_validate(self): + expected_error = "This password is entirely numeric." + self.assertIsNone(NumericPasswordValidator().validate('a-safe-password')) + + with self.assertRaises(ValidationError) as cm: + NumericPasswordValidator().validate('42424242') + self.assertEqual(cm.exception.messages, [expected_error]) + + def test_help_text(self): + self.assertEqual( + NumericPasswordValidator().get_help_text(), + "Your password can't be entirely numeric." + ) |
