summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorErik Romijn <eromijn@solidlinks.nl>2015-03-08 15:07:57 +0100
committerErik Romijn <eromijn@solidlinks.nl>2015-06-07 19:31:20 +0200
commit1daae25bdcd735151de394a5578c22257e3e5dc7 (patch)
tree5d03536fe9cf69bf0fcf1a1997db713ce52a880b /docs
parentf4416b1a8b92e492707a6261b7a1132f8550457f (diff)
Fixed #16860 -- Added password validation to django.contrib.auth.
Diffstat (limited to 'docs')
-rw-r--r--docs/ref/settings.txt13
-rw-r--r--docs/releases/1.9.txt40
-rw-r--r--docs/topics/auth/passwords.txt214
3 files changed, 266 insertions, 1 deletions
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index c745ad519b..a0c3e69877 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -2767,6 +2767,19 @@ Default::
'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher']
+.. setting:: AUTH_PASSWORD_VALIDATORS
+
+AUTH_PASSWORD_VALIDATORS
+------------------------
+
+.. versionadded:: 1.9
+
+Default: ``[]``
+
+Sets the validators that are used to check the strength of user's passwords.
+See :ref:`password-validation` for more details.
+By default, no validation is performed and all passwords are accepted.
+
.. _settings-messages:
Messages
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index afa624e295..ffa17391ec 100644
--- a/docs/releases/1.9.txt
+++ b/docs/releases/1.9.txt
@@ -25,7 +25,45 @@ Python 3.2 and added support for Python 3.5.
What's new in Django 1.9
========================
-...
+Password validation
+~~~~~~~~~~~~~~~~~~~
+
+Django now offers password validation, to help prevent the usage of weak
+passwords by users. The validation is integrated in the included password
+change and reset forms and is simple to integrate in any other code.
+Validation is performed by one or more validators, configured in the new
+:setting:`AUTH_PASSWORD_VALIDATORS` setting.
+
+Four validators are included in Django, which can enforce a minimum length,
+compare the password to the user's attributes like their name, ensure
+passwords aren't entirely numeric or check against an included list of common
+passwords. You can combine multiple validators, and some validators have
+custom configuration options. For example, you can choose to provide a custom
+list of common passwords. Each validator provides a help text to explain their
+requirements to the user.
+
+By default, no validation is performed and all passwords are accepted, so if
+you don't set :setting:`AUTH_PASSWORD_VALIDATORS`, you will not see any
+change. In new projects created with the default :djadmin:`startproject`
+template, a simple set of validators is enabled. To enable basic validation in
+the included auth forms for your project, you could set, for example::
+
+ AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+ ]
+
+See :ref:`password-validation` for more details.
Minor features
~~~~~~~~~~~~~~
diff --git a/docs/topics/auth/passwords.txt b/docs/topics/auth/passwords.txt
index 5f7bece6ee..090c9196b6 100644
--- a/docs/topics/auth/passwords.txt
+++ b/docs/topics/auth/passwords.txt
@@ -236,3 +236,217 @@ from the ``User`` model.
Checks if the given string is a hashed password that has a chance
of being verified against :func:`check_password`.
+
+.. _password-validation:
+
+Password validation
+===================
+
+Users often choose poor passwords. To help mitigate this problem, Django
+offers pluggable password validation. You can configure multiple password
+validators at the same time. A few validators are included in Django, but it's
+simple to write your own as well.
+
+Each password validator must provide a help text to explain the requirements to
+the user, validate a given password and return an error message if it does not
+meet the requirements, and optionally receive passwords that have been set.
+Validators can also have optional settings to fine tune their behavior.
+
+Validation is controlled by the :setting:`AUTH_PASSWORD_VALIDATORS` setting.
+By default, validators are used in the forms to reset or change passwords.
+The default for setting is an empty list, which means no validators are
+applied. In new projects created with the default :djadmin:`startproject`
+template, a simple set of validators is enabled.
+
+.. note::
+
+ Password validation can prevent the use of many types of weak passwords.
+ However, the fact that a password passes all the validators, doesn't
+ guarantee that it is a strong password. There are many factors that can
+ weaken a password that are not detectable by even the most advanced
+ password validators.
+
+Enabling password validation
+----------------------------
+
+Password validation is configured in the
+:setting:`AUTH_PASSWORD_VALIDATORS` setting::
+
+ AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ 'OPTIONS': {
+ 'min_length': 9,
+ }
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+ ]
+
+This example enables all four included validators:
+
+* ``UserAttributeSimilarityValidator``, which checks the similarity between
+ the password and a set of attributes of the user.
+* ``MinimumLengthValidator``, which simply checks whether the password meets a
+ minimum length. This validator is configured with a custom option: it now
+ requires the minimum length to be nine characters, instead of the default
+ eight.
+* ``CommonPasswordValidator``, which checks whether the password occurs in a
+ list of common passwords. By default, it compares to an included list of
+ 1000 common passwords.
+* ``NumericPasswordValidator``, which checks whether the password isn't
+ entirely numeric.
+
+For ``UserAttributeSimilarityValidator`` and ``CommonPasswordValidator``,
+we're simply using the default settings in this example.
+``NumericPasswordValidator`` has no settings.
+
+The help texts and any errors from password validators are always returned in
+the order they are listed in :setting:`AUTH_PASSWORD_VALIDATORS`.
+
+Included validators
+-------------------
+
+Django includes four validators:
+
+.. class:: MinimumLengthValidator(min_length=8)
+
+ Validates whether the password meets a minimum length.
+ The minimum length can be customized with the ``min_length`` parameter.
+
+.. class:: UserAttributeSimilarityValidator(user_attributes=DEFAULT_USER_ATTRIBUTES, max_similarity=0.7)
+
+ Validates whether the password is sufficiently different from certain
+ attributes of the user.
+
+ The ``user_attributes`` parameter should be an iterable of names of user
+ attributes to compare to. If this argument is not provided, the default
+ is used: ``'username', 'first_name', 'last_name', 'email'``.
+ Attributes that don't exist are ignored.
+
+ The maximum similarity the password can have, before it is rejected, can
+ be set with the ``max_similarity`` parameter, on a scale of 0 to 1.
+ A setting of 0 will cause all passwords to be rejected, whereas a setting
+ of 1 will cause it to only reject passwords that are identical to an
+ attribute's value.
+
+.. class:: CommonPasswordValidator(password_list_path=DEFAULT_PASSWORD_LIST_PATH)
+
+ Validates whether the password is not a common password. By default, this
+ checks against a list of 1000 common password created by
+ `Mark Burnett <https://xato.net/passwords/more-top-worst-passwords/>`_.
+
+ The ``password_list_path`` can be set to the path of a custom file of
+ common passwords. This file should contain one password per line, and
+ may be plain text or gzipped.
+
+.. class:: NumericPasswordValidator()
+
+ Validates whether the password is not entirely numeric.
+
+Integrating validation
+-----------------------
+
+.. module:: django.contrib.auth.password_validation
+
+There are a few functions in ``django.contrib.auth.password_validation`` that
+you can call from your own forms or other code to integrate password
+validation. This can be useful if you use custom forms for password setting,
+or if you have API calls that allow passwords to be set, for example.
+
+.. function:: validate_password(password, user=None, password_validators=None)
+
+ Validates a password. If all validators find the password valid, returns
+ ``None``. If one or more validators reject the password, raises a
+ :exc:`~django.core.exceptions.ValidationError` with all the error messages
+ from the validators.
+
+ The user object is optional: if it's not provided, some validators may not
+ be able to perform any validation and will accept any password.
+
+.. function:: password_changed(password, user=None, password_validators=None)
+
+ Informs all validators that the password has been changed. This can be used
+ by some validators, e.g. a validator that prevents password reuse. This
+ should be called once the password has been successfully changed.
+
+.. function:: password_validators_help_texts(password_validators=None)
+
+ Returns a list of the help texts of all validators. These explain the
+ password requirements to the user.
+
+.. function:: password_validators_help_text_html(password_validators=None)
+
+ Returns an HTML string with all help texts in an ``<ul>``. This is
+ helpful when adding password validation to forms, as you can pass the
+ output directly to the ``help_text`` parameter of a form field.
+
+.. function:: get_password_validators(validator_config)
+
+ Returns a set of validator objects based on the ``validator_config``
+ parameter. By default, all functions use the validators defined in
+ :setting:`AUTH_PASSWORD_VALIDATORS`, but by calling this function with an
+ alternate set of validators and then passing the result into the
+ ``password_validators`` parameter of the other functions, your custom set
+ of validators will be used instead. This is useful when you have a typical
+ set of validators to use for most scenarios, but also have a special
+ situation that requires a custom set. If you always use the same set
+ of validators, there is no need to use this function, as the configuration
+ from :setting:`AUTH_PASSWORD_VALIDATORS` is used by default.
+
+ The structure of ``validator_config`` is identical to the
+ structure of :setting:`AUTH_PASSWORD_VALIDATORS`. The return value of
+ this function can be passed into the ``password_validators`` parameter
+ of the functions listed above.
+
+Note that where the password is passed to one of these functions, this should
+always be the clear text password - not a hashed password.
+
+Writing your own validator
+--------------------------
+
+If Django's built-in validators are not sufficient, you can write your own
+password validators. Validators are fairly simple classes. They must implement
+two methods:
+
+* ``validate(self, password, user=None)``: validate a password. Return
+ ``None`` if the password is valid, or raise a
+ :exc:`~django.core.exceptions.ValidationError` with an error message if the
+ password is not valid. You must be able to deal with ``user`` being
+ ``None`` - if that means your validator can't run, simply return ``None``
+ for no error.
+* ``get_help_text()``: provide a help text to explain the requirements to
+ the user.
+
+Any items in the ``OPTIONS`` in :setting:`AUTH_PASSWORD_VALIDATORS` for your
+validator will be passed to the constructor. All constructor arguments should
+have a default value.
+
+Here's a basic example of a validator, with one optional setting::
+
+ from django.core.exceptions import ValidationError
+ from django.utils.translation import ugettext as _
+
+ class MinimumLengthValidator(object):
+ def __init__(self, min_length=8):
+ self.min_length = min_length
+
+ def validate(self, password, user=None):
+ if len(password) < self.min_length:
+ raise ValidationError(_("This password is too short."))
+
+ def get_help_text(self):
+ return _("Your password must contain at least %(min_length)d characters.")
+ % {'min_length': self.min_length}
+
+You can also implement ``password_changed(password, user=None``), which will
+be called after a successful password change. That can be used to prevent
+password reuse, for example. However, if you decide to store a user's previous
+passwords, you should never do so in clear text.