mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
Fixed #16860 -- Added password validation to django.contrib.auth.
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user