mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			935 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			935 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import sys
 | |
| from datetime import date
 | |
| from unittest import mock
 | |
| 
 | |
| from django.contrib.auth import (
 | |
|     BACKEND_SESSION_KEY,
 | |
|     SESSION_KEY,
 | |
|     _clean_credentials,
 | |
|     authenticate,
 | |
|     get_user,
 | |
|     signals,
 | |
| )
 | |
| from django.contrib.auth.backends import BaseBackend, ModelBackend
 | |
| from django.contrib.auth.hashers import MD5PasswordHasher
 | |
| from django.contrib.auth.models import AnonymousUser, Group, Permission, User
 | |
| from django.contrib.contenttypes.models import ContentType
 | |
| from django.core.exceptions import ImproperlyConfigured, PermissionDenied
 | |
| from django.http import HttpRequest
 | |
| from django.test import (
 | |
|     RequestFactory,
 | |
|     SimpleTestCase,
 | |
|     TestCase,
 | |
|     modify_settings,
 | |
|     override_settings,
 | |
| )
 | |
| from django.views.debug import technical_500_response
 | |
| from django.views.decorators.debug import sensitive_variables
 | |
| 
 | |
| from .models import (
 | |
|     CustomPermissionsUser,
 | |
|     CustomUser,
 | |
|     CustomUserWithoutIsActiveField,
 | |
|     ExtensionUser,
 | |
|     UUIDUser,
 | |
| )
 | |
| 
 | |
| 
 | |
| class SimpleBackend(BaseBackend):
 | |
|     def get_user_permissions(self, user_obj, obj=None):
 | |
|         return ["user_perm"]
 | |
| 
 | |
|     def get_group_permissions(self, user_obj, obj=None):
 | |
|         return ["group_perm"]
 | |
| 
 | |
| 
 | |
| @override_settings(
 | |
|     AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.SimpleBackend"]
 | |
| )
 | |
| class BaseBackendTest(TestCase):
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         cls.user = User.objects.create_user("test", "test@example.com", "test")
 | |
| 
 | |
|     def test_get_user_permissions(self):
 | |
|         self.assertEqual(self.user.get_user_permissions(), {"user_perm"})
 | |
| 
 | |
|     def test_get_group_permissions(self):
 | |
|         self.assertEqual(self.user.get_group_permissions(), {"group_perm"})
 | |
| 
 | |
|     def test_get_all_permissions(self):
 | |
|         self.assertEqual(self.user.get_all_permissions(), {"user_perm", "group_perm"})
 | |
| 
 | |
|     def test_has_perm(self):
 | |
|         self.assertIs(self.user.has_perm("user_perm"), True)
 | |
|         self.assertIs(self.user.has_perm("group_perm"), True)
 | |
|         self.assertIs(self.user.has_perm("other_perm", TestObj()), False)
 | |
| 
 | |
|     def test_has_perms_perm_list_invalid(self):
 | |
|         msg = "perm_list must be an iterable of permissions."
 | |
|         with self.assertRaisesMessage(ValueError, msg):
 | |
|             self.user.has_perms("user_perm")
 | |
|         with self.assertRaisesMessage(ValueError, msg):
 | |
|             self.user.has_perms(object())
 | |
| 
 | |
| 
 | |
| class CountingMD5PasswordHasher(MD5PasswordHasher):
 | |
|     """Hasher that counts how many times it computes a hash."""
 | |
| 
 | |
|     calls = 0
 | |
| 
 | |
|     def encode(self, *args, **kwargs):
 | |
|         type(self).calls += 1
 | |
|         return super().encode(*args, **kwargs)
 | |
| 
 | |
| 
 | |
| class BaseModelBackendTest:
 | |
|     """
 | |
|     A base class for tests that need to validate the ModelBackend
 | |
|     with different User models. Subclasses should define a class
 | |
|     level UserModel attribute, and a create_users() method to
 | |
|     construct two users for test purposes.
 | |
|     """
 | |
| 
 | |
|     backend = "django.contrib.auth.backends.ModelBackend"
 | |
| 
 | |
|     def setUp(self):
 | |
|         self.patched_settings = modify_settings(
 | |
|             AUTHENTICATION_BACKENDS={"append": self.backend},
 | |
|         )
 | |
|         self.patched_settings.enable()
 | |
|         self.create_users()
 | |
| 
 | |
|     def tearDown(self):
 | |
|         self.patched_settings.disable()
 | |
|         # The custom_perms test messes with ContentTypes, which will
 | |
|         # be cached; flush the cache to ensure there are no side effects
 | |
|         # Refs #14975, #14925
 | |
|         ContentType.objects.clear_cache()
 | |
| 
 | |
|     def test_has_perm(self):
 | |
|         user = self.UserModel._default_manager.get(pk=self.user.pk)
 | |
|         self.assertIs(user.has_perm("auth.test"), False)
 | |
| 
 | |
|         user.is_staff = True
 | |
|         user.save()
 | |
|         self.assertIs(user.has_perm("auth.test"), False)
 | |
| 
 | |
|         user.is_superuser = True
 | |
|         user.save()
 | |
|         self.assertIs(user.has_perm("auth.test"), True)
 | |
| 
 | |
|         user.is_staff = True
 | |
|         user.is_superuser = True
 | |
|         user.is_active = False
 | |
|         user.save()
 | |
|         self.assertIs(user.has_perm("auth.test"), False)
 | |
| 
 | |
|     def test_custom_perms(self):
 | |
|         user = self.UserModel._default_manager.get(pk=self.user.pk)
 | |
|         content_type = ContentType.objects.get_for_model(Group)
 | |
|         perm = Permission.objects.create(
 | |
|             name="test", content_type=content_type, codename="test"
 | |
|         )
 | |
|         user.user_permissions.add(perm)
 | |
| 
 | |
|         # reloading user to purge the _perm_cache
 | |
|         user = self.UserModel._default_manager.get(pk=self.user.pk)
 | |
|         self.assertEqual(user.get_all_permissions(), {"auth.test"})
 | |
|         self.assertEqual(user.get_user_permissions(), {"auth.test"})
 | |
|         self.assertEqual(user.get_group_permissions(), set())
 | |
|         self.assertIs(user.has_module_perms("Group"), False)
 | |
|         self.assertIs(user.has_module_perms("auth"), True)
 | |
| 
 | |
|         perm = Permission.objects.create(
 | |
|             name="test2", content_type=content_type, codename="test2"
 | |
|         )
 | |
|         user.user_permissions.add(perm)
 | |
|         perm = Permission.objects.create(
 | |
|             name="test3", content_type=content_type, codename="test3"
 | |
|         )
 | |
|         user.user_permissions.add(perm)
 | |
|         user = self.UserModel._default_manager.get(pk=self.user.pk)
 | |
|         expected_user_perms = {"auth.test2", "auth.test", "auth.test3"}
 | |
|         self.assertEqual(user.get_all_permissions(), expected_user_perms)
 | |
|         self.assertIs(user.has_perm("test"), False)
 | |
|         self.assertIs(user.has_perm("auth.test"), True)
 | |
|         self.assertIs(user.has_perms(["auth.test2", "auth.test3"]), True)
 | |
| 
 | |
|         perm = Permission.objects.create(
 | |
|             name="test_group", content_type=content_type, codename="test_group"
 | |
|         )
 | |
|         group = Group.objects.create(name="test_group")
 | |
|         group.permissions.add(perm)
 | |
|         user.groups.add(group)
 | |
|         user = self.UserModel._default_manager.get(pk=self.user.pk)
 | |
|         self.assertEqual(
 | |
|             user.get_all_permissions(), {*expected_user_perms, "auth.test_group"}
 | |
|         )
 | |
|         self.assertEqual(user.get_user_permissions(), expected_user_perms)
 | |
|         self.assertEqual(user.get_group_permissions(), {"auth.test_group"})
 | |
|         self.assertIs(user.has_perms(["auth.test3", "auth.test_group"]), True)
 | |
| 
 | |
|         user = AnonymousUser()
 | |
|         self.assertIs(user.has_perm("test"), False)
 | |
|         self.assertIs(user.has_perms(["auth.test2", "auth.test3"]), False)
 | |
| 
 | |
|     def test_has_no_object_perm(self):
 | |
|         """Regressiontest for #12462"""
 | |
|         user = self.UserModel._default_manager.get(pk=self.user.pk)
 | |
|         content_type = ContentType.objects.get_for_model(Group)
 | |
|         perm = Permission.objects.create(
 | |
|             name="test", content_type=content_type, codename="test"
 | |
|         )
 | |
|         user.user_permissions.add(perm)
 | |
| 
 | |
|         self.assertIs(user.has_perm("auth.test", "object"), False)
 | |
|         self.assertEqual(user.get_all_permissions("object"), set())
 | |
|         self.assertIs(user.has_perm("auth.test"), True)
 | |
|         self.assertEqual(user.get_all_permissions(), {"auth.test"})
 | |
| 
 | |
|     def test_anonymous_has_no_permissions(self):
 | |
|         """
 | |
|         #17903 -- Anonymous users shouldn't have permissions in
 | |
|         ModelBackend.get_(all|user|group)_permissions().
 | |
|         """
 | |
|         backend = ModelBackend()
 | |
| 
 | |
|         user = self.UserModel._default_manager.get(pk=self.user.pk)
 | |
|         content_type = ContentType.objects.get_for_model(Group)
 | |
|         user_perm = Permission.objects.create(
 | |
|             name="test", content_type=content_type, codename="test_user"
 | |
|         )
 | |
|         group_perm = Permission.objects.create(
 | |
|             name="test2", content_type=content_type, codename="test_group"
 | |
|         )
 | |
|         user.user_permissions.add(user_perm)
 | |
| 
 | |
|         group = Group.objects.create(name="test_group")
 | |
|         user.groups.add(group)
 | |
|         group.permissions.add(group_perm)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             backend.get_all_permissions(user), {"auth.test_user", "auth.test_group"}
 | |
|         )
 | |
|         self.assertEqual(backend.get_user_permissions(user), {"auth.test_user"})
 | |
|         self.assertEqual(backend.get_group_permissions(user), {"auth.test_group"})
 | |
| 
 | |
|         with mock.patch.object(self.UserModel, "is_anonymous", True):
 | |
|             self.assertEqual(backend.get_all_permissions(user), set())
 | |
|             self.assertEqual(backend.get_user_permissions(user), set())
 | |
|             self.assertEqual(backend.get_group_permissions(user), set())
 | |
| 
 | |
|     def test_inactive_has_no_permissions(self):
 | |
|         """
 | |
|         #17903 -- Inactive users shouldn't have permissions in
 | |
|         ModelBackend.get_(all|user|group)_permissions().
 | |
|         """
 | |
|         backend = ModelBackend()
 | |
| 
 | |
|         user = self.UserModel._default_manager.get(pk=self.user.pk)
 | |
|         content_type = ContentType.objects.get_for_model(Group)
 | |
|         user_perm = Permission.objects.create(
 | |
|             name="test", content_type=content_type, codename="test_user"
 | |
|         )
 | |
|         group_perm = Permission.objects.create(
 | |
|             name="test2", content_type=content_type, codename="test_group"
 | |
|         )
 | |
|         user.user_permissions.add(user_perm)
 | |
| 
 | |
|         group = Group.objects.create(name="test_group")
 | |
|         user.groups.add(group)
 | |
|         group.permissions.add(group_perm)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             backend.get_all_permissions(user), {"auth.test_user", "auth.test_group"}
 | |
|         )
 | |
|         self.assertEqual(backend.get_user_permissions(user), {"auth.test_user"})
 | |
|         self.assertEqual(backend.get_group_permissions(user), {"auth.test_group"})
 | |
| 
 | |
|         user.is_active = False
 | |
|         user.save()
 | |
| 
 | |
|         self.assertEqual(backend.get_all_permissions(user), set())
 | |
|         self.assertEqual(backend.get_user_permissions(user), set())
 | |
|         self.assertEqual(backend.get_group_permissions(user), set())
 | |
| 
 | |
|     def test_get_all_superuser_permissions(self):
 | |
|         """A superuser has all permissions. Refs #14795."""
 | |
|         user = self.UserModel._default_manager.get(pk=self.superuser.pk)
 | |
|         self.assertEqual(len(user.get_all_permissions()), len(Permission.objects.all()))
 | |
| 
 | |
|     @override_settings(
 | |
|         PASSWORD_HASHERS=["auth_tests.test_auth_backends.CountingMD5PasswordHasher"]
 | |
|     )
 | |
|     def test_authentication_timing(self):
 | |
|         """Hasher is run once regardless of whether the user exists. Refs #20760."""
 | |
|         # Re-set the password, because this tests overrides PASSWORD_HASHERS
 | |
|         self.user.set_password("test")
 | |
|         self.user.save()
 | |
| 
 | |
|         CountingMD5PasswordHasher.calls = 0
 | |
|         username = getattr(self.user, self.UserModel.USERNAME_FIELD)
 | |
|         authenticate(username=username, password="test")
 | |
|         self.assertEqual(CountingMD5PasswordHasher.calls, 1)
 | |
| 
 | |
|         CountingMD5PasswordHasher.calls = 0
 | |
|         authenticate(username="no_such_user", password="test")
 | |
|         self.assertEqual(CountingMD5PasswordHasher.calls, 1)
 | |
| 
 | |
|     @override_settings(
 | |
|         PASSWORD_HASHERS=["auth_tests.test_auth_backends.CountingMD5PasswordHasher"]
 | |
|     )
 | |
|     def test_authentication_without_credentials(self):
 | |
|         CountingMD5PasswordHasher.calls = 0
 | |
|         for credentials in (
 | |
|             {},
 | |
|             {"username": getattr(self.user, self.UserModel.USERNAME_FIELD)},
 | |
|             {"password": "test"},
 | |
|         ):
 | |
|             with self.subTest(credentials=credentials):
 | |
|                 with self.assertNumQueries(0):
 | |
|                     authenticate(**credentials)
 | |
|                 self.assertEqual(CountingMD5PasswordHasher.calls, 0)
 | |
| 
 | |
| 
 | |
| class ModelBackendTest(BaseModelBackendTest, TestCase):
 | |
|     """
 | |
|     Tests for the ModelBackend using the default User model.
 | |
|     """
 | |
| 
 | |
|     UserModel = User
 | |
|     user_credentials = {"username": "test", "password": "test"}
 | |
| 
 | |
|     def create_users(self):
 | |
|         self.user = User.objects.create_user(
 | |
|             email="test@example.com", **self.user_credentials
 | |
|         )
 | |
|         self.superuser = User.objects.create_superuser(
 | |
|             username="test2",
 | |
|             email="test2@example.com",
 | |
|             password="test",
 | |
|         )
 | |
| 
 | |
|     def test_authenticate_inactive(self):
 | |
|         """
 | |
|         An inactive user can't authenticate.
 | |
|         """
 | |
|         self.assertEqual(authenticate(**self.user_credentials), self.user)
 | |
|         self.user.is_active = False
 | |
|         self.user.save()
 | |
|         self.assertIsNone(authenticate(**self.user_credentials))
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithoutIsActiveField")
 | |
|     def test_authenticate_user_without_is_active_field(self):
 | |
|         """
 | |
|         A custom user without an `is_active` field is allowed to authenticate.
 | |
|         """
 | |
|         user = CustomUserWithoutIsActiveField.objects._create_user(
 | |
|             username="test",
 | |
|             email="test@example.com",
 | |
|             password="test",
 | |
|         )
 | |
|         self.assertEqual(authenticate(username="test", password="test"), user)
 | |
| 
 | |
| 
 | |
| @override_settings(AUTH_USER_MODEL="auth_tests.ExtensionUser")
 | |
| class ExtensionUserModelBackendTest(BaseModelBackendTest, TestCase):
 | |
|     """
 | |
|     Tests for the ModelBackend using the custom ExtensionUser model.
 | |
| 
 | |
|     This isn't a perfect test, because both the User and ExtensionUser are
 | |
|     synchronized to the database, which wouldn't ordinary happen in
 | |
|     production. As a result, it doesn't catch errors caused by the non-
 | |
|     existence of the User table.
 | |
| 
 | |
|     The specific problem is queries on .filter(groups__user) et al, which
 | |
|     makes an implicit assumption that the user model is called 'User'. In
 | |
|     production, the auth.User table won't exist, so the requested join
 | |
|     won't exist either; in testing, the auth.User *does* exist, and
 | |
|     so does the join. However, the join table won't contain any useful
 | |
|     data; for testing, we check that the data we expect actually does exist.
 | |
|     """
 | |
| 
 | |
|     UserModel = ExtensionUser
 | |
| 
 | |
|     def create_users(self):
 | |
|         self.user = ExtensionUser._default_manager.create_user(
 | |
|             username="test",
 | |
|             email="test@example.com",
 | |
|             password="test",
 | |
|             date_of_birth=date(2006, 4, 25),
 | |
|         )
 | |
|         self.superuser = ExtensionUser._default_manager.create_superuser(
 | |
|             username="test2",
 | |
|             email="test2@example.com",
 | |
|             password="test",
 | |
|             date_of_birth=date(1976, 11, 8),
 | |
|         )
 | |
| 
 | |
| 
 | |
| @override_settings(AUTH_USER_MODEL="auth_tests.CustomPermissionsUser")
 | |
| class CustomPermissionsUserModelBackendTest(BaseModelBackendTest, TestCase):
 | |
|     """
 | |
|     Tests for the ModelBackend using the CustomPermissionsUser model.
 | |
| 
 | |
|     As with the ExtensionUser test, this isn't a perfect test, because both
 | |
|     the User and CustomPermissionsUser are synchronized to the database,
 | |
|     which wouldn't ordinary happen in production.
 | |
|     """
 | |
| 
 | |
|     UserModel = CustomPermissionsUser
 | |
| 
 | |
|     def create_users(self):
 | |
|         self.user = CustomPermissionsUser._default_manager.create_user(
 | |
|             email="test@example.com", password="test", date_of_birth=date(2006, 4, 25)
 | |
|         )
 | |
|         self.superuser = CustomPermissionsUser._default_manager.create_superuser(
 | |
|             email="test2@example.com", password="test", date_of_birth=date(1976, 11, 8)
 | |
|         )
 | |
| 
 | |
| 
 | |
| @override_settings(AUTH_USER_MODEL="auth_tests.CustomUser")
 | |
| class CustomUserModelBackendAuthenticateTest(TestCase):
 | |
|     """
 | |
|     The model backend can accept a credentials kwarg labeled with
 | |
|     custom user model's USERNAME_FIELD.
 | |
|     """
 | |
| 
 | |
|     def test_authenticate(self):
 | |
|         test_user = CustomUser._default_manager.create_user(
 | |
|             email="test@example.com", password="test", date_of_birth=date(2006, 4, 25)
 | |
|         )
 | |
|         authenticated_user = authenticate(email="test@example.com", password="test")
 | |
|         self.assertEqual(test_user, authenticated_user)
 | |
| 
 | |
| 
 | |
| @override_settings(AUTH_USER_MODEL="auth_tests.UUIDUser")
 | |
| class UUIDUserTests(TestCase):
 | |
|     def test_login(self):
 | |
|         """
 | |
|         A custom user with a UUID primary key should be able to login.
 | |
|         """
 | |
|         user = UUIDUser.objects.create_user(username="uuid", password="test")
 | |
|         self.assertTrue(self.client.login(username="uuid", password="test"))
 | |
|         self.assertEqual(
 | |
|             UUIDUser.objects.get(pk=self.client.session[SESSION_KEY]), user
 | |
|         )
 | |
| 
 | |
| 
 | |
| class TestObj:
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class SimpleRowlevelBackend:
 | |
|     def has_perm(self, user, perm, obj=None):
 | |
|         if not obj:
 | |
|             return  # We only support row level perms
 | |
| 
 | |
|         if isinstance(obj, TestObj):
 | |
|             if user.username == "test2":
 | |
|                 return True
 | |
|             elif user.is_anonymous and perm == "anon":
 | |
|                 return True
 | |
|             elif not user.is_active and perm == "inactive":
 | |
|                 return True
 | |
|         return False
 | |
| 
 | |
|     def has_module_perms(self, user, app_label):
 | |
|         return (user.is_anonymous or user.is_active) and app_label == "app1"
 | |
| 
 | |
|     def get_all_permissions(self, user, obj=None):
 | |
|         if not obj:
 | |
|             return []  # We only support row level perms
 | |
| 
 | |
|         if not isinstance(obj, TestObj):
 | |
|             return ["none"]
 | |
| 
 | |
|         if user.is_anonymous:
 | |
|             return ["anon"]
 | |
|         if user.username == "test2":
 | |
|             return ["simple", "advanced"]
 | |
|         else:
 | |
|             return ["simple"]
 | |
| 
 | |
|     def get_group_permissions(self, user, obj=None):
 | |
|         if not obj:
 | |
|             return  # We only support row level perms
 | |
| 
 | |
|         if not isinstance(obj, TestObj):
 | |
|             return ["none"]
 | |
| 
 | |
|         if "test_group" in [group.name for group in user.groups.all()]:
 | |
|             return ["group_perm"]
 | |
|         else:
 | |
|             return ["none"]
 | |
| 
 | |
| 
 | |
| @modify_settings(
 | |
|     AUTHENTICATION_BACKENDS={
 | |
|         "append": "auth_tests.test_auth_backends.SimpleRowlevelBackend",
 | |
|     }
 | |
| )
 | |
| class RowlevelBackendTest(TestCase):
 | |
|     """
 | |
|     Tests for auth backend that supports object level permissions
 | |
|     """
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         cls.user1 = User.objects.create_user("test", "test@example.com", "test")
 | |
|         cls.user2 = User.objects.create_user("test2", "test2@example.com", "test")
 | |
|         cls.user3 = User.objects.create_user("test3", "test3@example.com", "test")
 | |
| 
 | |
|     def tearDown(self):
 | |
|         # The get_group_permissions test messes with ContentTypes, which will
 | |
|         # be cached; flush the cache to ensure there are no side effects
 | |
|         # Refs #14975, #14925
 | |
|         ContentType.objects.clear_cache()
 | |
| 
 | |
|     def test_has_perm(self):
 | |
|         self.assertIs(self.user1.has_perm("perm", TestObj()), False)
 | |
|         self.assertIs(self.user2.has_perm("perm", TestObj()), True)
 | |
|         self.assertIs(self.user2.has_perm("perm"), False)
 | |
|         self.assertIs(self.user2.has_perms(["simple", "advanced"], TestObj()), True)
 | |
|         self.assertIs(self.user3.has_perm("perm", TestObj()), False)
 | |
|         self.assertIs(self.user3.has_perm("anon", TestObj()), False)
 | |
|         self.assertIs(self.user3.has_perms(["simple", "advanced"], TestObj()), False)
 | |
| 
 | |
|     def test_get_all_permissions(self):
 | |
|         self.assertEqual(self.user1.get_all_permissions(TestObj()), {"simple"})
 | |
|         self.assertEqual(
 | |
|             self.user2.get_all_permissions(TestObj()), {"simple", "advanced"}
 | |
|         )
 | |
|         self.assertEqual(self.user2.get_all_permissions(), set())
 | |
| 
 | |
|     def test_get_group_permissions(self):
 | |
|         group = Group.objects.create(name="test_group")
 | |
|         self.user3.groups.add(group)
 | |
|         self.assertEqual(self.user3.get_group_permissions(TestObj()), {"group_perm"})
 | |
| 
 | |
| 
 | |
| @override_settings(
 | |
|     AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.SimpleRowlevelBackend"],
 | |
| )
 | |
| class AnonymousUserBackendTest(SimpleTestCase):
 | |
|     """
 | |
|     Tests for AnonymousUser delegating to backend.
 | |
|     """
 | |
| 
 | |
|     def setUp(self):
 | |
|         self.user1 = AnonymousUser()
 | |
| 
 | |
|     def test_has_perm(self):
 | |
|         self.assertIs(self.user1.has_perm("perm", TestObj()), False)
 | |
|         self.assertIs(self.user1.has_perm("anon", TestObj()), True)
 | |
| 
 | |
|     def test_has_perms(self):
 | |
|         self.assertIs(self.user1.has_perms(["anon"], TestObj()), True)
 | |
|         self.assertIs(self.user1.has_perms(["anon", "perm"], TestObj()), False)
 | |
| 
 | |
|     def test_has_perms_perm_list_invalid(self):
 | |
|         msg = "perm_list must be an iterable of permissions."
 | |
|         with self.assertRaisesMessage(ValueError, msg):
 | |
|             self.user1.has_perms("perm")
 | |
|         with self.assertRaisesMessage(ValueError, msg):
 | |
|             self.user1.has_perms(object())
 | |
| 
 | |
|     def test_has_module_perms(self):
 | |
|         self.assertIs(self.user1.has_module_perms("app1"), True)
 | |
|         self.assertIs(self.user1.has_module_perms("app2"), False)
 | |
| 
 | |
|     def test_get_all_permissions(self):
 | |
|         self.assertEqual(self.user1.get_all_permissions(TestObj()), {"anon"})
 | |
| 
 | |
| 
 | |
| @override_settings(AUTHENTICATION_BACKENDS=[])
 | |
| class NoBackendsTest(TestCase):
 | |
|     """
 | |
|     An appropriate error is raised if no auth backends are provided.
 | |
|     """
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         cls.user = User.objects.create_user("test", "test@example.com", "test")
 | |
| 
 | |
|     def test_raises_exception(self):
 | |
|         msg = (
 | |
|             "No authentication backends have been defined. "
 | |
|             "Does AUTHENTICATION_BACKENDS contain anything?"
 | |
|         )
 | |
|         with self.assertRaisesMessage(ImproperlyConfigured, msg):
 | |
|             self.user.has_perm(("perm", TestObj()))
 | |
| 
 | |
| 
 | |
| @override_settings(
 | |
|     AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.SimpleRowlevelBackend"]
 | |
| )
 | |
| class InActiveUserBackendTest(TestCase):
 | |
|     """
 | |
|     Tests for an inactive user
 | |
|     """
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         cls.user1 = User.objects.create_user("test", "test@example.com", "test")
 | |
|         cls.user1.is_active = False
 | |
|         cls.user1.save()
 | |
| 
 | |
|     def test_has_perm(self):
 | |
|         self.assertIs(self.user1.has_perm("perm", TestObj()), False)
 | |
|         self.assertIs(self.user1.has_perm("inactive", TestObj()), True)
 | |
| 
 | |
|     def test_has_module_perms(self):
 | |
|         self.assertIs(self.user1.has_module_perms("app1"), False)
 | |
|         self.assertIs(self.user1.has_module_perms("app2"), False)
 | |
| 
 | |
| 
 | |
| class PermissionDeniedBackend:
 | |
|     """
 | |
|     Always raises PermissionDenied in `authenticate`, `has_perm` and `has_module_perms`.
 | |
|     """
 | |
| 
 | |
|     def authenticate(self, request, username=None, password=None):
 | |
|         raise PermissionDenied
 | |
| 
 | |
|     def has_perm(self, user_obj, perm, obj=None):
 | |
|         raise PermissionDenied
 | |
| 
 | |
|     def has_module_perms(self, user_obj, app_label):
 | |
|         raise PermissionDenied
 | |
| 
 | |
| 
 | |
| class PermissionDeniedBackendTest(TestCase):
 | |
|     """
 | |
|     Other backends are not checked once a backend raises PermissionDenied
 | |
|     """
 | |
| 
 | |
|     backend = "auth_tests.test_auth_backends.PermissionDeniedBackend"
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         cls.user1 = User.objects.create_user("test", "test@example.com", "test")
 | |
| 
 | |
|     def setUp(self):
 | |
|         self.user_login_failed = []
 | |
|         signals.user_login_failed.connect(self.user_login_failed_listener)
 | |
| 
 | |
|     def tearDown(self):
 | |
|         signals.user_login_failed.disconnect(self.user_login_failed_listener)
 | |
| 
 | |
|     def user_login_failed_listener(self, sender, credentials, **kwargs):
 | |
|         self.user_login_failed.append(credentials)
 | |
| 
 | |
|     @modify_settings(AUTHENTICATION_BACKENDS={"prepend": backend})
 | |
|     def test_permission_denied(self):
 | |
|         "user is not authenticated after a backend raises permission denied #2550"
 | |
|         self.assertIsNone(authenticate(username="test", password="test"))
 | |
|         # user_login_failed signal is sent.
 | |
|         self.assertEqual(
 | |
|             self.user_login_failed,
 | |
|             [{"password": "********************", "username": "test"}],
 | |
|         )
 | |
| 
 | |
|     @modify_settings(AUTHENTICATION_BACKENDS={"append": backend})
 | |
|     def test_authenticates(self):
 | |
|         self.assertEqual(authenticate(username="test", password="test"), self.user1)
 | |
| 
 | |
|     @modify_settings(AUTHENTICATION_BACKENDS={"prepend": backend})
 | |
|     def test_has_perm_denied(self):
 | |
|         content_type = ContentType.objects.get_for_model(Group)
 | |
|         perm = Permission.objects.create(
 | |
|             name="test", content_type=content_type, codename="test"
 | |
|         )
 | |
|         self.user1.user_permissions.add(perm)
 | |
| 
 | |
|         self.assertIs(self.user1.has_perm("auth.test"), False)
 | |
|         self.assertIs(self.user1.has_module_perms("auth"), False)
 | |
| 
 | |
|     @modify_settings(AUTHENTICATION_BACKENDS={"append": backend})
 | |
|     def test_has_perm(self):
 | |
|         content_type = ContentType.objects.get_for_model(Group)
 | |
|         perm = Permission.objects.create(
 | |
|             name="test", content_type=content_type, codename="test"
 | |
|         )
 | |
|         self.user1.user_permissions.add(perm)
 | |
| 
 | |
|         self.assertIs(self.user1.has_perm("auth.test"), True)
 | |
|         self.assertIs(self.user1.has_module_perms("auth"), True)
 | |
| 
 | |
| 
 | |
| class NewModelBackend(ModelBackend):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class ChangedBackendSettingsTest(TestCase):
 | |
|     """
 | |
|     Tests for changes in the settings.AUTHENTICATION_BACKENDS
 | |
|     """
 | |
| 
 | |
|     backend = "auth_tests.test_auth_backends.NewModelBackend"
 | |
| 
 | |
|     TEST_USERNAME = "test_user"
 | |
|     TEST_PASSWORD = "test_password"
 | |
|     TEST_EMAIL = "test@example.com"
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         User.objects.create_user(cls.TEST_USERNAME, cls.TEST_EMAIL, cls.TEST_PASSWORD)
 | |
| 
 | |
|     @override_settings(AUTHENTICATION_BACKENDS=[backend])
 | |
|     def test_changed_backend_settings(self):
 | |
|         """
 | |
|         Removing a backend configured in AUTHENTICATION_BACKENDS makes 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)
 | |
| 
 | |
| 
 | |
| class TypeErrorBackend:
 | |
|     """
 | |
|     Always raises TypeError.
 | |
|     """
 | |
| 
 | |
|     @sensitive_variables("password")
 | |
|     def authenticate(self, request, username=None, password=None):
 | |
|         raise TypeError
 | |
| 
 | |
| 
 | |
| class SkippedBackend:
 | |
|     def authenticate(self):
 | |
|         # Doesn't accept any credentials so is skipped by authenticate().
 | |
|         pass
 | |
| 
 | |
| 
 | |
| class SkippedBackendWithDecoratedMethod:
 | |
|     @sensitive_variables()
 | |
|     def authenticate(self):
 | |
|         pass
 | |
| 
 | |
| 
 | |
| class AuthenticateTests(TestCase):
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         cls.user1 = User.objects.create_user("test", "test@example.com", "test")
 | |
| 
 | |
|     def setUp(self):
 | |
|         self.sensitive_password = "mypassword"
 | |
| 
 | |
|     @override_settings(
 | |
|         AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.TypeErrorBackend"]
 | |
|     )
 | |
|     def test_type_error_raised(self):
 | |
|         """A TypeError within a backend is propagated properly (#18171)."""
 | |
|         with self.assertRaises(TypeError):
 | |
|             authenticate(username="test", password="test")
 | |
| 
 | |
|     @override_settings(
 | |
|         AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.TypeErrorBackend"]
 | |
|     )
 | |
|     def test_authenticate_sensitive_variables(self):
 | |
|         try:
 | |
|             authenticate(username="testusername", password=self.sensitive_password)
 | |
|         except TypeError:
 | |
|             exc_info = sys.exc_info()
 | |
|         rf = RequestFactory()
 | |
|         response = technical_500_response(rf.get("/"), *exc_info)
 | |
|         self.assertNotContains(response, self.sensitive_password, status_code=500)
 | |
|         self.assertContains(response, "TypeErrorBackend", status_code=500)
 | |
|         self.assertContains(
 | |
|             response,
 | |
|             '<tr><td>credentials</td><td class="code">'
 | |
|             "<pre>'********************'</pre></td></tr>",
 | |
|             html=True,
 | |
|             status_code=500,
 | |
|         )
 | |
| 
 | |
|     def test_clean_credentials_sensitive_variables(self):
 | |
|         try:
 | |
|             # Passing in a list to cause an exception
 | |
|             _clean_credentials([1, self.sensitive_password])
 | |
|         except TypeError:
 | |
|             exc_info = sys.exc_info()
 | |
|         rf = RequestFactory()
 | |
|         response = technical_500_response(rf.get("/"), *exc_info)
 | |
|         self.assertNotContains(response, self.sensitive_password, status_code=500)
 | |
|         self.assertContains(
 | |
|             response,
 | |
|             '<tr><td>credentials</td><td class="code">'
 | |
|             "<pre>'********************'</pre></td></tr>",
 | |
|             html=True,
 | |
|             status_code=500,
 | |
|         )
 | |
| 
 | |
|     @override_settings(
 | |
|         AUTHENTICATION_BACKENDS=(
 | |
|             "auth_tests.test_auth_backends.SkippedBackend",
 | |
|             "django.contrib.auth.backends.ModelBackend",
 | |
|         )
 | |
|     )
 | |
|     def test_skips_backends_without_arguments(self):
 | |
|         """
 | |
|         A backend (SkippedBackend) is ignored if it doesn't accept the
 | |
|         credentials as arguments.
 | |
|         """
 | |
|         self.assertEqual(authenticate(username="test", password="test"), self.user1)
 | |
| 
 | |
|     @override_settings(
 | |
|         AUTHENTICATION_BACKENDS=(
 | |
|             "auth_tests.test_auth_backends.SkippedBackendWithDecoratedMethod",
 | |
|             "django.contrib.auth.backends.ModelBackend",
 | |
|         )
 | |
|     )
 | |
|     def test_skips_backends_with_decorated_method(self):
 | |
|         self.assertEqual(authenticate(username="test", password="test"), self.user1)
 | |
| 
 | |
| 
 | |
| class ImproperlyConfiguredUserModelTest(TestCase):
 | |
|     """
 | |
|     An exception from within get_user_model() is propagated and doesn't
 | |
|     raise an UnboundLocalError (#21439).
 | |
|     """
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         cls.user1 = User.objects.create_user("test", "test@example.com", "test")
 | |
| 
 | |
|     def setUp(self):
 | |
|         self.client.login(username="test", password="test")
 | |
| 
 | |
|     @override_settings(AUTH_USER_MODEL="thismodel.doesntexist")
 | |
|     def test_does_not_shadow_exception(self):
 | |
|         # Prepare a request object
 | |
|         request = HttpRequest()
 | |
|         request.session = self.client.session
 | |
| 
 | |
|         msg = (
 | |
|             "AUTH_USER_MODEL refers to model 'thismodel.doesntexist' "
 | |
|             "that has not been installed"
 | |
|         )
 | |
|         with self.assertRaisesMessage(ImproperlyConfigured, msg):
 | |
|             get_user(request)
 | |
| 
 | |
| 
 | |
| class ImportedModelBackend(ModelBackend):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class CustomModelBackend(ModelBackend):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class OtherModelBackend(ModelBackend):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class ImportedBackendTests(TestCase):
 | |
|     """
 | |
|     #23925 - The backend path added to the session should be the same
 | |
|     as the one defined in AUTHENTICATION_BACKENDS setting.
 | |
|     """
 | |
| 
 | |
|     backend = "auth_tests.backend_alias.ImportedModelBackend"
 | |
| 
 | |
|     @override_settings(AUTHENTICATION_BACKENDS=[backend])
 | |
|     def test_backend_path(self):
 | |
|         username = "username"
 | |
|         password = "password"
 | |
|         User.objects.create_user(username, "email", password)
 | |
|         self.assertTrue(self.client.login(username=username, password=password))
 | |
|         request = HttpRequest()
 | |
|         request.session = self.client.session
 | |
|         self.assertEqual(request.session[BACKEND_SESSION_KEY], self.backend)
 | |
| 
 | |
| 
 | |
| class SelectingBackendTests(TestCase):
 | |
|     backend = "auth_tests.test_auth_backends.CustomModelBackend"
 | |
|     other_backend = "auth_tests.test_auth_backends.OtherModelBackend"
 | |
|     username = "username"
 | |
|     password = "password"
 | |
| 
 | |
|     def assertBackendInSession(self, backend):
 | |
|         request = HttpRequest()
 | |
|         request.session = self.client.session
 | |
|         self.assertEqual(request.session[BACKEND_SESSION_KEY], backend)
 | |
| 
 | |
|     @override_settings(AUTHENTICATION_BACKENDS=[backend])
 | |
|     def test_backend_path_login_without_authenticate_single_backend(self):
 | |
|         user = User.objects.create_user(self.username, "email", self.password)
 | |
|         self.client._login(user)
 | |
|         self.assertBackendInSession(self.backend)
 | |
| 
 | |
|     @override_settings(AUTHENTICATION_BACKENDS=[backend, other_backend])
 | |
|     def test_backend_path_login_without_authenticate_multiple_backends(self):
 | |
|         user = User.objects.create_user(self.username, "email", self.password)
 | |
|         expected_message = (
 | |
|             "You have multiple authentication backends configured and "
 | |
|             "therefore must provide the `backend` argument or set the "
 | |
|             "`backend` attribute on the user."
 | |
|         )
 | |
|         with self.assertRaisesMessage(ValueError, expected_message):
 | |
|             self.client._login(user)
 | |
| 
 | |
|     def test_non_string_backend(self):
 | |
|         user = User.objects.create_user(self.username, "email", self.password)
 | |
|         expected_message = (
 | |
|             "backend must be a dotted import path string (got "
 | |
|             "<class 'django.contrib.auth.backends.ModelBackend'>)."
 | |
|         )
 | |
|         with self.assertRaisesMessage(TypeError, expected_message):
 | |
|             self.client._login(user, backend=ModelBackend)
 | |
| 
 | |
|     @override_settings(AUTHENTICATION_BACKENDS=[backend, other_backend])
 | |
|     def test_backend_path_login_with_explicit_backends(self):
 | |
|         user = User.objects.create_user(self.username, "email", self.password)
 | |
|         self.client._login(user, self.other_backend)
 | |
|         self.assertBackendInSession(self.other_backend)
 | |
| 
 | |
| 
 | |
| @override_settings(
 | |
|     AUTHENTICATION_BACKENDS=["django.contrib.auth.backends.AllowAllUsersModelBackend"]
 | |
| )
 | |
| class AllowAllUsersModelBackendTest(TestCase):
 | |
|     """
 | |
|     Inactive users may authenticate with the AllowAllUsersModelBackend.
 | |
|     """
 | |
| 
 | |
|     user_credentials = {"username": "test", "password": "test"}
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpTestData(cls):
 | |
|         cls.user = User.objects.create_user(
 | |
|             email="test@example.com", is_active=False, **cls.user_credentials
 | |
|         )
 | |
| 
 | |
|     def test_authenticate(self):
 | |
|         self.assertFalse(self.user.is_active)
 | |
|         self.assertEqual(authenticate(**self.user_credentials), self.user)
 | |
| 
 | |
|     def test_get_user(self):
 | |
|         self.client.force_login(self.user)
 | |
|         request = HttpRequest()
 | |
|         request.session = self.client.session
 | |
|         user = get_user(request)
 | |
|         self.assertEqual(user, self.user)
 |