123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- from unittest import mock
- from django.conf.global_settings import PASSWORD_HASHERS
- from django.contrib.auth import get_user_model
- from django.contrib.auth.backends import ModelBackend
- from django.contrib.auth.base_user import AbstractBaseUser
- from django.contrib.auth.hashers import get_hasher
- from django.contrib.auth.models import (
- AnonymousUser,
- Group,
- Permission,
- User,
- UserManager,
- )
- from django.contrib.contenttypes.models import ContentType
- from django.core import mail
- from django.db import connection, migrations
- from django.db.migrations.state import ModelState, ProjectState
- from django.db.models.signals import post_save
- from django.test import SimpleTestCase, TestCase, TransactionTestCase, override_settings
- from .models import CustomEmailField, IntegerUsernameUser
- class NaturalKeysTestCase(TestCase):
- def test_user_natural_key(self):
- staff_user = User.objects.create_user(username="staff")
- self.assertEqual(User.objects.get_by_natural_key("staff"), staff_user)
- self.assertEqual(staff_user.natural_key(), ("staff",))
- async def test_auser_natural_key(self):
- staff_user = await User.objects.acreate_user(username="staff")
- self.assertEqual(await User.objects.aget_by_natural_key("staff"), staff_user)
- self.assertEqual(staff_user.natural_key(), ("staff",))
- def test_group_natural_key(self):
- users_group = Group.objects.create(name="users")
- self.assertEqual(Group.objects.get_by_natural_key("users"), users_group)
- async def test_agroup_natural_key(self):
- users_group = await Group.objects.acreate(name="users")
- self.assertEqual(await Group.objects.aget_by_natural_key("users"), users_group)
- class LoadDataWithoutNaturalKeysTestCase(TestCase):
- fixtures = ["regular.json"]
- def test_user_is_created_and_added_to_group(self):
- user = User.objects.get(username="my_username")
- group = Group.objects.get(name="my_group")
- self.assertEqual(group, user.groups.get())
- class LoadDataWithNaturalKeysTestCase(TestCase):
- fixtures = ["natural.json"]
- def test_user_is_created_and_added_to_group(self):
- user = User.objects.get(username="my_username")
- group = Group.objects.get(name="my_group")
- self.assertEqual(group, user.groups.get())
- class LoadDataWithNaturalKeysAndMultipleDatabasesTestCase(TestCase):
- databases = {"default", "other"}
- def test_load_data_with_user_permissions(self):
- # Create test contenttypes for both databases
- default_objects = [
- ContentType.objects.db_manager("default").create(
- model="examplemodela",
- app_label="app_a",
- ),
- ContentType.objects.db_manager("default").create(
- model="examplemodelb",
- app_label="app_b",
- ),
- ]
- other_objects = [
- ContentType.objects.db_manager("other").create(
- model="examplemodelb",
- app_label="app_b",
- ),
- ContentType.objects.db_manager("other").create(
- model="examplemodela",
- app_label="app_a",
- ),
- ]
- # Now we create the test UserPermission
- Permission.objects.db_manager("default").create(
- name="Can delete example model b",
- codename="delete_examplemodelb",
- content_type=default_objects[1],
- )
- Permission.objects.db_manager("other").create(
- name="Can delete example model b",
- codename="delete_examplemodelb",
- content_type=other_objects[0],
- )
- perm_default = Permission.objects.get_by_natural_key(
- "delete_examplemodelb",
- "app_b",
- "examplemodelb",
- )
- perm_other = Permission.objects.db_manager("other").get_by_natural_key(
- "delete_examplemodelb",
- "app_b",
- "examplemodelb",
- )
- self.assertEqual(perm_default.content_type_id, default_objects[1].id)
- self.assertEqual(perm_other.content_type_id, other_objects[0].id)
- class UserManagerTestCase(TransactionTestCase):
- available_apps = [
- "auth_tests",
- "django.contrib.auth",
- "django.contrib.contenttypes",
- ]
- def test_create_user(self):
- email_lowercase = "normal@normal.com"
- user = User.objects.create_user("user", email_lowercase)
- self.assertEqual(user.email, email_lowercase)
- self.assertEqual(user.username, "user")
- self.assertFalse(user.has_usable_password())
- def test_create_user_email_domain_normalize_rfc3696(self):
- # According to RFC 3696 Section 3 the "@" symbol can be part of the
- # local part of an email address.
- returned = UserManager.normalize_email(r"Abc\@DEF@EXAMPLE.com")
- self.assertEqual(returned, r"Abc\@DEF@example.com")
- def test_create_user_email_domain_normalize(self):
- returned = UserManager.normalize_email("normal@DOMAIN.COM")
- self.assertEqual(returned, "normal@domain.com")
- def test_create_user_email_domain_normalize_with_whitespace(self):
- returned = UserManager.normalize_email(r"email\ with_whitespace@D.COM")
- self.assertEqual(returned, r"email\ with_whitespace@d.com")
- def test_empty_username(self):
- with self.assertRaisesMessage(ValueError, "The given username must be set"):
- User.objects.create_user(username="")
- def test_create_user_is_staff(self):
- email = "normal@normal.com"
- user = User.objects.create_user("user", email, is_staff=True)
- self.assertEqual(user.email, email)
- self.assertEqual(user.username, "user")
- self.assertTrue(user.is_staff)
- def test_create_super_user_raises_error_on_false_is_superuser(self):
- with self.assertRaisesMessage(
- ValueError, "Superuser must have is_superuser=True."
- ):
- User.objects.create_superuser(
- username="test",
- email="test@test.com",
- password="test",
- is_superuser=False,
- )
- async def test_acreate_super_user_raises_error_on_false_is_superuser(self):
- with self.assertRaisesMessage(
- ValueError, "Superuser must have is_superuser=True."
- ):
- await User.objects.acreate_superuser(
- username="test",
- email="test@test.com",
- password="test",
- is_superuser=False,
- )
- def test_create_superuser_raises_error_on_false_is_staff(self):
- with self.assertRaisesMessage(ValueError, "Superuser must have is_staff=True."):
- User.objects.create_superuser(
- username="test",
- email="test@test.com",
- password="test",
- is_staff=False,
- )
- async def test_acreate_superuser_raises_error_on_false_is_staff(self):
- with self.assertRaisesMessage(ValueError, "Superuser must have is_staff=True."):
- await User.objects.acreate_superuser(
- username="test",
- email="test@test.com",
- password="test",
- is_staff=False,
- )
- def test_runpython_manager_methods(self):
- def forwards(apps, schema_editor):
- UserModel = apps.get_model("auth", "User")
- user = UserModel.objects.create_user("user1", password="secure")
- self.assertIsInstance(user, UserModel)
- operation = migrations.RunPython(forwards, migrations.RunPython.noop)
- project_state = ProjectState()
- project_state.add_model(ModelState.from_model(User))
- project_state.add_model(ModelState.from_model(Group))
- project_state.add_model(ModelState.from_model(Permission))
- project_state.add_model(ModelState.from_model(ContentType))
- new_state = project_state.clone()
- with connection.schema_editor() as editor:
- operation.state_forwards("test_manager_methods", new_state)
- operation.database_forwards(
- "test_manager_methods",
- editor,
- project_state,
- new_state,
- )
- user = User.objects.get(username="user1")
- self.assertTrue(user.check_password("secure"))
- class AbstractBaseUserTests(SimpleTestCase):
- def test_has_usable_password(self):
- """
- Passwords are usable even if they don't correspond to a hasher in
- settings.PASSWORD_HASHERS.
- """
- self.assertIs(User(password="some-gibbberish").has_usable_password(), True)
- def test_normalize_username(self):
- self.assertEqual(IntegerUsernameUser().normalize_username(123), 123)
- def test_clean_normalize_username(self):
- # The normalization happens in AbstractBaseUser.clean()
- ohm_username = "iamtheΩ" # U+2126 OHM SIGN
- for model in ("auth.User", "auth_tests.CustomUser"):
- with self.subTest(model=model), self.settings(AUTH_USER_MODEL=model):
- User = get_user_model()
- user = User(**{User.USERNAME_FIELD: ohm_username, "password": "foo"})
- user.clean()
- username = user.get_username()
- self.assertNotEqual(username, ohm_username)
- self.assertEqual(
- username, "iamtheΩ"
- ) # U+03A9 GREEK CAPITAL LETTER OMEGA
- def test_default_email(self):
- self.assertEqual(AbstractBaseUser.get_email_field_name(), "email")
- def test_custom_email(self):
- user = CustomEmailField()
- self.assertEqual(user.get_email_field_name(), "email_address")
- class AbstractUserTestCase(TestCase):
- def test_email_user(self):
- # valid send_mail parameters
- kwargs = {
- "fail_silently": False,
- "auth_user": None,
- "auth_password": None,
- "connection": None,
- "html_message": None,
- }
- user = User(email="foo@bar.com")
- user.email_user(
- subject="Subject here",
- message="This is a message",
- from_email="from@domain.com",
- **kwargs,
- )
- self.assertEqual(len(mail.outbox), 1)
- message = mail.outbox[0]
- self.assertEqual(message.subject, "Subject here")
- self.assertEqual(message.body, "This is a message")
- self.assertEqual(message.from_email, "from@domain.com")
- self.assertEqual(message.to, [user.email])
- def test_last_login_default(self):
- user1 = User.objects.create(username="user1")
- self.assertIsNone(user1.last_login)
- user2 = User.objects.create_user(username="user2")
- self.assertIsNone(user2.last_login)
- def test_user_clean_normalize_email(self):
- user = User(username="user", password="foo", email="foo@BAR.com")
- user.clean()
- self.assertEqual(user.email, "foo@bar.com")
- def test_user_double_save(self):
- """
- Calling user.save() twice should trigger password_changed() once.
- """
- user = User.objects.create_user(username="user", password="foo")
- user.set_password("bar")
- with mock.patch(
- "django.contrib.auth.password_validation.password_changed"
- ) as pw_changed:
- user.save()
- self.assertEqual(pw_changed.call_count, 1)
- user.save()
- self.assertEqual(pw_changed.call_count, 1)
- @override_settings(PASSWORD_HASHERS=PASSWORD_HASHERS)
- def test_check_password_upgrade(self):
- """
- password_changed() shouldn't be called if User.check_password()
- triggers a hash iteration upgrade.
- """
- user = User.objects.create_user(username="user", password="foo")
- initial_password = user.password
- self.assertTrue(user.check_password("foo"))
- hasher = get_hasher("default")
- self.assertEqual("pbkdf2_sha256", hasher.algorithm)
- old_iterations = hasher.iterations
- try:
- # Upgrade the password iterations
- hasher.iterations = old_iterations + 1
- with mock.patch(
- "django.contrib.auth.password_validation.password_changed"
- ) as pw_changed:
- user.check_password("foo")
- self.assertEqual(pw_changed.call_count, 0)
- self.assertNotEqual(initial_password, user.password)
- finally:
- hasher.iterations = old_iterations
- @override_settings(PASSWORD_HASHERS=PASSWORD_HASHERS)
- async def test_acheck_password_upgrade(self):
- user = await User.objects.acreate_user(username="user", password="foo")
- initial_password = user.password
- self.assertIs(await user.acheck_password("foo"), True)
- hasher = get_hasher("default")
- self.assertEqual("pbkdf2_sha256", hasher.algorithm)
- old_iterations = hasher.iterations
- try:
- # Upgrade the password iterations.
- hasher.iterations = old_iterations + 1
- with mock.patch(
- "django.contrib.auth.password_validation.password_changed"
- ) as pw_changed:
- self.assertIs(await user.acheck_password("foo"), True)
- self.assertEqual(pw_changed.call_count, 0)
- self.assertNotEqual(initial_password, user.password)
- finally:
- hasher.iterations = old_iterations
- class CustomModelBackend(ModelBackend):
- def with_perm(
- self, perm, is_active=True, include_superusers=True, backend=None, obj=None
- ):
- if obj is not None and obj.username == "charliebrown":
- return User.objects.filter(pk=obj.pk)
- return User.objects.filter(username__startswith="charlie")
- class UserWithPermTestCase(TestCase):
- @classmethod
- def setUpTestData(cls):
- content_type = ContentType.objects.get_for_model(Group)
- cls.permission = Permission.objects.create(
- name="test",
- content_type=content_type,
- codename="test",
- )
- # User with permission.
- cls.user1 = User.objects.create_user("user 1", "foo@example.com")
- cls.user1.user_permissions.add(cls.permission)
- # User with group permission.
- group1 = Group.objects.create(name="group 1")
- group1.permissions.add(cls.permission)
- group2 = Group.objects.create(name="group 2")
- group2.permissions.add(cls.permission)
- cls.user2 = User.objects.create_user("user 2", "bar@example.com")
- cls.user2.groups.add(group1, group2)
- # Users without permissions.
- cls.user_charlie = User.objects.create_user("charlie", "charlie@example.com")
- cls.user_charlie_b = User.objects.create_user(
- "charliebrown", "charlie@brown.com"
- )
- # Superuser.
- cls.superuser = User.objects.create_superuser(
- "superuser",
- "superuser@example.com",
- "superpassword",
- )
- # Inactive user with permission.
- cls.inactive_user = User.objects.create_user(
- "inactive_user",
- "baz@example.com",
- is_active=False,
- )
- cls.inactive_user.user_permissions.add(cls.permission)
- def test_invalid_permission_name(self):
- msg = "Permission name should be in the form app_label.permission_codename."
- for perm in ("nodots", "too.many.dots", "...", ""):
- with self.subTest(perm), self.assertRaisesMessage(ValueError, msg):
- User.objects.with_perm(perm)
- def test_invalid_permission_type(self):
- msg = "The `perm` argument must be a string or a permission instance."
- for perm in (b"auth.test", object(), None):
- with self.subTest(perm), self.assertRaisesMessage(TypeError, msg):
- User.objects.with_perm(perm)
- def test_invalid_backend_type(self):
- msg = "backend must be a dotted import path string (got %r)."
- for backend in (b"auth_tests.CustomModelBackend", object()):
- with self.subTest(backend):
- with self.assertRaisesMessage(TypeError, msg % backend):
- User.objects.with_perm("auth.test", backend=backend)
- def test_basic(self):
- active_users = [self.user1, self.user2]
- tests = [
- ({}, [*active_users, self.superuser]),
- ({"obj": self.user1}, []),
- # Only inactive users.
- ({"is_active": False}, [self.inactive_user]),
- # All users.
- ({"is_active": None}, [*active_users, self.superuser, self.inactive_user]),
- # Exclude superusers.
- ({"include_superusers": False}, active_users),
- (
- {"include_superusers": False, "is_active": False},
- [self.inactive_user],
- ),
- (
- {"include_superusers": False, "is_active": None},
- [*active_users, self.inactive_user],
- ),
- ]
- for kwargs, expected_users in tests:
- for perm in ("auth.test", self.permission):
- with self.subTest(perm=perm, **kwargs):
- self.assertCountEqual(
- User.objects.with_perm(perm, **kwargs),
- expected_users,
- )
- @override_settings(
- AUTHENTICATION_BACKENDS=["django.contrib.auth.backends.BaseBackend"]
- )
- def test_backend_without_with_perm(self):
- self.assertSequenceEqual(User.objects.with_perm("auth.test"), [])
- def test_nonexistent_permission(self):
- self.assertSequenceEqual(User.objects.with_perm("auth.perm"), [self.superuser])
- def test_nonexistent_backend(self):
- with self.assertRaises(ImportError):
- User.objects.with_perm(
- "auth.test",
- backend="invalid.backend.CustomModelBackend",
- )
- def test_invalid_backend_submodule(self):
- with self.assertRaises(ImportError):
- User.objects.with_perm(
- "auth.test",
- backend="json.tool",
- )
- @override_settings(
- AUTHENTICATION_BACKENDS=["auth_tests.test_models.CustomModelBackend"]
- )
- def test_custom_backend(self):
- for perm in ("auth.test", self.permission):
- with self.subTest(perm):
- self.assertCountEqual(
- User.objects.with_perm(perm),
- [self.user_charlie, self.user_charlie_b],
- )
- @override_settings(
- AUTHENTICATION_BACKENDS=["auth_tests.test_models.CustomModelBackend"]
- )
- def test_custom_backend_pass_obj(self):
- for perm in ("auth.test", self.permission):
- with self.subTest(perm):
- self.assertSequenceEqual(
- User.objects.with_perm(perm, obj=self.user_charlie_b),
- [self.user_charlie_b],
- )
- @override_settings(
- AUTHENTICATION_BACKENDS=[
- "auth_tests.test_models.CustomModelBackend",
- "django.contrib.auth.backends.ModelBackend",
- ]
- )
- def test_multiple_backends(self):
- msg = (
- "You have multiple authentication backends configured and "
- "therefore must provide the `backend` argument."
- )
- with self.assertRaisesMessage(ValueError, msg):
- User.objects.with_perm("auth.test")
- backend = "auth_tests.test_models.CustomModelBackend"
- self.assertCountEqual(
- User.objects.with_perm("auth.test", backend=backend),
- [self.user_charlie, self.user_charlie_b],
- )
- class IsActiveTestCase(TestCase):
- """
- Tests the behavior of the guaranteed is_active attribute
- """
- def test_builtin_user_isactive(self):
- user = User.objects.create(username="foo", email="foo@bar.com")
- # is_active is true by default
- self.assertIs(user.is_active, True)
- user.is_active = False
- user.save()
- user_fetched = User.objects.get(pk=user.pk)
- # the is_active flag is saved
- self.assertFalse(user_fetched.is_active)
- @override_settings(AUTH_USER_MODEL="auth_tests.IsActiveTestUser1")
- def test_is_active_field_default(self):
- """
- tests that the default value for is_active is provided
- """
- UserModel = get_user_model()
- user = UserModel(username="foo")
- self.assertIs(user.is_active, True)
- # you can set the attribute - but it will not save
- user.is_active = False
- # there should be no problem saving - but the attribute is not saved
- user.save()
- user_fetched = UserModel._default_manager.get(pk=user.pk)
- # the attribute is always true for newly retrieved instance
- self.assertIs(user_fetched.is_active, True)
- class TestCreateSuperUserSignals(TestCase):
- """
- Simple test case for ticket #20541
- """
- def post_save_listener(self, *args, **kwargs):
- self.signals_count += 1
- def setUp(self):
- self.signals_count = 0
- post_save.connect(self.post_save_listener, sender=User)
- self.addCleanup(post_save.disconnect, self.post_save_listener, sender=User)
- def test_create_user(self):
- User.objects.create_user("JohnDoe")
- self.assertEqual(self.signals_count, 1)
- def test_create_superuser(self):
- User.objects.create_superuser("JohnDoe", "mail@example.com", "1")
- self.assertEqual(self.signals_count, 1)
- class AnonymousUserTests(SimpleTestCase):
- no_repr_msg = "Django doesn't provide a DB representation for AnonymousUser."
- def setUp(self):
- self.user = AnonymousUser()
- def test_properties(self):
- self.assertIsNone(self.user.pk)
- self.assertEqual(self.user.username, "")
- self.assertEqual(self.user.get_username(), "")
- self.assertIs(self.user.is_anonymous, True)
- self.assertIs(self.user.is_authenticated, False)
- self.assertIs(self.user.is_staff, False)
- self.assertIs(self.user.is_active, False)
- self.assertIs(self.user.is_superuser, False)
- self.assertEqual(self.user.groups.count(), 0)
- self.assertEqual(self.user.user_permissions.count(), 0)
- self.assertEqual(self.user.get_user_permissions(), set())
- self.assertEqual(self.user.get_group_permissions(), set())
- async def test_properties_async_versions(self):
- self.assertEqual(await self.user.groups.acount(), 0)
- self.assertEqual(await self.user.user_permissions.acount(), 0)
- self.assertEqual(await self.user.aget_user_permissions(), set())
- self.assertEqual(await self.user.aget_group_permissions(), set())
- def test_str(self):
- self.assertEqual(str(self.user), "AnonymousUser")
- def test_eq(self):
- self.assertEqual(self.user, AnonymousUser())
- self.assertNotEqual(self.user, User("super", "super@example.com", "super"))
- def test_hash(self):
- self.assertEqual(hash(self.user), 1)
- def test_int(self):
- msg = (
- "Cannot cast AnonymousUser to int. Are you trying to use it in "
- "place of User?"
- )
- with self.assertRaisesMessage(TypeError, msg):
- int(self.user)
- def test_delete(self):
- with self.assertRaisesMessage(NotImplementedError, self.no_repr_msg):
- self.user.delete()
- def test_save(self):
- with self.assertRaisesMessage(NotImplementedError, self.no_repr_msg):
- self.user.save()
- def test_set_password(self):
- with self.assertRaisesMessage(NotImplementedError, self.no_repr_msg):
- self.user.set_password("password")
- def test_check_password(self):
- with self.assertRaisesMessage(NotImplementedError, self.no_repr_msg):
- self.user.check_password("password")
- class GroupTests(SimpleTestCase):
- def test_str(self):
- g = Group(name="Users")
- self.assertEqual(str(g), "Users")
- class PermissionTests(TestCase):
- def test_str(self):
- p = Permission.objects.get(codename="view_customemailfield")
- self.assertEqual(
- str(p), "Auth_Tests | custom email field | Can view custom email field"
- )
|