David542
David542

Reputation: 110432

Enforcing a min length in Django password

I am currently using django.contrib.auth.views.password_password_reset_confirm to change a user's password. This is how my urls look:

from django.contrib.auth import views as auth_views

url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
    redirect_if_loggedin(auth_views.password_reset_confirm),
    name='auth_password_reset_confirm'),

Currently, I am doing it directly into the django trunk -

# django.contrib.auth.views
def clean_new_password2(self):
    password1 = self.cleaned_data.get('new_password1')
    password2 = self.cleaned_data.get('new_password2')
    if password1 and password2:
        if len(password1) < 8:
            raise forms.ValidationError(_("Password must be at least 8 chars."))
        if password1 != password2:
            raise forms.ValidationError(_("The two password fields didn't match."))
    return password2

Surely there must be a better way.

Upvotes: 7

Views: 5162

Answers (3)

Variant
Variant

Reputation: 17385

The code that I eventually wrote after understanding Arthur's accepted answer:

This is the inherited form:

class SetPasswordWithMinLengthForm(SetPasswordForm):
    """
    Inherited form that lets a user change set his/her password without
    entering the old password while validating min password length
    """
    def clean_new_password1(self):
        password1 = self.cleaned_data.get('new_password1')
        if len(password1) < 4:
            raise ValidationError("Password must be at least 4 chars.")
        return password1

In the urls.py you can instruct the view to use the custom form by specifing set_password_form:

url(r'^forgot_password/reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
                                                     'django.contrib.auth.views.password_reset_confirm',
                                                     {'set_password_form':SetPasswordWithMinLengthForm}),

Upvotes: 6

wouldnt
wouldnt

Reputation: 622

I'm using the django-registration plugin, which I've found to be excellent, so my example is based on that. But you could do a very similar thing without it.

This post does a good job of walking one through how to override a form (and widget) for django-registration -- in this case for a recaptcha spam-bot blocker.

What you need to do is override the RegistrationForm class (as below) and point your urls.py to use it instead of the default RegistrationForm

class MinPasswdLenRegistrationForm(RegistrationForm):
    min_password_length = 8

    def clean_password1(self):
        " Minimum length "
        password1 = self.cleaned_data.get('password1', '')
        if len(password1) < self.min_password_length:
            raise forms.ValidationError("Password must have at least %i characters" % self.min_password_length)
        else:
            return password1

(In a Form class, django will look for functions that start with clean_ and end with a field name (like password1) to execute during form validation.)

The other important bit is to use the form in your urls.py, like so:

from django.conf.urls.defaults import *
from registration.views import register

from myapp.forms import MinPasswdLenRegistrationForm

urlpatterns = patterns('',
    url(r'^register/$', register,
        {'form_class': MinPasswdLenRegistrationForm},
        name='registration.views.register'),
    (r'', include('registration.urls')),
)

HTH

Upvotes: 4

Arthur
Arthur

Reputation: 1984

If I understand correctly, you're modifying the django code? Because that's just can not be the way to do it.

What form do you use? It seems indeed that the built-in PasswordChangeForm won't let you set a min_length.

Maybe you could use the password_change view and set your own password_change_form, which could inherit from the basic PasswordChangeForm to which you could apply additional cleaning.

Upvotes: 2

Related Questions