Fixed #23155 -- Added request argument to user_login_failed signal.
This commit is contained in:
parent
4b9330ccc0
commit
f0f3de3c96
|
@ -94,7 +94,7 @@ def authenticate(request=None, **credentials):
|
|||
return user
|
||||
|
||||
# The credentials supplied are invalid to all backends, fire signal
|
||||
user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials))
|
||||
user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials), request=request)
|
||||
|
||||
|
||||
def login(request, user, backend=None):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from django.dispatch import Signal
|
||||
|
||||
user_logged_in = Signal(providing_args=['request', 'user'])
|
||||
user_login_failed = Signal(providing_args=['credentials'])
|
||||
user_login_failed = Signal(providing_args=['credentials', 'request'])
|
||||
user_logged_out = Signal(providing_args=['request', 'user'])
|
||||
|
|
|
@ -479,6 +479,14 @@ can be used for notification when a user logs in or out.
|
|||
authentication backend. Credentials matching a set of 'sensitive' patterns,
|
||||
(including password) will not be sent in the clear as part of the signal.
|
||||
|
||||
``request``
|
||||
The :class:`~django.http.HttpRequest` object, if one was provided to
|
||||
:func:`~django.contrib.auth.authenticate`.
|
||||
|
||||
.. versionchanged:: 1.11
|
||||
|
||||
The ``request`` argument was added.
|
||||
|
||||
.. _authentication-backends-reference:
|
||||
|
||||
Authentication backends
|
||||
|
|
|
@ -117,6 +117,9 @@ Minor features
|
|||
which in turn passes it to the authentication backend if it accepts a
|
||||
``request`` argument.
|
||||
|
||||
* The :func:`~django.contrib.auth.signals.user_login_failed` signal now
|
||||
receives a ``request`` argument.
|
||||
|
||||
:mod:`django.contrib.contenttypes`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ from django.contrib.auth.forms import (
|
|||
SetPasswordForm, UserChangeForm, UserCreationForm,
|
||||
)
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.signals import user_login_failed
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core import mail
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
|
@ -279,6 +280,24 @@ class AuthenticationFormTest(TestDataMixin, TestCase):
|
|||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(form.non_field_errors(), [force_text(form.error_messages['inactive'])])
|
||||
|
||||
def test_login_failed(self):
|
||||
signal_calls = []
|
||||
|
||||
def signal_handler(**kwargs):
|
||||
signal_calls.append(kwargs)
|
||||
|
||||
user_login_failed.connect(signal_handler)
|
||||
fake_request = object()
|
||||
try:
|
||||
form = AuthenticationForm(fake_request, {
|
||||
'username': 'testclient',
|
||||
'password': 'incorrect',
|
||||
})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertIs(signal_calls[0]['request'], fake_request)
|
||||
finally:
|
||||
user_login_failed.disconnect(signal_handler)
|
||||
|
||||
def test_inactive_user_i18n(self):
|
||||
with self.settings(USE_I18N=True), translation.override('pt-br', deactivate=True):
|
||||
# The user is inactive.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from django.contrib.auth import signals
|
||||
from django.contrib.auth import authenticate, signals
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test.client import RequestFactory
|
||||
|
@ -18,8 +18,8 @@ class SignalTestCase(TestCase):
|
|||
def listener_logout(self, user, **kwargs):
|
||||
self.logged_out.append(user)
|
||||
|
||||
def listener_login_failed(self, sender, credentials, **kwargs):
|
||||
self.login_failed.append(credentials)
|
||||
def listener_login_failed(self, sender, **kwargs):
|
||||
self.login_failed.append(kwargs)
|
||||
|
||||
def setUp(self):
|
||||
"""Set up the listeners and reset the logged in/logged out counters"""
|
||||
|
@ -41,9 +41,10 @@ class SignalTestCase(TestCase):
|
|||
self.client.login(username='testclient', password='bad')
|
||||
self.assertEqual(len(self.logged_in), 0)
|
||||
self.assertEqual(len(self.login_failed), 1)
|
||||
self.assertEqual(self.login_failed[0]['username'], 'testclient')
|
||||
self.assertEqual(self.login_failed[0]['credentials']['username'], 'testclient')
|
||||
# verify the password is cleansed
|
||||
self.assertIn('***', self.login_failed[0]['password'])
|
||||
self.assertIn('***', self.login_failed[0]['credentials']['password'])
|
||||
self.assertIn('request', self.login_failed[0])
|
||||
|
||||
# Like this:
|
||||
self.client.login(username='testclient', password='password')
|
||||
|
@ -77,3 +78,7 @@ class SignalTestCase(TestCase):
|
|||
user.refresh_from_db()
|
||||
self.assertEqual(user.username, 'staff')
|
||||
self.assertNotEqual(user.last_login, old_last_login)
|
||||
|
||||
def test_failed_login_without_request(self):
|
||||
authenticate(username='testclient', password='bad')
|
||||
self.assertIsNone(self.login_failed[0]['request'])
|
||||
|
|
Loading…
Reference in New Issue