Fixed #18998 - Prevented session crash when auth backend removed

Removing a backend configured in AUTHENTICATION_BACKENDS should not
raise an exception for existing sessions, but should make already
logged-in users disconnect.
Thanks Bradley Ayers for the report.
This commit is contained in:
Jorge Bastida 2013-05-18 13:46:31 +02:00 committed by Claude Paroz
parent a0c0cc924e
commit dc43fbc2f2
3 changed files with 56 additions and 2 deletions

View File

@ -92,6 +92,7 @@ answer newbie questions, and generally made Django that much better:
Randy Barlow <randy@electronsweatshop.com> Randy Barlow <randy@electronsweatshop.com>
Scott Barr <scott@divisionbyzero.com.au> Scott Barr <scott@divisionbyzero.com.au>
Jiri Barton Jiri Barton
Jorge Bastida <me@jorgebastida.com>
Ned Batchelder <http://www.nedbatchelder.com/> Ned Batchelder <http://www.nedbatchelder.com/>
batiste@dosimple.ch batiste@dosimple.ch
Batman Batman

View File

@ -120,12 +120,14 @@ def get_user_model():
def get_user(request): def get_user(request):
from django.conf import settings
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
try: try:
user_id = request.session[SESSION_KEY] user_id = request.session[SESSION_KEY]
backend_path = request.session[BACKEND_SESSION_KEY] backend_path = request.session[BACKEND_SESSION_KEY]
assert backend_path in settings.AUTHENTICATION_BACKENDS
backend = load_backend(backend_path) backend = load_backend(backend_path)
user = backend.get_user(user_id) or AnonymousUser() user = backend.get_user(user_id) or AnonymousUser()
except KeyError: except (KeyError, AssertionError):
user = AnonymousUser() user = AnonymousUser()
return user return user

View File

@ -2,12 +2,14 @@ from __future__ import unicode_literals
from datetime import date from datetime import date
from django.conf import settings from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User, Group, Permission, AnonymousUser from django.contrib.auth.models import User, Group, Permission, AnonymousUser
from django.contrib.auth.tests.utils import skipIfCustomUser from django.contrib.auth.tests.utils import skipIfCustomUser
from django.contrib.auth.tests.test_custom_user import ExtensionUser, CustomPermissionsUser, CustomUser from django.contrib.auth.tests.test_custom_user import ExtensionUser, CustomPermissionsUser, CustomUser
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.contrib.auth import authenticate from django.contrib.auth import authenticate, get_user
from django.http import HttpRequest
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
@ -402,3 +404,52 @@ class PermissionDeniedBackendTest(TestCase):
settings.AUTHENTICATION_BACKENDS) + (backend, )) settings.AUTHENTICATION_BACKENDS) + (backend, ))
def test_authenticates(self): def test_authenticates(self):
self.assertEqual(authenticate(username='test', password='test'), self.user1) self.assertEqual(authenticate(username='test', password='test'), self.user1)
class NewModelBackend(ModelBackend):
pass
@skipIfCustomUser
class ChangedBackendSettingsTest(TestCase):
"""
Tests for changes in the settings.AUTHENTICATION_BACKENDS
"""
backend = 'django.contrib.auth.tests.test_auth_backends.NewModelBackend'
TEST_USERNAME = 'test_user'
TEST_PASSWORD = 'test_password'
TEST_EMAIL = 'test@example.com'
def setUp(self):
User.objects.create_user(self.TEST_USERNAME,
self.TEST_EMAIL,
self.TEST_PASSWORD)
@override_settings(AUTHENTICATION_BACKENDS=(backend, ))
def test_changed_backend_settings(self):
"""
Tests that removing a backend configured in AUTHENTICATION_BACKENDS
make already logged-in users disconnect.
"""
# Get a session for the test user
self.assertTrue(self.client.login(
username=self.TEST_USERNAME,
password=self.TEST_PASSWORD)
)
# Prepare a request object
request = HttpRequest()
request.session = self.client.session
# Remove NewModelBackend
with self.settings(AUTHENTICATION_BACKENDS=(
'django.contrib.auth.backends.ModelBackend',)):
# Get the user from the request
user = get_user(request)
# Assert that the user retrieval is successful and the user is
# anonymous as the backend is not longer available.
self.assertIsNotNone(user)
self.assertTrue(user.is_anonymous())