diff --git a/loginas/tests/tests.py b/loginas/tests/tests.py index bfe4888..2966fab 100644 --- a/loginas/tests/tests.py +++ b/loginas/tests/tests.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals +import unittest from datetime import timedelta +import django from django.conf import settings as django_settings from django.contrib.auth.models import User from django.contrib.messages.storage.cookie import CookieStorage @@ -66,6 +68,16 @@ def can_login_as_always_raise_permission_denied(request, user): raise PermissionDenied("You can't login as target user") +class WrongAuthBackend: + """ + An authentication backend is a class that implements two required methods: get_user(user_id) and + authenticate(**credentials). Unfortunately, some libraries don't comply with this interface (e.g. + `django-rules` with ObjectPermissionBackend) and omit the required `get_user` method. + """ + def authenticate(self, *args, **kwargs): + return None + + class ViewTest(TestCase): """Tests for user_login view""" @@ -185,6 +197,19 @@ def test_as_non_superuser(self): self.assertLoginError(self.get_target_url()) self.assertCurrentUserIs(user) + @unittest.skipIf(django.VERSION[:2] < (1, 10), "Django < 1.10 allows to authenticate as inactive user") + def test_auth_backends_user_not_found(self): + superuser = create_user("me", "pass", is_superuser=True, is_staff=True) + self.assertTrue(self.client.login(username="me", password="pass")) + self.assertCurrentUserIs(superuser) + # ModelBackend should authenticate superuser but prevent this action for inactive user + inactive_user = create_user("name", "pass", is_active=False) + with self.settings(AUTHENTICATION_BACKENDS=('django.contrib.auth.backends.ModelBackend', + 'tests.WrongAuthBackend',)): + message = "Could not find an appropriate authentication backend" + self.assertLoginError(self.get_target_url(target_user=inactive_user), message=message) + self.assertCurrentUserIs(superuser) + @override_settings(CAN_LOGIN_AS=can_login_as_always_raise_permission_denied) def test_can_login_as_permission_denied(self): message = "You can't login as target user" diff --git a/loginas/utils.py b/loginas/utils.py index b35a7f7..f3ef883 100644 --- a/loginas/utils.py +++ b/loginas/utils.py @@ -57,7 +57,7 @@ def login_as(user, request, store_original_user=True): user.backend = backend break else: - raise ImproperlyConfigured("Could not found an appropriate authentication backend") + raise ImproperlyConfigured("Could not find an appropriate authentication backend") # Add admin audit log entry if original_user_pk: diff --git a/loginas/views.py b/loginas/views.py index 831586c..06a8f9a 100644 --- a/loginas/views.py +++ b/loginas/views.py @@ -55,7 +55,6 @@ def user_login(request, user_id): can_login_as = la_settings.CAN_LOGIN_AS else: raise ImproperlyConfigured("The CAN_LOGIN_AS setting is neither a valid module nor callable.") - no_permission_error = None try: if not can_login_as(request, user): @@ -71,7 +70,16 @@ def user_login(request, user_id): ) return redirect(request.META.get("HTTP_REFERER", "/")) - login_as(user, request) + try: + login_as(user, request) + except ImproperlyConfigured as e: + messages.error( + request, + str(e), + extra_tags=la_settings.MESSAGE_EXTRA_TAGS, + fail_silently=True, + ) + return redirect(request.META.get("HTTP_REFERER", "/")) return redirect(la_settings.LOGIN_REDIRECT)