From dc43fbc2f21c12e34e309d0e8a121020391aa03a Mon Sep 17 00:00:00 2001 From: Jorge Bastida Date: Sat, 18 May 2013 13:46:31 +0200 Subject: [PATCH] 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. --- AUTHORS | 1 + django/contrib/auth/__init__.py | 4 +- .../contrib/auth/tests/test_auth_backends.py | 53 ++++++++++++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 0ad6522725..e83fc035a3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -92,6 +92,7 @@ answer newbie questions, and generally made Django that much better: Randy Barlow Scott Barr Jiri Barton + Jorge Bastida Ned Batchelder batiste@dosimple.ch Batman diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py index ef9066657d..17f6b895c7 100644 --- a/django/contrib/auth/__init__.py +++ b/django/contrib/auth/__init__.py @@ -120,12 +120,14 @@ def get_user_model(): def get_user(request): + from django.conf import settings from django.contrib.auth.models import AnonymousUser try: user_id = request.session[SESSION_KEY] backend_path = request.session[BACKEND_SESSION_KEY] + assert backend_path in settings.AUTHENTICATION_BACKENDS backend = load_backend(backend_path) user = backend.get_user(user_id) or AnonymousUser() - except KeyError: + except (KeyError, AssertionError): user = AnonymousUser() return user diff --git a/django/contrib/auth/tests/test_auth_backends.py b/django/contrib/auth/tests/test_auth_backends.py index bb97c54a11..fc5a80e8dd 100644 --- a/django/contrib/auth/tests/test_auth_backends.py +++ b/django/contrib/auth/tests/test_auth_backends.py @@ -2,12 +2,14 @@ from __future__ import unicode_literals from datetime import date 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.tests.utils import skipIfCustomUser from django.contrib.auth.tests.test_custom_user import ExtensionUser, CustomPermissionsUser, CustomUser from django.contrib.contenttypes.models import ContentType 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.utils import override_settings @@ -402,3 +404,52 @@ class PermissionDeniedBackendTest(TestCase): settings.AUTHENTICATION_BACKENDS) + (backend, )) def test_authenticates(self): 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())