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 /docs | |
| parent | f4416b1a8b92e492707a6261b7a1132f8550457f (diff) | |
Fixed #16860 -- Added password validation to django.contrib.auth.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/ref/settings.txt | 13 | ||||
| -rw-r--r-- | docs/releases/1.9.txt | 40 | ||||
| -rw-r--r-- | docs/topics/auth/passwords.txt | 214 |
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. |
