From 576fd92c86fb9eb5d4afe24a97d024e91cf8337a Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Fri, 6 Jul 2018 12:20:55 +0200 Subject: [PATCH 2/3] convert password validation code to new API (#24833) --- src/authentic2/validators.py | 69 +++++++---------------------------- tests/test_attribute_kinds.py | 52 +++++++++++++------------- tests/test_registration.py | 2 +- 3 files changed, 40 insertions(+), 83 deletions(-) diff --git a/src/authentic2/validators.py b/src/authentic2/validators.py index c9e9b09b..d1bce8db 100644 --- a/src/authentic2/validators.py +++ b/src/authentic2/validators.py @@ -15,7 +15,7 @@ import socket import dns.resolver import dns.exception -from . import app_settings +from . import app_settings, passwords # copied from http://www.djangotips.com/real-email-validation class EmailValidator(object): @@ -80,38 +80,6 @@ class EmailValidator(object): email_validator = EmailValidator() -def validate_password(password): - password_set = set(password) - digits = set(string.digits) - lower = set(string.lowercase) - upper = set(string.uppercase) - punc = set(string.punctuation) - errors = [] - - if not password: - return - min_len = app_settings.A2_PASSWORD_POLICY_MIN_LENGTH - if len(password) < min_len: - errors.append(ValidationError(_('password must contain at least %d ' - 'characters') % min_len)) - - class_count = 0 - for cls in (digits, lower, upper, punc): - if not password_set.isdisjoint(cls): - class_count += 1 - min_class_count = app_settings.A2_PASSWORD_POLICY_MIN_CLASSES - if class_count < min_class_count: - errors.append(ValidationError(_('password must contain characters ' - 'from at least %d classes among: lowercase letters, ' - 'uppercase letters, digits, and punctuations') % min_class_count)) - if app_settings.A2_PASSWORD_POLICY_REGEX: - if not re.match(app_settings.A2_PASSWORD_POLICY_REGEX, password): - msg = app_settings.A2_PASSWORD_POLICY_REGEX_ERROR_MSG - msg = msg or _('your password dit not match the regular expession %s') % app_settings.A2_PASSWORD_POLICY_REGEX - errors.append(ValidationError(msg)) - if errors: - raise ValidationError(errors) - class UsernameValidator(RegexValidator): def __init__(self, *args, **kwargs): @@ -119,29 +87,18 @@ class UsernameValidator(RegexValidator): super(UsernameValidator, self).__init__(*args, **kwargs) -def __password_help_text_helper(): - if app_settings.A2_PASSWORD_POLICY_MIN_LENGTH and \ - app_settings.A2_PASSWORD_POLICY_MIN_CLASSES: - yield ugettext('Your password must contain at least %(min_length)d characters from at ' - 'least %(min_classes)d classes among: lowercase letters, uppercase letters, ' - 'digits and punctuations.') % { - 'min_length': app_settings.A2_PASSWORD_POLICY_MIN_LENGTH, - 'min_classes': app_settings.A2_PASSWORD_POLICY_MIN_CLASSES} +def validate_password(password): + error = password_help_text(password, only_errors=True) + if error: + raise ValidationError(error) + + +def password_help_text(password='', only_errors=False): + password_checker = passwords.get_password_checker() + criteria = [check.label for check in password_checker(password) if not (only_errors and check.result)] + if criteria: + return ugettext('In order to create a secure password, please use at least: %s') % (', '.join(criteria)) else: - if app_settings.A2_PASSWORD_POLICY_MIN_LENGTH: - yield ugettext('Your password must contain at least %(min_length)d characters.') % {'min_length': app_settings.A2_PASSWORD_POLICY_MIN_LENGTH} - if app_settings.A2_PASSWORD_POLICY_MIN_CLASSES: - yield ugettext('Your password must contain characters from at least %(min_classes)d ' - 'classes among: lowercase letters, uppercase letters, digits ' - 'and punctuations.') % {'min_classes': app_settings.A2_PASSWORD_POLICY_MIN_CLASSES} - if app_settings.A2_PASSWORD_POLICY_REGEX: - yield ugettext(app_settings.A2_PASSWORD_POLICY_REGEX_ERROR_MSG) or \ - ugettext('Your password must match the regular expression: ' - '%(regexp)s, please change this message using the ' - 'A2_PASSWORD_POLICY_REGEX_ERROR_MSG setting.') % \ - {'regexp': app_settings.A2_PASSWORD_POLICY_REGEX} - -def password_help_text(): - return ' '.join(__password_help_text_helper()) + return '' password_help_text = lazy(password_help_text, six.text_type) diff --git a/tests/test_attribute_kinds.py b/tests/test_attribute_kinds.py index 9da2c251..b6ecf052 100644 --- a/tests/test_attribute_kinds.py +++ b/tests/test_attribute_kinds.py @@ -23,15 +23,15 @@ def test_string(db, app, admin, mailoutbox): form.set('first_name', 'John') form.set('last_name', 'Doe') form.set('nom_de_naissance', '1234567890' * 30) - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit() assert response.pyquery.find('.form-field-error #id_nom_de_naissance') form = response.form form.set('nom_de_naissance', u'Noël') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit().follow() assert qs.get().attributes.nom_de_naissance == u'Noël' qs.delete() @@ -71,22 +71,22 @@ def test_fr_postcode(db, app, admin, mailoutbox): form.set('first_name', 'John') form.set('last_name', 'Doe') form.set('postcode', 'abc') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit() assert response.pyquery.find('.form-field-error #id_postcode') form = response.form form.set('postcode', '123') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit() assert response.pyquery.find('.form-field-error #id_postcode') form = response.form form.set('postcode', '12345') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit().follow() assert qs.get().attributes.postcode == '12345' qs.delete() @@ -96,8 +96,8 @@ def test_fr_postcode(db, app, admin, mailoutbox): form.set('first_name', 'John') form.set('last_name', 'Doe') form.set('postcode', ' 12345 ') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit().follow() assert qs.get().attributes.postcode == '12345' qs.delete() @@ -107,8 +107,8 @@ def test_fr_postcode(db, app, admin, mailoutbox): form.set('first_name', 'John') form.set('last_name', 'Doe') form.set('postcode', '') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit().follow() assert qs.get().attributes.postcode == '' qs.delete() @@ -174,23 +174,23 @@ def test_phone_number(db, app, admin, mailoutbox): form.set('first_name', 'John') form.set('last_name', 'Doe') form.set('phone_number', 'abc') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit() assert response.pyquery.find('.form-field-error #id_phone_number') form = response.form assert response.pyquery('#id_phone_number').attr('maxlength') == '30' form.set('phone_number', '1234512345' * 10) - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit() assert response.pyquery.find('.form-field-error #id_phone_number') form = response.form form.set('phone_number', '12345') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit().follow() assert qs.get().attributes.phone_number == '12345' qs.delete() @@ -200,8 +200,8 @@ def test_phone_number(db, app, admin, mailoutbox): form.set('first_name', 'John') form.set('last_name', 'Doe') form.set('phone_number', '+12345') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit().follow() assert qs.get().attributes.phone_number == '+12345' qs.delete() @@ -211,8 +211,8 @@ def test_phone_number(db, app, admin, mailoutbox): form.set('first_name', 'John') form.set('last_name', 'Doe') form.set('phone_number', '') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit().follow() assert qs.get().attributes.phone_number == '' qs.delete() @@ -222,8 +222,8 @@ def test_phone_number(db, app, admin, mailoutbox): form.set('first_name', 'John') form.set('last_name', 'Doe') form.set('phone_number', ' + 1.2-3 4 5 ') - form.set('password1', '12345abcd#') - form.set('password2', '12345abcd#') + form.set('password1', '12345abcdA') + form.set('password2', '12345abcdA') response = form.submit().follow() assert qs.get().attributes.phone_number == '+12345' qs.delete() diff --git a/tests/test_registration.py b/tests/test_registration.py index 1f39cd8a..d6d3a104 100644 --- a/tests/test_registration.py +++ b/tests/test_registration.py @@ -40,7 +40,7 @@ def test_registration(app, db, settings, mailoutbox, external_redirect): response.form.set('password1', 'toto') response.form.set('password2', 'toto') response = response.form.submit() - assert 'password must contain at least 8 characters' in response.content + assert '8 characters' in response.content # set valid password response.form.set('password1', 'T0==toto') -- 2.18.0