Fixed #18171 -- Checked signature of authenticate() to avoid supressing TypeErrors.

The current auth backend code catches TypeError to detect backends that
do not support specified argumetnts. As a result, any TypeErrors raised
within the actual backend code are silenced.

In Python 2.7+ and 3.2+ this can be avoided by using inspect.getcallargs().
With this method, we can test whether arguments match the signature without
actually calling the function.

Thanks David Eyk for the report.
This commit is contained in:
Michał Górny 2013-08-23 17:49:42 +02:00 committed by Tim Graham
parent 5b889b2408
commit b89c2a5d9e
2 changed files with 34 additions and 1 deletions

View File

@ -1,3 +1,4 @@
import inspect
import re
from django.conf import settings
@ -46,10 +47,13 @@ def authenticate(**credentials):
"""
for backend in get_backends():
try:
user = backend.authenticate(**credentials)
inspect.getcallargs(backend.authenticate, **credentials)
except TypeError:
# This backend doesn't accept these credentials as arguments. Try the next one.
continue
try:
user = backend.authenticate(**credentials)
except PermissionDenied:
# This backend says to stop in our tracks - this user should not be allowed in at all.
return None

View File

@ -480,3 +480,32 @@ class ChangedBackendSettingsTest(TestCase):
# anonymous as the backend is not longer available.
self.assertIsNotNone(user)
self.assertTrue(user.is_anonymous())
class TypeErrorBackend(object):
"""
Always raises TypeError.
"""
supports_object_permissions = True
supports_anonymous_user = True
supports_inactive_user = True
def authenticate(self, username=None, password=None):
raise TypeError
@skipIfCustomUser
class TypeErrorBackendTest(TestCase):
"""
Tests that a TypeError within a backend is propagated properly.
Regression test for ticket #18171
"""
backend = 'django.contrib.auth.tests.test_auth_backends.TypeErrorBackend'
def setUp(self):
self.user1 = User.objects.create_user('test', 'test@example.com', 'test')
@override_settings(AUTHENTICATION_BACKENDS=(backend, ))
def test_type_error_raised(self):
self.assertRaises(TypeError, authenticate, username='test', password='test')