Code

Ticket #12103: 12103_with_better_working_tests.diff

File 12103_with_better_working_tests.diff, 4.9 KB (added by ejucovy, 3 years ago)
Line 
1Index: docs/topics/auth.txt
2===================================================================
3--- docs/topics/auth.txt        (revision 16061)
4+++ docs/topics/auth.txt        (working copy)
5@@ -1046,6 +1046,31 @@
6 
7     A form for logging a user in.
8 
9+    The ``AuthenticationForm`` rejects users whose ``is_active`` flag is set to ``False``.
10+    You may override this behavior with a custom policy to determine which users can log in.
11+    Do this with a custom form that subclasses ``AuthenticationForm`` and overrides the
12+    ``confirm_login_allowed(self, user)`` method.  This method will raise a ``forms.ValidationError``
13+    if the given user may not log in.
14+
15+    For example, to allow all users to log in, regardless of activation status::
16+
17+    .. code-block:: python
18+
19+        class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
20+            def confirm_login_allowed(self, user):
21+               pass
22+
23+    Or to allow only some active users to log in:
24+
25+    .. code-block:: python
26+
27+        class PickyAuthenticationForm(AuthenticationForm):
28+            def confirm_login_allowed(self, user):
29+               if not user.is_active:
30+                   raise forms.ValidationError(_("This account is inactive."))
31+               if user.username.startswith('b'):
32+                   raise forms.ValidationError(_("Sorry, accounts starting with 'b' aren't welcome here."))
33+
34 .. class:: PasswordChangeForm
35 
36     A form for allowing a user to change their password.
37Index: django/contrib/auth/tests/forms.py
38===================================================================
39--- django/contrib/auth/tests/forms.py  (revision 16061)
40+++ django/contrib/auth/tests/forms.py  (working copy)
41@@ -102,6 +102,44 @@
42                          [u'This account is inactive.'])
43 
44 
45+    def test_custom_login_allowed_policy(self):
46+        # The user is inactive, but our custom form policy allows him to log in.
47+        data = {
48+            'username': 'inactive',
49+            'password': 'password',
50+            }
51+
52+        class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
53+            def confirm_login_allowed(self, user):
54+                pass
55+
56+        form = AuthenticationFormWithInactiveUsersOkay(None, data)
57+        self.assertTrue(form.is_valid())
58+
59+        # If we want to disallow some logins according to custom logic,
60+        # we should raise a django.forms.ValidationError in the form.
61+        from django.forms import ValidationError
62+        from django.utils.translation import ugettext_lazy as _
63+        class PickyAuthenticationForm(AuthenticationForm):
64+            def confirm_login_allowed(self, user):
65+                if user.username == "inactive":
66+                    raise ValidationError(_("This user is disallowed."))
67+                raise ValidationError(_("Sorry, nobody's allowed in."))
68+       
69+        form = PickyAuthenticationForm(None, data)
70+        self.assertFalse(form.is_valid())
71+        self.assertEqual(form.non_field_errors(),
72+                         [u'This user is disallowed.'])
73+       
74+        data = {
75+            'username': 'testclient',
76+            'password': 'password',
77+            }
78+        form = PickyAuthenticationForm(None, data)
79+        self.assertFalse(form.is_valid())
80+        self.assertEqual(form.non_field_errors(),
81+                         [u"Sorry, nobody's allowed in."])
82+       
83     def test_success(self):
84         # The success case
85         data = {
86Index: django/contrib/auth/forms.py
87===================================================================
88--- django/contrib/auth/forms.py        (revision 16061)
89+++ django/contrib/auth/forms.py        (working copy)
90@@ -85,8 +85,8 @@
91             self.user_cache = authenticate(username=username, password=password)
92             if self.user_cache is None:
93                 raise forms.ValidationError(_("Please enter a correct username and password. Note that both fields are case-sensitive."))
94-            elif not self.user_cache.is_active:
95-                raise forms.ValidationError(_("This account is inactive."))
96+            else:
97+                self.confirm_login_allowed(self.user_cache)
98         self.check_for_test_cookie()
99         return self.cleaned_data
100 
101@@ -96,6 +96,19 @@
102                 _("Your Web browser doesn't appear to have cookies enabled. "
103                   "Cookies are required for logging in."))
104 
105+    def confirm_login_allowed(self, user):
106+        """
107+        Controls whether the given ``auth.User`` object may log in. This is a policy setting,
108+        independent of end-user authentication. This default behavior is to allow login by
109+        active users, and reject login by inactive users.
110+
111+        If the given user cannot log in, this method should raise a ``forms.ValidationError``.
112+
113+        If the given user may log in, this method should return None.
114+        """
115+        if not user.is_active:
116+            raise forms.ValidationError(_("This account is inactive."))
117+
118     def get_user_id(self):
119         if self.user_cache:
120             return self.user_cache.id