Loading django/contrib/auth/forms.py +20 −5 Original line number Diff line number Diff line Loading @@ -191,12 +191,27 @@ class AuthenticationForm(forms.Form): code='invalid_login', params={'username': self.username_field.verbose_name}, ) elif not self.user_cache.is_active: else: self.confirm_login_allowed(self.user_cache) return self.cleaned_data def confirm_login_allowed(self, user): """ Controls whether the given User may log in. This is a policy setting, independent of end-user authentication. This default behavior is to allow login by active users, and reject login by inactive users. If the given user cannot log in, this method should raise a ``forms.ValidationError``. If the given user may log in, this method should return None. """ if not user.is_active: raise forms.ValidationError( self.error_messages['inactive'], code='inactive', ) return self.cleaned_data def get_user_id(self): if self.user_cache: Loading django/contrib/auth/tests/test_forms.py +35 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ from __future__ import unicode_literals import os from django import forms from django.contrib.auth import get_user_model from django.contrib.auth.models import User from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm, Loading Loading @@ -131,6 +132,40 @@ class AuthenticationFormTest(TestCase): self.assertEqual(form.non_field_errors(), [force_text(form.error_messages['inactive'])]) def test_custom_login_allowed_policy(self): # The user is inactive, but our custom form policy allows him to log in. data = { 'username': 'inactive', 'password': 'password', } class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm): def confirm_login_allowed(self, user): pass form = AuthenticationFormWithInactiveUsersOkay(None, data) self.assertTrue(form.is_valid()) # If we want to disallow some logins according to custom logic, # we should raise a django.forms.ValidationError in the form. class PickyAuthenticationForm(AuthenticationForm): def confirm_login_allowed(self, user): if user.username == "inactive": raise forms.ValidationError(_("This user is disallowed.")) raise forms.ValidationError(_("Sorry, nobody's allowed in.")) form = PickyAuthenticationForm(None, data) self.assertFalse(form.is_valid()) self.assertEqual(form.non_field_errors(), ['This user is disallowed.']) data = { 'username': 'testclient', 'password': 'password', } form = PickyAuthenticationForm(None, data) self.assertFalse(form.is_valid()) self.assertEqual(form.non_field_errors(), ["Sorry, nobody's allowed in."]) def test_success(self): # The success case data = { Loading docs/releases/1.7.txt +4 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,10 @@ Minor features :class:`~django.middleware.http.ConditionalGetMiddleware` to handle conditional ``GET`` requests for sitemaps which set ``lastmod``. * You can override the new :meth:`AuthenticationForm.confirm_login_allowed() <django.contrib.auth.forms.AuthenticationForm.confirm_login_allowed>` method to more easily customize the login policy. Backwards incompatible changes in 1.7 ===================================== Loading docs/topics/auth/default.txt +34 −0 Original line number Diff line number Diff line Loading @@ -959,6 +959,40 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`: Takes ``request`` as its first positional argument, which is stored on the form instance for use by sub-classes. .. method:: confirm_login_allowed(user) .. versionadded:: 1.7 By default, ``AuthenticationForm`` rejects users whose ``is_active`` flag is set to ``False``. You may override this behavior with a custom policy to determine which users can log in. Do this with a custom form that subclasses ``AuthenticationForm`` and overrides the ``confirm_login_allowed`` method. This method should raise a :exc:`~django.core.exceptions.ValidationError` if the given user may not log in. For example, to allow all users to log in, regardless of "active" status:: from django.contrib.auth.forms import AuthenticationForm class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm): def confirm_login_allowed(self, user): pass Or to allow only some active users to log in:: class PickyAuthenticationForm(AuthenticationForm): def confirm_login_allowed(self, user): if not user.is_active: raise forms.ValidationError( _("This account is inactive."), code='inactive', ) if user.username.startswith('b'): raise forms.ValidationError( _("Sorry, accounts starting with 'b' aren't welcome here."), code='no_b_users', ) .. class:: PasswordChangeForm A form for allowing a user to change their password. Loading Loading
django/contrib/auth/forms.py +20 −5 Original line number Diff line number Diff line Loading @@ -191,12 +191,27 @@ class AuthenticationForm(forms.Form): code='invalid_login', params={'username': self.username_field.verbose_name}, ) elif not self.user_cache.is_active: else: self.confirm_login_allowed(self.user_cache) return self.cleaned_data def confirm_login_allowed(self, user): """ Controls whether the given User may log in. This is a policy setting, independent of end-user authentication. This default behavior is to allow login by active users, and reject login by inactive users. If the given user cannot log in, this method should raise a ``forms.ValidationError``. If the given user may log in, this method should return None. """ if not user.is_active: raise forms.ValidationError( self.error_messages['inactive'], code='inactive', ) return self.cleaned_data def get_user_id(self): if self.user_cache: Loading
django/contrib/auth/tests/test_forms.py +35 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ from __future__ import unicode_literals import os from django import forms from django.contrib.auth import get_user_model from django.contrib.auth.models import User from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm, Loading Loading @@ -131,6 +132,40 @@ class AuthenticationFormTest(TestCase): self.assertEqual(form.non_field_errors(), [force_text(form.error_messages['inactive'])]) def test_custom_login_allowed_policy(self): # The user is inactive, but our custom form policy allows him to log in. data = { 'username': 'inactive', 'password': 'password', } class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm): def confirm_login_allowed(self, user): pass form = AuthenticationFormWithInactiveUsersOkay(None, data) self.assertTrue(form.is_valid()) # If we want to disallow some logins according to custom logic, # we should raise a django.forms.ValidationError in the form. class PickyAuthenticationForm(AuthenticationForm): def confirm_login_allowed(self, user): if user.username == "inactive": raise forms.ValidationError(_("This user is disallowed.")) raise forms.ValidationError(_("Sorry, nobody's allowed in.")) form = PickyAuthenticationForm(None, data) self.assertFalse(form.is_valid()) self.assertEqual(form.non_field_errors(), ['This user is disallowed.']) data = { 'username': 'testclient', 'password': 'password', } form = PickyAuthenticationForm(None, data) self.assertFalse(form.is_valid()) self.assertEqual(form.non_field_errors(), ["Sorry, nobody's allowed in."]) def test_success(self): # The success case data = { Loading
docs/releases/1.7.txt +4 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,10 @@ Minor features :class:`~django.middleware.http.ConditionalGetMiddleware` to handle conditional ``GET`` requests for sitemaps which set ``lastmod``. * You can override the new :meth:`AuthenticationForm.confirm_login_allowed() <django.contrib.auth.forms.AuthenticationForm.confirm_login_allowed>` method to more easily customize the login policy. Backwards incompatible changes in 1.7 ===================================== Loading
docs/topics/auth/default.txt +34 −0 Original line number Diff line number Diff line Loading @@ -959,6 +959,40 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`: Takes ``request`` as its first positional argument, which is stored on the form instance for use by sub-classes. .. method:: confirm_login_allowed(user) .. versionadded:: 1.7 By default, ``AuthenticationForm`` rejects users whose ``is_active`` flag is set to ``False``. You may override this behavior with a custom policy to determine which users can log in. Do this with a custom form that subclasses ``AuthenticationForm`` and overrides the ``confirm_login_allowed`` method. This method should raise a :exc:`~django.core.exceptions.ValidationError` if the given user may not log in. For example, to allow all users to log in, regardless of "active" status:: from django.contrib.auth.forms import AuthenticationForm class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm): def confirm_login_allowed(self, user): pass Or to allow only some active users to log in:: class PickyAuthenticationForm(AuthenticationForm): def confirm_login_allowed(self, user): if not user.is_active: raise forms.ValidationError( _("This account is inactive."), code='inactive', ) if user.username.startswith('b'): raise forms.ValidationError( _("Sorry, accounts starting with 'b' aren't welcome here."), code='no_b_users', ) .. class:: PasswordChangeForm A form for allowing a user to change their password. Loading