From 5d308d943ec1ae83ecd02f5373afb3cf00a6dade Mon Sep 17 00:00:00 2001 From: Paul Eggleton Date: Fri, 19 Oct 2018 15:32:04 +1300 Subject: [PATCH] Enable password strength validation by default Use Django's built-in password validators with reasonable settings, and add a basic complexity validator since there isn't one provided. Additionally, fix the registration form so that it shows the help text which includes a description of what the password requirements are. Signed-off-by: Paul Eggleton --- docker/settings.py | 22 ++++++++++++++++ password_validation.py | 25 +++++++++++++++++++ settings.py | 22 ++++++++++++++++ templates/registration/registration_form.html | 3 +++ 4 files changed, 72 insertions(+) create mode 100644 password_validation.py diff --git a/docker/settings.py b/docker/settings.py index 462f432..e5d4824 100644 --- a/docker/settings.py +++ b/docker/settings.py @@ -162,6 +162,28 @@ AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', ] +# Password validation +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 8, + } + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + { + 'NAME': 'password_validation.ComplexityValidator', + }, +] + REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ( 'layerindex.restperm.ReadOnlyPermission', diff --git a/password_validation.py b/password_validation.py new file mode 100644 index 0000000..8669250 --- /dev/null +++ b/password_validation.py @@ -0,0 +1,25 @@ +from django.core.exceptions import ValidationError +from django.utils.translation import ugettext as _ + +import re + +class ComplexityValidator(object): + def validate(self, password, user=None): + score = 0 + if re.search('[0-9]', password): + score += 1 + if password.lower() != password: + score += 1 + if re.search('[^a-zA-Z0-9]', password): + score += 1 + + if score < 2: + raise ValidationError( + _("This password does not contain at least two of: upper/lowercase characters; a number; a special (non-alphanumeric) character."), + code='password_too_simple' + ) + + def get_help_text(self): + return _( + "Your password must contain at least two of: upper/lowercase characters; a number; a special (non-alphanumeric) character" + ) diff --git a/settings.py b/settings.py index 9a12a7b..80d28f7 100644 --- a/settings.py +++ b/settings.py @@ -162,6 +162,28 @@ AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', ] +# Password validation +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 8, + } + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + { + 'NAME': 'password_validation.ComplexityValidator', + }, +] + REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ( 'layerindex.restperm.ReadOnlyPermission', diff --git a/templates/registration/registration_form.html b/templates/registration/registration_form.html index 45f8c9a..38833af 100644 --- a/templates/registration/registration_form.html +++ b/templates/registration/registration_form.html @@ -20,6 +20,9 @@
{{ field }}
+

+ {{ field.help_text|safe }} +

{% endfor %}