16

I’m implementing authentication in a Django site using the built-in auth module, including the built-in UserCreationForm.

I’d like to set a minimum length for passwords. However, I can’t find any documentation on how to do this.

Can I configure the auth module’s User module to require this at the database level? Or should I sub-class the UserCreationForm (I’m actually doing this already for unrelated reasons) and add an extra validator that enforces the password length?

Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270

5 Answers5

44

I think the easiest way to achieve this is using Django password validation

For minimum length would be enough adding this to settings file:

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 8,
        }
    },
]

There are others validators like NumericPasswordValidator and CommonPasswordValidator

Andres
  • 4,323
  • 7
  • 39
  • 53
8

Especially if you're already using a sub-classed UserCreationForm, I'd say you should definitely just add the validation to it. You should be able to override the clean_password method on the form:

def clean_password(self):
    password = self.cleaned_data.get('password1')
    if len(password) < 8:
        raise ValidationError('Password too short')
    return super(MyUserCreationForm, self).clean_password1()
aliteralmind
  • 19,847
  • 17
  • 77
  • 108
Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • 1
    2 questions: 1) Why use super() here? Why not `return password`? 2) I'm getting a `AttributeError: 'super' object has no attribute 'clean_password'`. What might cause that? – Brian Dant Jun 23 '13 at 16:13
  • 1
    It should be `clean_password1` not `clean_password` (and `self.cleaned_data.get('password1')`) since UserCreationForm has a `password1` and `password2` for confirmation. – Kevin Stone Aug 24 '13 at 19:56
  • There is a better way. See other answer: https://stackoverflow.com/a/39714008/3708462 – Emdadul Sawon Mar 07 '18 at 07:31
  • What is the default minimum length if `AUTH_PASSWORD_VALIDATORS` not used? How can I check, is there a method? – Timo Jul 18 '18 at 09:03
4

Subclassing the user creation form sounds like a good approach. You can't enforce it at the database level, since Django only stores a hash of the password.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
1

Some info about answers,

django.contrib.auth.password_validation.MinimumLengthValidator

was newly implemented from django 1.9+ for older version it wont work,

so you can go with your own custom validator,

from django.core.exceptions import ValidationError
from django.utils.translation import ugettext

def validate(min_length, password):
    special_characters = "[~\!@#\$%\^&\*\(\)_\+{}\":;'\[\]]"
    if len(password) < 8:
        raise ValidationError(ugettext('Password length must be greater than 8 character.'))
    if not any(char.isdigit() for char in password):
        raise ValidationError(ugettext('Password must contain at least %(min_length)d digit.') % {'min_length': min_length})
    if not any(char.isalpha() for char in password):
        raise ValidationError(ugettext('Password must contain at least %(min_length)d letter.') % {'min_length': min_length})
    if not any(char in special_characters for char in password):
        raise ValidationError(ugettext('Password must contain at least %(min_length)d special character.') % {'min_length': min_length})
Mohideen bin Mohammed
  • 18,813
  • 10
  • 112
  • 118
0

/django/contrib/auth/password_validation.py Contains class MinimumLengthValidator with default the password minimum length:

class MinimumLengthValidator(object):
    """
    Validate whether the password is of a minimum length.
    """
    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(
                ungettext(
                    "This password is too short. It must contain at least %(min_length)d character.",
                    "This password is too short. It must contain at least %(min_length)d characters.",
                    self.min_length
                ),
                code='password_too_short',
                params={'min_length': self.min_length},
            )

    def get_help_text(self):
        return ungettext(
            "Your password must contain at least %(min_length)d character.",
            "Your password must contain at least %(min_length)d characters.",
            self.min_length
        ) % {'min_length': self.min_length}
Stan Zeez
  • 1,138
  • 2
  • 16
  • 38