Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #12103 -- Added AuthenticationForm.confirm_login_allowed to all…

…ow customizing the logic policy.

Thanks ejucovy and lasko for work on the patch.
  • Loading branch information...
commit a1889397a9f0e6a35189de455098b4c70923e561 1 parent 1c3c21b
@timgraham timgraham authored
View
25 django/contrib/auth/forms.py
@@ -191,13 +191,28 @@ def clean(self):
code='invalid_login',
params={'username': self.username_field.verbose_name},
)
- elif not self.user_cache.is_active:
- raise forms.ValidationError(
- self.error_messages['inactive'],
- code='inactive',
- )
+ 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',
+ )
+
def get_user_id(self):
if self.user_cache:
return self.user_cache.id
View
35 django/contrib/auth/tests/test_forms.py
@@ -2,6 +2,7 @@
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,
@@ -131,6 +132,40 @@ def test_inactive_user_i18n(self):
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 = {
View
4 docs/releases/1.7.txt
@@ -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
=====================================
View
34 docs/topics/auth/default.txt
@@ -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.
Please sign in to comment.
Something went wrong with that request. Please try again.