diff options
author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/auth_tests | |
parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
download | django-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/auth_tests')
39 files changed, 3573 insertions, 2739 deletions
diff --git a/tests/auth_tests/backend_alias.py b/tests/auth_tests/backend_alias.py index ae14d1538c..fe398d1674 100644 --- a/tests/auth_tests/backend_alias.py +++ b/tests/auth_tests/backend_alias.py @@ -1,4 +1,4 @@ # For testing that auth backends can be referenced using a convenience import from .test_auth_backends import ImportedModelBackend -__all__ = ['ImportedModelBackend'] +__all__ = ["ImportedModelBackend"] diff --git a/tests/auth_tests/client.py b/tests/auth_tests/client.py index c2ce1102ce..7426f93e6e 100644 --- a/tests/auth_tests/client.py +++ b/tests/auth_tests/client.py @@ -1,13 +1,14 @@ import re from django.contrib.auth.views import ( - INTERNAL_RESET_SESSION_TOKEN, PasswordResetConfirmView, + INTERNAL_RESET_SESSION_TOKEN, + PasswordResetConfirmView, ) from django.test import Client def extract_token_from_url(url): - token_search = re.search(r'/reset/.*/(.+?)/', url) + token_search = re.search(r"/reset/.*/(.+?)/", url) if token_search: return token_search[1] @@ -22,6 +23,7 @@ class PasswordResetConfirmClient(Client): >>> client = PasswordResetConfirmClient() >>> client.get('/reset/bla/my-token/') """ + reset_url_token = PasswordResetConfirmView.reset_url_token def _get_password_reset_confirm_redirect_url(self, url): diff --git a/tests/auth_tests/models/__init__.py b/tests/auth_tests/models/__init__.py index b3e06cd7b8..bce5edf883 100644 --- a/tests/auth_tests/models/__init__.py +++ b/tests/auth_tests/models/__init__.py @@ -1,7 +1,5 @@ from .custom_permissions import CustomPermissionsUser -from .custom_user import ( - CustomUser, CustomUserWithoutIsActiveField, ExtensionUser, -) +from .custom_user import CustomUser, CustomUserWithoutIsActiveField, ExtensionUser from .invalid_models import CustomUserNonUniqueUsername from .is_active import IsActiveTestUser1 from .minimal import MinimalUser @@ -12,15 +10,26 @@ from .with_custom_email_field import CustomEmailField from .with_foreign_key import CustomUserWithFK, Email from .with_integer_username import IntegerUsernameUser from .with_last_login_attr import UserWithDisabledLastLoginField -from .with_many_to_many import ( - CustomUserWithM2M, CustomUserWithM2MThrough, Organization, -) +from .with_many_to_many import CustomUserWithM2M, CustomUserWithM2MThrough, Organization __all__ = ( - 'CustomEmailField', 'CustomPermissionsUser', 'CustomUser', - 'CustomUserNonUniqueUsername', 'CustomUserWithFK', 'CustomUserWithM2M', - 'CustomUserWithM2MThrough', 'CustomUserWithoutIsActiveField', 'Email', - 'ExtensionUser', 'IntegerUsernameUser', 'IsActiveTestUser1', 'MinimalUser', - 'NoPasswordUser', 'Organization', 'Proxy', 'UUIDUser', 'UserProxy', - 'UserWithDisabledLastLoginField', + "CustomEmailField", + "CustomPermissionsUser", + "CustomUser", + "CustomUserNonUniqueUsername", + "CustomUserWithFK", + "CustomUserWithM2M", + "CustomUserWithM2MThrough", + "CustomUserWithoutIsActiveField", + "Email", + "ExtensionUser", + "IntegerUsernameUser", + "IsActiveTestUser1", + "MinimalUser", + "NoPasswordUser", + "Organization", + "Proxy", + "UUIDUser", + "UserProxy", + "UserWithDisabledLastLoginField", ) diff --git a/tests/auth_tests/models/custom_permissions.py b/tests/auth_tests/models/custom_permissions.py index bddcfde2eb..52d28bd276 100644 --- a/tests/auth_tests/models/custom_permissions.py +++ b/tests/auth_tests/models/custom_permissions.py @@ -18,14 +18,17 @@ class CustomPermissionsUserManager(CustomUserManager): with RemoveGroupsAndPermissions(): + class CustomPermissionsUser(AbstractBaseUser, PermissionsMixin): - email = models.EmailField(verbose_name='email address', max_length=255, unique=True) + email = models.EmailField( + verbose_name="email address", max_length=255, unique=True + ) date_of_birth = models.DateField() custom_objects = CustomPermissionsUserManager() - USERNAME_FIELD = 'email' - REQUIRED_FIELDS = ['date_of_birth'] + USERNAME_FIELD = "email" + REQUIRED_FIELDS = ["date_of_birth"] def __str__(self): return self.email diff --git a/tests/auth_tests/models/custom_user.py b/tests/auth_tests/models/custom_user.py index a46f1d5a9c..b9938681ca 100644 --- a/tests/auth_tests/models/custom_user.py +++ b/tests/auth_tests/models/custom_user.py @@ -1,6 +1,11 @@ from django.contrib.auth.models import ( - AbstractBaseUser, AbstractUser, BaseUserManager, Group, Permission, - PermissionsMixin, UserManager, + AbstractBaseUser, + AbstractUser, + BaseUserManager, + Group, + Permission, + PermissionsMixin, + UserManager, ) from django.db import models @@ -14,12 +19,10 @@ class CustomUserManager(BaseUserManager): Creates and saves a User with the given email and password. """ if not email: - raise ValueError('Users must have an email address') + raise ValueError("Users must have an email address") user = self.model( - email=self.normalize_email(email), - date_of_birth=date_of_birth, - **fields + email=self.normalize_email(email), date_of_birth=date_of_birth, **fields ) user.set_password(password) @@ -27,14 +30,16 @@ class CustomUserManager(BaseUserManager): return user def create_superuser(self, email, password, date_of_birth, **fields): - u = self.create_user(email, password=password, date_of_birth=date_of_birth, **fields) + u = self.create_user( + email, password=password, date_of_birth=date_of_birth, **fields + ) u.is_admin = True u.save(using=self._db) return u class CustomUser(AbstractBaseUser): - email = models.EmailField(verbose_name='email address', max_length=255, unique=True) + email = models.EmailField(verbose_name="email address", max_length=255, unique=True) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) date_of_birth = models.DateField() @@ -42,8 +47,8 @@ class CustomUser(AbstractBaseUser): custom_objects = CustomUserManager() - USERNAME_FIELD = 'email' - REQUIRED_FIELDS = ['date_of_birth', 'first_name'] + USERNAME_FIELD = "email" + REQUIRED_FIELDS = ["date_of_birth", "first_name"] def __str__(self): return self.email @@ -76,6 +81,7 @@ class RemoveGroupsAndPermissions: fields from the AbstractUser class, so they don't clash with the related_name sets. """ + def __enter__(self): self._old_au_local_m2m = AbstractUser._meta.local_many_to_many self._old_pm_local_m2m = PermissionsMixin._meta.local_many_to_many @@ -97,16 +103,17 @@ class CustomUserWithoutIsActiveField(AbstractBaseUser): objects = UserManager() - USERNAME_FIELD = 'username' + USERNAME_FIELD = "username" # The extension user is a simple extension of the built-in user class, # adding a required date_of_birth field. This allows us to check for # any hard references to the name "User" in forms/handlers etc. with RemoveGroupsAndPermissions(): + class ExtensionUser(AbstractUser): date_of_birth = models.DateField() custom_objects = UserManager() - REQUIRED_FIELDS = AbstractUser.REQUIRED_FIELDS + ['date_of_birth'] + REQUIRED_FIELDS = AbstractUser.REQUIRED_FIELDS + ["date_of_birth"] diff --git a/tests/auth_tests/models/invalid_models.py b/tests/auth_tests/models/invalid_models.py index 123ed4d865..280c690faa 100644 --- a/tests/auth_tests/models/invalid_models.py +++ b/tests/auth_tests/models/invalid_models.py @@ -9,12 +9,13 @@ class CustomUserNonUniqueUsername(AbstractBaseUser): This model is not invalid if it is used with a custom authentication backend which supports non-unique usernames. """ + username = models.CharField(max_length=30) email = models.EmailField(blank=True) is_staff = models.BooleanField(default=False) is_superuser = models.BooleanField(default=False) - USERNAME_FIELD = 'username' - REQUIRED_FIELDS = ['email'] + USERNAME_FIELD = "username" + REQUIRED_FIELDS = ["email"] objects = UserManager() diff --git a/tests/auth_tests/models/is_active.py b/tests/auth_tests/models/is_active.py index 4c3144ffdc..cc91b8b97e 100644 --- a/tests/auth_tests/models/is_active.py +++ b/tests/auth_tests/models/is_active.py @@ -6,10 +6,11 @@ class IsActiveTestUser1(AbstractBaseUser): """ This test user class and derivatives test the default is_active behavior """ + username = models.CharField(max_length=30, unique=True) custom_objects = BaseUserManager() - USERNAME_FIELD = 'username' + USERNAME_FIELD = "username" # the is_active attr is provided by AbstractBaseUser diff --git a/tests/auth_tests/models/minimal.py b/tests/auth_tests/models/minimal.py index 7b8931b231..6fd986848c 100644 --- a/tests/auth_tests/models/minimal.py +++ b/tests/auth_tests/models/minimal.py @@ -3,4 +3,4 @@ from django.db import models class MinimalUser(models.Model): REQUIRED_FIELDS = () - USERNAME_FIELD = 'id' + USERNAME_FIELD = "id" diff --git a/tests/auth_tests/models/no_password.py b/tests/auth_tests/models/no_password.py index c7c40f76f6..33c08b4692 100644 --- a/tests/auth_tests/models/no_password.py +++ b/tests/auth_tests/models/no_password.py @@ -17,5 +17,5 @@ class NoPasswordUser(AbstractBaseUser): last_login = None username = models.CharField(max_length=50, unique=True) - USERNAME_FIELD = 'username' + USERNAME_FIELD = "username" objects = UserManager() diff --git a/tests/auth_tests/models/proxy.py b/tests/auth_tests/models/proxy.py index 9e82a398c2..ddcdfd582c 100644 --- a/tests/auth_tests/models/proxy.py +++ b/tests/auth_tests/models/proxy.py @@ -9,14 +9,10 @@ class Concrete(models.Model): class Proxy(Concrete): class Meta: proxy = True - permissions = ( - ('display_proxys', 'May display proxys information'), - ) + permissions = (("display_proxys", "May display proxys information"),) class UserProxy(User): class Meta: proxy = True - permissions = ( - ('use_different_app_label', 'May use a different app label'), - ) + permissions = (("use_different_app_label", "May use a different app label"),) diff --git a/tests/auth_tests/models/uuid_pk.py b/tests/auth_tests/models/uuid_pk.py index 87a4ee0658..d753660cbe 100644 --- a/tests/auth_tests/models/uuid_pk.py +++ b/tests/auth_tests/models/uuid_pk.py @@ -6,6 +6,8 @@ from django.db import models from .custom_user import RemoveGroupsAndPermissions with RemoveGroupsAndPermissions(): + class UUIDUser(AbstractUser): """A user with a UUID as primary key""" + id = models.UUIDField(default=uuid.uuid4, primary_key=True) diff --git a/tests/auth_tests/models/with_custom_email_field.py b/tests/auth_tests/models/with_custom_email_field.py index 278cd137a4..3cba8802d9 100644 --- a/tests/auth_tests/models/with_custom_email_field.py +++ b/tests/auth_tests/models/with_custom_email_field.py @@ -18,7 +18,7 @@ class CustomEmailField(AbstractBaseUser): email_address = models.EmailField(null=True) is_active = models.BooleanField(default=True) - EMAIL_FIELD = 'email_address' - USERNAME_FIELD = 'username' + EMAIL_FIELD = "email_address" + USERNAME_FIELD = "username" objects = CustomEmailFieldUserManager() diff --git a/tests/auth_tests/models/with_foreign_key.py b/tests/auth_tests/models/with_foreign_key.py index d16329a04b..13100accff 100644 --- a/tests/auth_tests/models/with_foreign_key.py +++ b/tests/auth_tests/models/with_foreign_key.py @@ -3,7 +3,7 @@ from django.db import models class Email(models.Model): - email = models.EmailField(verbose_name='email address', max_length=255, unique=True) + email = models.EmailField(verbose_name="email address", max_length=255, unique=True) class CustomUserWithFKManager(BaseUserManager): @@ -15,11 +15,13 @@ class CustomUserWithFKManager(BaseUserManager): class CustomUserWithFK(AbstractBaseUser): - username = models.ForeignKey(Email, models.CASCADE, related_name='primary') - email = models.ForeignKey(Email, models.CASCADE, to_field='email', related_name='secondary') + username = models.ForeignKey(Email, models.CASCADE, related_name="primary") + email = models.ForeignKey( + Email, models.CASCADE, to_field="email", related_name="secondary" + ) group = models.ForeignKey(Group, models.CASCADE) custom_objects = CustomUserWithFKManager() - USERNAME_FIELD = 'username' - REQUIRED_FIELDS = ['email', 'group'] + USERNAME_FIELD = "username" + REQUIRED_FIELDS = ["email", "group"] diff --git a/tests/auth_tests/models/with_integer_username.py b/tests/auth_tests/models/with_integer_username.py index fc3728d798..8d99bee13a 100644 --- a/tests/auth_tests/models/with_integer_username.py +++ b/tests/auth_tests/models/with_integer_username.py @@ -17,7 +17,7 @@ class IntegerUsernameUser(AbstractBaseUser): username = models.IntegerField() password = models.CharField(max_length=255) - USERNAME_FIELD = 'username' - REQUIRED_FIELDS = ['username', 'password'] + USERNAME_FIELD = "username" + REQUIRED_FIELDS = ["username", "password"] objects = IntegerUsernameUserManager() diff --git a/tests/auth_tests/models/with_many_to_many.py b/tests/auth_tests/models/with_many_to_many.py index 82142048ec..0c51365143 100644 --- a/tests/auth_tests/models/with_many_to_many.py +++ b/tests/auth_tests/models/with_many_to_many.py @@ -21,18 +21,18 @@ class CustomUserWithM2M(AbstractBaseUser): custom_objects = CustomUserWithM2MManager() - USERNAME_FIELD = 'username' - REQUIRED_FIELDS = ['orgs'] + USERNAME_FIELD = "username" + REQUIRED_FIELDS = ["orgs"] class CustomUserWithM2MThrough(AbstractBaseUser): username = models.CharField(max_length=30, unique=True) - orgs = models.ManyToManyField(Organization, through='Membership') + orgs = models.ManyToManyField(Organization, through="Membership") custom_objects = CustomUserWithM2MManager() - USERNAME_FIELD = 'username' - REQUIRED_FIELDS = ['orgs'] + USERNAME_FIELD = "username" + REQUIRED_FIELDS = ["orgs"] class Membership(models.Model): diff --git a/tests/auth_tests/settings.py b/tests/auth_tests/settings.py index 5de7f3be45..9cf7855d44 100644 --- a/tests/auth_tests/settings.py +++ b/tests/auth_tests/settings.py @@ -1,19 +1,21 @@ import os AUTH_MIDDLEWARE = [ - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', + "django.contrib.sessions.middleware.SessionMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", ] -AUTH_TEMPLATES = [{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(os.path.dirname(__file__), 'templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, -}] +AUTH_TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(os.path.dirname(__file__), "templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + } +] diff --git a/tests/auth_tests/test_admin_multidb.py b/tests/auth_tests/test_admin_multidb.py index fac2c0fc7e..20faab25d8 100644 --- a/tests/auth_tests/test_admin_multidb.py +++ b/tests/auth_tests/test_admin_multidb.py @@ -16,17 +16,17 @@ class Router: db_for_write = db_for_read -site = admin.AdminSite(name='test_adminsite') +site = admin.AdminSite(name="test_adminsite") site.register(User, admin_class=UserAdmin) urlpatterns = [ - path('admin/', site.urls), + path("admin/", site.urls), ] -@override_settings(ROOT_URLCONF=__name__, DATABASE_ROUTERS=['%s.Router' % __name__]) +@override_settings(ROOT_URLCONF=__name__, DATABASE_ROUTERS=["%s.Router" % __name__]) class MultiDatabaseTests(TestCase): - databases = {'default', 'other'} + databases = {"default", "other"} @classmethod def setUpTestData(cls): @@ -34,18 +34,23 @@ class MultiDatabaseTests(TestCase): for db in cls.databases: Router.target_db = db cls.superusers[db] = User.objects.create_superuser( - username='admin', password='something', email='test@test.org', + username="admin", + password="something", + email="test@test.org", ) - @mock.patch('django.contrib.auth.admin.transaction') + @mock.patch("django.contrib.auth.admin.transaction") def test_add_view(self, mock): for db in self.databases: with self.subTest(db_connection=db): Router.target_db = db self.client.force_login(self.superusers[db]) - self.client.post(reverse('test_adminsite:auth_user_add'), { - 'username': 'some_user', - 'password1': 'helloworld', - 'password2': 'helloworld', - }) + self.client.post( + reverse("test_adminsite:auth_user_add"), + { + "username": "some_user", + "password1": "helloworld", + "password2": "helloworld", + }, + ) mock.atomic.assert_called_with(using=db) diff --git a/tests/auth_tests/test_auth_backends.py b/tests/auth_tests/test_auth_backends.py index d1471466d7..a535f329d2 100644 --- a/tests/auth_tests/test_auth_backends.py +++ b/tests/auth_tests/test_auth_backends.py @@ -3,8 +3,12 @@ from datetime import date from unittest import mock from django.contrib.auth import ( - BACKEND_SESSION_KEY, SESSION_KEY, _clean_credentials, authenticate, - get_user, signals, + 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 @@ -13,50 +17,58 @@ 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, + 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, + CustomPermissionsUser, + CustomUser, + CustomUserWithoutIsActiveField, + ExtensionUser, + UUIDUser, ) class SimpleBackend(BaseBackend): def get_user_permissions(self, user_obj, obj=None): - return ['user_perm'] + return ["user_perm"] def get_group_permissions(self, user_obj, obj=None): - return ['group_perm'] + return ["group_perm"] -@override_settings(AUTHENTICATION_BACKENDS=['auth_tests.test_auth_backends.SimpleBackend']) +@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') + 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'}) + self.assertEqual(self.user.get_user_permissions(), {"user_perm"}) def test_get_group_permissions(self): - self.assertEqual(self.user.get_group_permissions(), {'group_perm'}) + 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'}) + 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) + 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.' + msg = "perm_list must be an iterable of permissions." with self.assertRaisesMessage(ValueError, msg): - self.user.has_perms('user_perm') + self.user.has_perms("user_perm") with self.assertRaisesMessage(ValueError, msg): self.user.has_perms(object()) @@ -78,11 +90,12 @@ class BaseModelBackendTest: level UserModel attribute, and a create_users() method to construct two users for test purposes. """ - backend = 'django.contrib.auth.backends.ModelBackend' + + backend = "django.contrib.auth.backends.ModelBackend" def setUp(self): self.patched_settings = modify_settings( - AUTHENTICATION_BACKENDS={'append': self.backend}, + AUTHENTICATION_BACKENDS={"append": self.backend}, ) self.patched_settings.enable() self.create_users() @@ -96,72 +109,84 @@ class BaseModelBackendTest: def test_has_perm(self): user = self.UserModel._default_manager.get(pk=self.user.pk) - self.assertIs(user.has_perm('auth.test'), False) + self.assertIs(user.has_perm("auth.test"), False) user.is_staff = True user.save() - self.assertIs(user.has_perm('auth.test'), False) + self.assertIs(user.has_perm("auth.test"), False) user.is_superuser = True user.save() - self.assertIs(user.has_perm('auth.test'), True) + 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) + 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') + 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_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) + 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') + 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') + 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'} + 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) + 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') + 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_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) + 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) + 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') + 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'}) + 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): """ @@ -172,19 +197,25 @@ class BaseModelBackendTest: 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_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') + 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'}) + 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): + 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()) @@ -198,17 +229,23 @@ class BaseModelBackendTest: 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_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') + 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'}) + 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() @@ -222,29 +259,33 @@ class BaseModelBackendTest: 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']) + @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.set_password("test") self.user.save() CountingMD5PasswordHasher.calls = 0 username = getattr(self.user, self.UserModel.USERNAME_FIELD) - authenticate(username=username, password='test') + authenticate(username=username, password="test") self.assertEqual(CountingMD5PasswordHasher.calls, 1) CountingMD5PasswordHasher.calls = 0 - authenticate(username='no_such_user', password='test') + authenticate(username="no_such_user", password="test") self.assertEqual(CountingMD5PasswordHasher.calls, 1) - @override_settings(PASSWORD_HASHERS=['auth_tests.test_auth_backends.CountingMD5PasswordHasher']) + @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'}, + {"username": getattr(self.user, self.UserModel.USERNAME_FIELD)}, + {"password": "test"}, ): with self.subTest(credentials=credentials): with self.assertNumQueries(0): @@ -256,15 +297,18 @@ class ModelBackendTest(BaseModelBackendTest, TestCase): """ Tests for the ModelBackend using the default User model. """ + UserModel = User - user_credentials = {'username': 'test', 'password': 'test'} + user_credentials = {"username": "test", "password": "test"} def create_users(self): - self.user = User.objects.create_user(email='test@example.com', **self.user_credentials) + 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', + username="test2", + email="test2@example.com", + password="test", ) def test_authenticate_inactive(self): @@ -276,18 +320,20 @@ class ModelBackendTest(BaseModelBackendTest, TestCase): self.user.save() self.assertIsNone(authenticate(**self.user_credentials)) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithoutIsActiveField') + @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', + username="test", + email="test@example.com", + password="test", ) - self.assertEqual(authenticate(username='test', password='test'), user) + self.assertEqual(authenticate(username="test", password="test"), user) -@override_settings(AUTH_USER_MODEL='auth_tests.ExtensionUser') +@override_settings(AUTH_USER_MODEL="auth_tests.ExtensionUser") class ExtensionUserModelBackendTest(BaseModelBackendTest, TestCase): """ Tests for the ModelBackend using the custom ExtensionUser model. @@ -309,20 +355,20 @@ class ExtensionUserModelBackendTest(BaseModelBackendTest, TestCase): 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) + 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) + username="test2", + email="test2@example.com", + password="test", + date_of_birth=date(1976, 11, 8), ) -@override_settings(AUTH_USER_MODEL='auth_tests.CustomPermissionsUser') +@override_settings(AUTH_USER_MODEL="auth_tests.CustomPermissionsUser") class CustomPermissionsUserModelBackendTest(BaseModelBackendTest, TestCase): """ Tests for the ModelBackend using the CustomPermissionsUser model. @@ -336,18 +382,14 @@ class CustomPermissionsUserModelBackendTest(BaseModelBackendTest, TestCase): def create_users(self): self.user = CustomPermissionsUser._default_manager.create_user( - email='test@example.com', - password='test', - date_of_birth=date(2006, 4, 25) + 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) + email="test2@example.com", password="test", date_of_birth=date(1976, 11, 8) ) -@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') +@override_settings(AUTH_USER_MODEL="auth_tests.CustomUser") class CustomUserModelBackendAuthenticateTest(TestCase): """ The model backend can accept a credentials kwarg labeled with @@ -356,24 +398,23 @@ class CustomUserModelBackendAuthenticateTest(TestCase): def test_authenticate(self): test_user = CustomUser._default_manager.create_user( - email='test@example.com', - password='test', - date_of_birth=date(2006, 4, 25) + email="test@example.com", password="test", date_of_birth=date(2006, 4, 25) ) - authenticated_user = authenticate(email='test@example.com', password='test') + authenticated_user = authenticate(email="test@example.com", password="test") self.assertEqual(test_user, authenticated_user) -@override_settings(AUTH_USER_MODEL='auth_tests.UUIDUser') +@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) + 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: @@ -386,47 +427,49 @@ class SimpleRowlevelBackend: return # We only support row level perms if isinstance(obj, TestObj): - if user.username == 'test2': + if user.username == "test2": return True - elif user.is_anonymous and perm == 'anon': + elif user.is_anonymous and perm == "anon": return True - elif not user.is_active and perm == 'inactive': + 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' + 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'] + return ["none"] if user.is_anonymous: - return ['anon'] - if user.username == 'test2': - return ['simple', 'advanced'] + return ["anon"] + if user.username == "test2": + return ["simple", "advanced"] else: - return ['simple'] + 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'] + return ["none"] - if 'test_group' in [group.name for group in user.groups.all()]: - return ['group_perm'] + if "test_group" in [group.name for group in user.groups.all()]: + return ["group_perm"] else: - return ['none'] + return ["none"] -@modify_settings(AUTHENTICATION_BACKENDS={ - 'append': 'auth_tests.test_auth_backends.SimpleRowlevelBackend', -}) +@modify_settings( + AUTHENTICATION_BACKENDS={ + "append": "auth_tests.test_auth_backends.SimpleRowlevelBackend", + } +) class RowlevelBackendTest(TestCase): """ Tests for auth backend that supports object level permissions @@ -434,9 +477,9 @@ class RowlevelBackendTest(TestCase): @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') + 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 @@ -445,27 +488,29 @@ class RowlevelBackendTest(TestCase): 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) + 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.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') + group = Group.objects.create(name="test_group") self.user3.groups.add(group) - self.assertEqual(self.user3.get_group_permissions(TestObj()), {'group_perm'}) + self.assertEqual(self.user3.get_group_permissions(TestObj()), {"group_perm"}) @override_settings( - AUTHENTICATION_BACKENDS=['auth_tests.test_auth_backends.SimpleRowlevelBackend'], + AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.SimpleRowlevelBackend"], ) class AnonymousUserBackendTest(SimpleTestCase): """ @@ -476,17 +521,17 @@ class AnonymousUserBackendTest(SimpleTestCase): 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) + 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) + 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.' + msg = "perm_list must be an iterable of permissions." with self.assertRaisesMessage(ValueError, msg): - self.user1.has_perms('perm') + self.user1.has_perms("perm") with self.assertRaisesMessage(ValueError, msg): self.user1.has_perms(object()) @@ -495,7 +540,7 @@ class AnonymousUserBackendTest(SimpleTestCase): self.assertIs(self.user1.has_module_perms("app2"), False) def test_get_all_permissions(self): - self.assertEqual(self.user1.get_all_permissions(TestObj()), {'anon'}) + self.assertEqual(self.user1.get_all_permissions(TestObj()), {"anon"}) @override_settings(AUTHENTICATION_BACKENDS=[]) @@ -503,20 +548,23 @@ 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') + 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?' + "No authentication backends have been defined. " + "Does AUTHENTICATION_BACKENDS contain anything?" ) with self.assertRaisesMessage(ImproperlyConfigured, msg): - self.user.has_perm(('perm', TestObj())) + self.user.has_perm(("perm", TestObj())) -@override_settings(AUTHENTICATION_BACKENDS=['auth_tests.test_auth_backends.SimpleRowlevelBackend']) +@override_settings( + AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.SimpleRowlevelBackend"] +) class InActiveUserBackendTest(TestCase): """ Tests for an inactive user @@ -524,13 +572,13 @@ class InActiveUserBackendTest(TestCase): @classmethod def setUpTestData(cls): - cls.user1 = User.objects.create_user('test', 'test@example.com', 'test') + 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) + 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) @@ -556,11 +604,12 @@ class PermissionDeniedBackendTest(TestCase): """ Other backends are not checked once a backend raises PermissionDenied """ - backend = 'auth_tests.test_auth_backends.PermissionDeniedBackend' + + backend = "auth_tests.test_auth_backends.PermissionDeniedBackend" @classmethod def setUpTestData(cls): - cls.user1 = User.objects.create_user('test', 'test@example.com', 'test') + cls.user1 = User.objects.create_user("test", "test@example.com", "test") def setUp(self): self.user_login_failed = [] @@ -572,34 +621,41 @@ class PermissionDeniedBackendTest(TestCase): def user_login_failed_listener(self, sender, credentials, **kwargs): self.user_login_failed.append(credentials) - @modify_settings(AUTHENTICATION_BACKENDS={'prepend': backend}) + @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')) + self.assertIsNone(authenticate(username="test", password="test")) # user_login_failed signal is sent. - self.assertEqual(self.user_login_failed, [{'password': '********************', 'username': 'test'}]) + self.assertEqual( + self.user_login_failed, + [{"password": "********************", "username": "test"}], + ) - @modify_settings(AUTHENTICATION_BACKENDS={'append': backend}) + @modify_settings(AUTHENTICATION_BACKENDS={"append": backend}) def test_authenticates(self): - self.assertEqual(authenticate(username='test', password='test'), self.user1) + self.assertEqual(authenticate(username="test", password="test"), self.user1) - @modify_settings(AUTHENTICATION_BACKENDS={'prepend': backend}) + @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') + 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) + self.assertIs(self.user1.has_perm("auth.test"), False) + self.assertIs(self.user1.has_module_perms("auth"), False) - @modify_settings(AUTHENTICATION_BACKENDS={'append': backend}) + @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') + 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) + self.assertIs(self.user1.has_perm("auth.test"), True) + self.assertIs(self.user1.has_module_perms("auth"), True) class NewModelBackend(ModelBackend): @@ -610,11 +666,12 @@ 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' + backend = "auth_tests.test_auth_backends.NewModelBackend" + + TEST_USERNAME = "test_user" + TEST_PASSWORD = "test_password" + TEST_EMAIL = "test@example.com" @classmethod def setUpTestData(cls): @@ -627,16 +684,19 @@ class ChangedBackendSettingsTest(TestCase): logged-in users disconnect. """ # Get a session for the test user - self.assertTrue(self.client.login( - username=self.TEST_USERNAME, - password=self.TEST_PASSWORD, - )) + 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']): + with self.settings( + AUTHENTICATION_BACKENDS=["django.contrib.auth.backends.ModelBackend"] + ): # Get the user from the request user = get_user(request) @@ -651,7 +711,7 @@ class TypeErrorBackend: Always raises TypeError. """ - @sensitive_variables('password') + @sensitive_variables("password") def authenticate(self, request, username=None, password=None): raise TypeError @@ -671,31 +731,35 @@ class SkippedBackendWithDecoratedMethod: class AuthenticateTests(TestCase): @classmethod def setUpTestData(cls): - cls.user1 = User.objects.create_user('test', 'test@example.com', 'test') + cls.user1 = User.objects.create_user("test", "test@example.com", "test") def setUp(self): - self.sensitive_password = 'mypassword' + self.sensitive_password = "mypassword" - @override_settings(AUTHENTICATION_BACKENDS=['auth_tests.test_auth_backends.TypeErrorBackend']) + @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') + authenticate(username="test", password="test") - @override_settings(AUTHENTICATION_BACKENDS=['auth_tests.test_auth_backends.TypeErrorBackend']) + @override_settings( + AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.TypeErrorBackend"] + ) def test_authenticate_sensitive_variables(self): try: - authenticate(username='testusername', password=self.sensitive_password) + authenticate(username="testusername", password=self.sensitive_password) except TypeError: exc_info = sys.exc_info() rf = RequestFactory() - response = technical_500_response(rf.get('/'), *exc_info) + 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, "TypeErrorBackend", status_code=500) self.assertContains( response, '<tr><td>credentials</td><td class="code">' - '<pre>'********************'</pre></td></tr>', + "<pre>'********************'</pre></td></tr>", html=True, status_code=500, ) @@ -707,33 +771,37 @@ class AuthenticateTests(TestCase): except TypeError: exc_info = sys.exc_info() rf = RequestFactory() - response = technical_500_response(rf.get('/'), *exc_info) + 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>', + "<pre>'********************'</pre></td></tr>", html=True, status_code=500, ) - @override_settings(AUTHENTICATION_BACKENDS=( - 'auth_tests.test_auth_backends.SkippedBackend', - 'django.contrib.auth.backends.ModelBackend', - )) + @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) + self.assertEqual(authenticate(username="test", password="test"), self.user1) - @override_settings(AUTHENTICATION_BACKENDS=( - 'auth_tests.test_auth_backends.SkippedBackendWithDecoratedMethod', - 'django.contrib.auth.backends.ModelBackend', - )) + @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) + self.assertEqual(authenticate(username="test", password="test"), self.user1) class ImproperlyConfiguredUserModelTest(TestCase): @@ -741,14 +809,15 @@ 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') + cls.user1 = User.objects.create_user("test", "test@example.com", "test") def setUp(self): - self.client.login(username='test', password='test') + self.client.login(username="test", password="test") - @override_settings(AUTH_USER_MODEL='thismodel.doesntexist') + @override_settings(AUTH_USER_MODEL="thismodel.doesntexist") def test_does_not_shadow_exception(self): # Prepare a request object request = HttpRequest() @@ -780,13 +849,13 @@ class ImportedBackendTests(TestCase): as the one defined in AUTHENTICATION_BACKENDS setting. """ - backend = 'auth_tests.backend_alias.ImportedModelBackend' + 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) + 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 @@ -794,10 +863,10 @@ class ImportedBackendTests(TestCase): class SelectingBackendTests(TestCase): - backend = 'auth_tests.test_auth_backends.CustomModelBackend' - other_backend = 'auth_tests.test_auth_backends.OtherModelBackend' - username = 'username' - password = 'password' + 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() @@ -806,49 +875,51 @@ class SelectingBackendTests(TestCase): @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) + 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) + 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.' + "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) + 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\'>).' + "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) + 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']) +@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'} + + 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 + email="test@example.com", is_active=False, **cls.user_credentials ) def test_authenticate(self): diff --git a/tests/auth_tests/test_basic.py b/tests/auth_tests/test_basic.py index 4cba35eb41..4b491e521e 100644 --- a/tests/auth_tests/test_basic.py +++ b/tests/auth_tests/test_basic.py @@ -12,23 +12,23 @@ from .models import CustomUser class BasicTestCase(TestCase): def test_user(self): "Users can be created and can set their password" - u = User.objects.create_user('testuser', 'test@example.com', 'testpw') + u = User.objects.create_user("testuser", "test@example.com", "testpw") self.assertTrue(u.has_usable_password()) - self.assertFalse(u.check_password('bad')) - self.assertTrue(u.check_password('testpw')) + self.assertFalse(u.check_password("bad")) + self.assertTrue(u.check_password("testpw")) # Check we can manually set an unusable password u.set_unusable_password() u.save() - self.assertFalse(u.check_password('testpw')) + self.assertFalse(u.check_password("testpw")) self.assertFalse(u.has_usable_password()) - u.set_password('testpw') - self.assertTrue(u.check_password('testpw')) + u.set_password("testpw") + self.assertTrue(u.check_password("testpw")) u.set_password(None) self.assertFalse(u.has_usable_password()) # Check username getter - self.assertEqual(u.get_username(), 'testuser') + self.assertEqual(u.get_username(), "testuser") # Check authentication/permissions self.assertFalse(u.is_anonymous) @@ -38,15 +38,15 @@ class BasicTestCase(TestCase): self.assertFalse(u.is_superuser) # Check API-based user creation with no password - u2 = User.objects.create_user('testuser2', 'test2@example.com') + u2 = User.objects.create_user("testuser2", "test2@example.com") self.assertFalse(u2.has_usable_password()) def test_unicode_username(self): - User.objects.create_user('jörg') - User.objects.create_user('Григорий') + User.objects.create_user("jörg") + User.objects.create_user("Григорий") # Two equivalent Unicode normalized usernames are duplicates. - omega_username = 'iamtheΩ' # U+03A9 GREEK CAPITAL LETTER OMEGA - ohm_username = 'iamtheΩ' # U+2126 OHM SIGN + omega_username = "iamtheΩ" # U+03A9 GREEK CAPITAL LETTER OMEGA + ohm_username = "iamtheΩ" # U+2126 OHM SIGN User.objects.create_user(ohm_username) with self.assertRaises(IntegrityError): User.objects.create_user(omega_username) @@ -55,20 +55,17 @@ class BasicTestCase(TestCase): "Users can be created without an email" cases = [ {}, - {'email': ''}, - {'email': None}, + {"email": ""}, + {"email": None}, ] for i, kwargs in enumerate(cases): with self.subTest(**kwargs): - u = User.objects.create_user( - 'testuser{}'.format(i), - **kwargs - ) - self.assertEqual(u.email, '') + u = User.objects.create_user("testuser{}".format(i), **kwargs) + self.assertEqual(u.email, "") def test_superuser(self): "Check the creation and properties of a superuser" - super = User.objects.create_superuser('super', 'super@example.com', 'super') + super = User.objects.create_superuser("super", "super@example.com", "super") self.assertTrue(super.is_superuser) self.assertTrue(super.is_active) self.assertTrue(super.is_staff) @@ -76,38 +73,35 @@ class BasicTestCase(TestCase): def test_superuser_no_email_or_password(self): cases = [ {}, - {'email': ''}, - {'email': None}, - {'password': None}, + {"email": ""}, + {"email": None}, + {"password": None}, ] for i, kwargs in enumerate(cases): with self.subTest(**kwargs): - superuser = User.objects.create_superuser( - 'super{}'.format(i), - **kwargs - ) - self.assertEqual(superuser.email, '') + superuser = User.objects.create_superuser("super{}".format(i), **kwargs) + self.assertEqual(superuser.email, "") self.assertFalse(superuser.has_usable_password()) def test_get_user_model(self): "The current user model can be retrieved" self.assertEqual(get_user_model(), User) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUser") def test_swappable_user(self): "The current user model can be swapped out for another" self.assertEqual(get_user_model(), CustomUser) with self.assertRaises(AttributeError): User.objects.all() - @override_settings(AUTH_USER_MODEL='badsetting') + @override_settings(AUTH_USER_MODEL="badsetting") def test_swappable_user_bad_setting(self): "The alternate user setting must point to something in the format app.model" msg = "AUTH_USER_MODEL must be of the form 'app_label.model_name'" with self.assertRaisesMessage(ImproperlyConfigured, msg): get_user_model() - @override_settings(AUTH_USER_MODEL='thismodel.doesntexist') + @override_settings(AUTH_USER_MODEL="thismodel.doesntexist") def test_swappable_user_nonexistent_model(self): "The current user model must point to an installed model" msg = ( @@ -119,16 +113,15 @@ class BasicTestCase(TestCase): def test_user_verbose_names_translatable(self): "Default User model verbose names are translatable (#19945)" - with translation.override('en'): - self.assertEqual(User._meta.verbose_name, 'user') - self.assertEqual(User._meta.verbose_name_plural, 'users') - with translation.override('es'): - self.assertEqual(User._meta.verbose_name, 'usuario') - self.assertEqual(User._meta.verbose_name_plural, 'usuarios') + with translation.override("en"): + self.assertEqual(User._meta.verbose_name, "user") + self.assertEqual(User._meta.verbose_name_plural, "users") + with translation.override("es"): + self.assertEqual(User._meta.verbose_name, "usuario") + self.assertEqual(User._meta.verbose_name_plural, "usuarios") class TestGetUser(TestCase): - def test_get_user_anonymous(self): request = HttpRequest() request.session = self.client.session @@ -136,8 +129,10 @@ class TestGetUser(TestCase): self.assertIsInstance(user, AnonymousUser) def test_get_user(self): - created_user = User.objects.create_user('testuser', 'test@example.com', 'testpw') - self.client.login(username='testuser', password='testpw') + created_user = User.objects.create_user( + "testuser", "test@example.com", "testpw" + ) + self.client.login(username="testuser", password="testpw") request = HttpRequest() request.session = self.client.session user = get_user(request) diff --git a/tests/auth_tests/test_checks.py b/tests/auth_tests/test_checks.py index 4dc1ef4aec..cd19fbcc9b 100644 --- a/tests/auth_tests/test_checks.py +++ b/tests/auth_tests/test_checks.py @@ -1,154 +1,171 @@ -from django.contrib.auth.checks import ( - check_models_permissions, check_user_model, -) +from django.contrib.auth.checks import check_models_permissions, check_user_model from django.contrib.auth.models import AbstractBaseUser from django.core import checks from django.db import models from django.db.models import Q, UniqueConstraint -from django.test import ( - SimpleTestCase, override_settings, override_system_checks, -) +from django.test import SimpleTestCase, override_settings, override_system_checks from django.test.utils import isolate_apps from .models import CustomUserNonUniqueUsername -@isolate_apps('auth_tests', attr_name='apps') +@isolate_apps("auth_tests", attr_name="apps") @override_system_checks([check_user_model]) class UserModelChecksTests(SimpleTestCase): - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonListRequiredFields') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserNonListRequiredFields") def test_required_fields_is_list(self): """REQUIRED_FIELDS should be a list.""" + class CustomUserNonListRequiredFields(AbstractBaseUser): username = models.CharField(max_length=30, unique=True) date_of_birth = models.DateField() - USERNAME_FIELD = 'username' - REQUIRED_FIELDS = 'date_of_birth' + USERNAME_FIELD = "username" + REQUIRED_FIELDS = "date_of_birth" errors = checks.run_checks(app_configs=self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "'REQUIRED_FIELDS' must be a list or tuple.", - obj=CustomUserNonListRequiredFields, - id='auth.E001', - ), - ]) - - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserBadRequiredFields') + self.assertEqual( + errors, + [ + checks.Error( + "'REQUIRED_FIELDS' must be a list or tuple.", + obj=CustomUserNonListRequiredFields, + id="auth.E001", + ), + ], + ) + + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserBadRequiredFields") def test_username_not_in_required_fields(self): """USERNAME_FIELD should not appear in REQUIRED_FIELDS.""" + class CustomUserBadRequiredFields(AbstractBaseUser): username = models.CharField(max_length=30, unique=True) date_of_birth = models.DateField() - USERNAME_FIELD = 'username' - REQUIRED_FIELDS = ['username', 'date_of_birth'] + USERNAME_FIELD = "username" + REQUIRED_FIELDS = ["username", "date_of_birth"] errors = checks.run_checks(self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "The field named as the 'USERNAME_FIELD' for a custom user model " - "must not be included in 'REQUIRED_FIELDS'.", - hint=( - "The 'USERNAME_FIELD' is currently set to 'username', you " - "should remove 'username' from the 'REQUIRED_FIELDS'." + self.assertEqual( + errors, + [ + checks.Error( + "The field named as the 'USERNAME_FIELD' for a custom user model " + "must not be included in 'REQUIRED_FIELDS'.", + hint=( + "The 'USERNAME_FIELD' is currently set to 'username', you " + "should remove 'username' from the 'REQUIRED_FIELDS'." + ), + obj=CustomUserBadRequiredFields, + id="auth.E002", ), - obj=CustomUserBadRequiredFields, - id='auth.E002', - ), - ]) + ], + ) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonUniqueUsername') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserNonUniqueUsername") def test_username_non_unique(self): """ A non-unique USERNAME_FIELD raises an error only if the default authentication backend is used. Otherwise, a warning is raised. """ errors = checks.run_checks() - self.assertEqual(errors, [ - checks.Error( - "'CustomUserNonUniqueUsername.username' must be " - "unique because it is named as the 'USERNAME_FIELD'.", - obj=CustomUserNonUniqueUsername, - id='auth.E003', - ), - ]) - with self.settings(AUTHENTICATION_BACKENDS=['my.custom.backend']): - errors = checks.run_checks() - self.assertEqual(errors, [ - checks.Warning( - "'CustomUserNonUniqueUsername.username' is named as " - "the 'USERNAME_FIELD', but it is not unique.", - hint='Ensure that your authentication backend(s) can handle non-unique usernames.', + self.assertEqual( + errors, + [ + checks.Error( + "'CustomUserNonUniqueUsername.username' must be " + "unique because it is named as the 'USERNAME_FIELD'.", obj=CustomUserNonUniqueUsername, - id='auth.W004', + id="auth.E003", ), - ]) + ], + ) + with self.settings(AUTHENTICATION_BACKENDS=["my.custom.backend"]): + errors = checks.run_checks() + self.assertEqual( + errors, + [ + checks.Warning( + "'CustomUserNonUniqueUsername.username' is named as " + "the 'USERNAME_FIELD', but it is not unique.", + hint="Ensure that your authentication backend(s) can handle non-unique usernames.", + obj=CustomUserNonUniqueUsername, + id="auth.W004", + ), + ], + ) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserPartiallyUnique') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserPartiallyUnique") def test_username_partially_unique(self): class CustomUserPartiallyUnique(AbstractBaseUser): username = models.CharField(max_length=30) - USERNAME_FIELD = 'username' + USERNAME_FIELD = "username" class Meta: constraints = [ UniqueConstraint( - fields=['username'], - name='partial_username_unique', + fields=["username"], + name="partial_username_unique", condition=Q(password__isnull=False), ), ] errors = checks.run_checks(app_configs=self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "'CustomUserPartiallyUnique.username' must be unique because " - "it is named as the 'USERNAME_FIELD'.", - obj=CustomUserPartiallyUnique, - id='auth.E003', - ), - ]) - with self.settings(AUTHENTICATION_BACKENDS=['my.custom.backend']): - errors = checks.run_checks(app_configs=self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Warning( - "'CustomUserPartiallyUnique.username' is named as the " - "'USERNAME_FIELD', but it is not unique.", - hint=( - 'Ensure that your authentication backend(s) can ' - 'handle non-unique usernames.' - ), + self.assertEqual( + errors, + [ + checks.Error( + "'CustomUserPartiallyUnique.username' must be unique because " + "it is named as the 'USERNAME_FIELD'.", obj=CustomUserPartiallyUnique, - id='auth.W004', + id="auth.E003", ), - ]) + ], + ) + with self.settings(AUTHENTICATION_BACKENDS=["my.custom.backend"]): + errors = checks.run_checks(app_configs=self.apps.get_app_configs()) + self.assertEqual( + errors, + [ + checks.Warning( + "'CustomUserPartiallyUnique.username' is named as the " + "'USERNAME_FIELD', but it is not unique.", + hint=( + "Ensure that your authentication backend(s) can " + "handle non-unique usernames." + ), + obj=CustomUserPartiallyUnique, + id="auth.W004", + ), + ], + ) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserUniqueConstraint') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserUniqueConstraint") def test_username_unique_with_model_constraint(self): class CustomUserUniqueConstraint(AbstractBaseUser): username = models.CharField(max_length=30) - USERNAME_FIELD = 'username' + USERNAME_FIELD = "username" class Meta: constraints = [ - UniqueConstraint(fields=['username'], name='username_unique'), + UniqueConstraint(fields=["username"], name="username_unique"), ] self.assertEqual(checks.run_checks(app_configs=self.apps.get_app_configs()), []) - with self.settings(AUTHENTICATION_BACKENDS=['my.custom.backend']): + with self.settings(AUTHENTICATION_BACKENDS=["my.custom.backend"]): errors = checks.run_checks(app_configs=self.apps.get_app_configs()) self.assertEqual(errors, []) - @override_settings(AUTH_USER_MODEL='auth_tests.BadUser') + @override_settings(AUTH_USER_MODEL="auth_tests.BadUser") def test_is_anonymous_authenticated_methods(self): """ <User Model>.is_anonymous/is_authenticated must not be methods. """ + class BadUser(AbstractBaseUser): username = models.CharField(max_length=30, unique=True) - USERNAME_FIELD = 'username' + USERNAME_FIELD = "username" def is_anonymous(self): return True @@ -157,50 +174,56 @@ class UserModelChecksTests(SimpleTestCase): return True errors = checks.run_checks(app_configs=self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Critical( - '%s.is_anonymous must be an attribute or property rather than ' - 'a method. Ignoring this is a security issue as anonymous ' - 'users will be treated as authenticated!' % BadUser, - obj=BadUser, - id='auth.C009', - ), - checks.Critical( - '%s.is_authenticated must be an attribute or property rather ' - 'than a method. Ignoring this is a security issue as anonymous ' - 'users will be treated as authenticated!' % BadUser, - obj=BadUser, - id='auth.C010', - ), - ]) - - -@isolate_apps('auth_tests', attr_name='apps') + self.assertEqual( + errors, + [ + checks.Critical( + "%s.is_anonymous must be an attribute or property rather than " + "a method. Ignoring this is a security issue as anonymous " + "users will be treated as authenticated!" % BadUser, + obj=BadUser, + id="auth.C009", + ), + checks.Critical( + "%s.is_authenticated must be an attribute or property rather " + "than a method. Ignoring this is a security issue as anonymous " + "users will be treated as authenticated!" % BadUser, + obj=BadUser, + id="auth.C010", + ), + ], + ) + + +@isolate_apps("auth_tests", attr_name="apps") @override_system_checks([check_models_permissions]) class ModelsPermissionsChecksTests(SimpleTestCase): def test_clashing_default_permissions(self): class Checked(models.Model): class Meta: - permissions = [ - ('change_checked', 'Can edit permission (duplicate)') - ] + permissions = [("change_checked", "Can edit permission (duplicate)")] + errors = checks.run_checks(self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "The permission codenamed 'change_checked' clashes with a builtin " - "permission for model 'auth_tests.Checked'.", - obj=Checked, - id='auth.E005', - ), - ]) + self.assertEqual( + errors, + [ + checks.Error( + "The permission codenamed 'change_checked' clashes with a builtin " + "permission for model 'auth_tests.Checked'.", + obj=Checked, + id="auth.E005", + ), + ], + ) def test_non_clashing_custom_permissions(self): class Checked(models.Model): class Meta: permissions = [ - ('my_custom_permission', 'Some permission'), - ('other_one', 'Some other permission'), + ("my_custom_permission", "Some permission"), + ("other_one", "Some other permission"), ] + errors = checks.run_checks(self.apps.get_app_configs()) self.assertEqual(errors, []) @@ -208,84 +231,109 @@ class ModelsPermissionsChecksTests(SimpleTestCase): class Checked(models.Model): class Meta: permissions = [ - ('my_custom_permission', 'Some permission'), - ('other_one', 'Some other permission'), - ('my_custom_permission', 'Some permission with duplicate permission code'), + ("my_custom_permission", "Some permission"), + ("other_one", "Some other permission"), + ( + "my_custom_permission", + "Some permission with duplicate permission code", + ), ] + errors = checks.run_checks(self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "The permission codenamed 'my_custom_permission' is duplicated for " - "model 'auth_tests.Checked'.", - obj=Checked, - id='auth.E006', - ), - ]) + self.assertEqual( + errors, + [ + checks.Error( + "The permission codenamed 'my_custom_permission' is duplicated for " + "model 'auth_tests.Checked'.", + obj=Checked, + id="auth.E006", + ), + ], + ) def test_verbose_name_max_length(self): class Checked(models.Model): class Meta: - verbose_name = 'some ridiculously long verbose name that is out of control' * 5 + verbose_name = ( + "some ridiculously long verbose name that is out of control" * 5 + ) + errors = checks.run_checks(self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "The verbose_name of model 'auth_tests.Checked' must be at most 244 " - "characters for its builtin permission names to be at most 255 characters.", - obj=Checked, - id='auth.E007', - ), - ]) + self.assertEqual( + errors, + [ + checks.Error( + "The verbose_name of model 'auth_tests.Checked' must be at most 244 " + "characters for its builtin permission names to be at most 255 characters.", + obj=Checked, + id="auth.E007", + ), + ], + ) def test_model_name_max_length(self): - model_name = 'X' * 94 - model = type(model_name, (models.Model,), {'__module__': self.__module__}) + model_name = "X" * 94 + model = type(model_name, (models.Model,), {"__module__": self.__module__}) errors = checks.run_checks(self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "The name of model 'auth_tests.%s' must be at most 93 " - "characters for its builtin permission codenames to be at " - "most 100 characters." % model_name, - obj=model, - id='auth.E011', - ), - ]) + self.assertEqual( + errors, + [ + checks.Error( + "The name of model 'auth_tests.%s' must be at most 93 " + "characters for its builtin permission codenames to be at " + "most 100 characters." % model_name, + obj=model, + id="auth.E011", + ), + ], + ) def test_custom_permission_name_max_length(self): - custom_permission_name = 'some ridiculously long verbose name that is out of control' * 5 + custom_permission_name = ( + "some ridiculously long verbose name that is out of control" * 5 + ) class Checked(models.Model): class Meta: permissions = [ - ('my_custom_permission', custom_permission_name), + ("my_custom_permission", custom_permission_name), ] + errors = checks.run_checks(self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "The permission named '%s' of model 'auth_tests.Checked' is longer " - "than 255 characters." % custom_permission_name, - obj=Checked, - id='auth.E008', - ), - ]) + self.assertEqual( + errors, + [ + checks.Error( + "The permission named '%s' of model 'auth_tests.Checked' is longer " + "than 255 characters." % custom_permission_name, + obj=Checked, + id="auth.E008", + ), + ], + ) def test_custom_permission_codename_max_length(self): - custom_permission_codename = 'x' * 101 + custom_permission_codename = "x" * 101 class Checked(models.Model): class Meta: permissions = [ - (custom_permission_codename, 'Custom permission'), + (custom_permission_codename, "Custom permission"), ] errors = checks.run_checks(self.apps.get_app_configs()) - self.assertEqual(errors, [ - checks.Error( - "The permission codenamed '%s' of model 'auth_tests.Checked' " - "is longer than 100 characters." % custom_permission_codename, - obj=Checked, - id='auth.E012', - ), - ]) + self.assertEqual( + errors, + [ + checks.Error( + "The permission codenamed '%s' of model 'auth_tests.Checked' " + "is longer than 100 characters." % custom_permission_codename, + obj=Checked, + id="auth.E012", + ), + ], + ) def test_empty_default_permissions(self): class Checked(models.Model): diff --git a/tests/auth_tests/test_context_processors.py b/tests/auth_tests/test_context_processors.py index 98e51a62d9..ab621313e8 100644 --- a/tests/auth_tests/test_context_processors.py +++ b/tests/auth_tests/test_context_processors.py @@ -10,23 +10,25 @@ from .settings import AUTH_MIDDLEWARE, AUTH_TEMPLATES class MockUser: def __repr__(self): - return 'MockUser()' + return "MockUser()" def has_module_perms(self, perm): - return perm == 'mockapp' + return perm == "mockapp" def has_perm(self, perm, obj=None): - return perm == 'mockapp.someperm' + return perm == "mockapp.someperm" class PermWrapperTests(SimpleTestCase): """ Test some details of the PermWrapper implementation. """ + class EQLimiterObject: """ This object makes sure __eq__ will not be called endlessly. """ + def __init__(self): self.eq_calls = 0 @@ -38,7 +40,7 @@ class PermWrapperTests(SimpleTestCase): def test_repr(self): perms = PermWrapper(MockUser()) - self.assertEqual(repr(perms), 'PermWrapper(MockUser())') + self.assertEqual(repr(perms), "PermWrapper(MockUser())") def test_permwrapper_in(self): """ @@ -46,25 +48,25 @@ class PermWrapperTests(SimpleTestCase): """ perms = PermWrapper(MockUser()) # Works for modules and full permissions. - self.assertIn('mockapp', perms) - self.assertNotIn('nonexistent', perms) - self.assertIn('mockapp.someperm', perms) - self.assertNotIn('mockapp.nonexistent', perms) + self.assertIn("mockapp", perms) + self.assertNotIn("nonexistent", perms) + self.assertIn("mockapp.someperm", perms) + self.assertNotIn("mockapp.nonexistent", perms) def test_permlookupdict_in(self): """ No endless loops if accessed with 'in' - refs #18979. """ - pldict = PermLookupDict(MockUser(), 'mockapp') + pldict = PermLookupDict(MockUser(), "mockapp") with self.assertRaises(TypeError): self.EQLimiterObject() in pldict def test_iter(self): - with self.assertRaisesMessage(TypeError, 'PermWrapper is not iterable.'): + with self.assertRaisesMessage(TypeError, "PermWrapper is not iterable."): iter(PermWrapper(MockUser())) -@override_settings(ROOT_URLCONF='auth_tests.urls', TEMPLATES=AUTH_TEMPLATES) +@override_settings(ROOT_URLCONF="auth_tests.urls", TEMPLATES=AUTH_TEMPLATES) class AuthContextProcessorTests(TestCase): """ Tests for the ``django.contrib.auth.context_processors.auth`` processor @@ -72,7 +74,9 @@ class AuthContextProcessorTests(TestCase): @classmethod def setUpTestData(cls): - cls.superuser = User.objects.create_superuser(username='super', password='secret', email='super@example.com') + cls.superuser = User.objects.create_superuser( + username="super", password="secret", email="super@example.com" + ) @override_settings(MIDDLEWARE=AUTH_MIDDLEWARE) def test_session_not_accessed(self): @@ -80,7 +84,7 @@ class AuthContextProcessorTests(TestCase): The session is not accessed simply by including the auth context processor """ - response = self.client.get('/auth_processor_no_attr_access/') + response = self.client.get("/auth_processor_no_attr_access/") self.assertContains(response, "Session not accessed") @override_settings(MIDDLEWARE=AUTH_MIDDLEWARE) @@ -89,36 +93,40 @@ class AuthContextProcessorTests(TestCase): The session is accessed if the auth context processor is used and relevant attributes accessed. """ - response = self.client.get('/auth_processor_attr_access/') + response = self.client.get("/auth_processor_attr_access/") self.assertContains(response, "Session accessed") def test_perms_attrs(self): - u = User.objects.create_user(username='normal', password='secret') + u = User.objects.create_user(username="normal", password="secret") u.user_permissions.add( Permission.objects.get( content_type=ContentType.objects.get_for_model(Permission), - codename='add_permission')) + codename="add_permission", + ) + ) self.client.force_login(u) - response = self.client.get('/auth_processor_perms/') + response = self.client.get("/auth_processor_perms/") self.assertContains(response, "Has auth permissions") self.assertContains(response, "Has auth.add_permission permissions") self.assertNotContains(response, "nonexistent") def test_perm_in_perms_attrs(self): - u = User.objects.create_user(username='normal', password='secret') + u = User.objects.create_user(username="normal", password="secret") u.user_permissions.add( Permission.objects.get( content_type=ContentType.objects.get_for_model(Permission), - codename='add_permission')) - self.client.login(username='normal', password='secret') - response = self.client.get('/auth_processor_perm_in_perms/') + codename="add_permission", + ) + ) + self.client.login(username="normal", password="secret") + response = self.client.get("/auth_processor_perm_in_perms/") self.assertContains(response, "Has auth permissions") self.assertContains(response, "Has auth.add_permission permissions") self.assertNotContains(response, "nonexistent") def test_message_attrs(self): self.client.force_login(self.superuser) - response = self.client.get('/auth_processor_messages/') + response = self.client.get("/auth_processor_messages/") self.assertContains(response, "Message 1") def test_user_attrs(self): @@ -128,9 +136,9 @@ class AuthContextProcessorTests(TestCase): # These are 'functional' level tests for common use cases. Direct # testing of the implementation (SimpleLazyObject) is in the 'utils' # tests. - self.client.login(username='super', password='secret') - user = authenticate(username='super', password='secret') - response = self.client.get('/auth_processor_user/') + self.client.login(username="super", password="secret") + user = authenticate(username="super", password="secret") + response = self.client.get("/auth_processor_user/") self.assertContains(response, "unicode: super") self.assertContains(response, "id: %d" % self.superuser.pk) self.assertContains(response, "username: super") @@ -138,10 +146,10 @@ class AuthContextProcessorTests(TestCase): self.assertContains(response, "url: /userpage/super/") # A Q() comparing a user and with another Q() (in an AND or OR fashion). - Q(user=response.context['user']) & Q(someflag=True) + Q(user=response.context["user"]) & Q(someflag=True) # Tests for user equality. This is hard because User defines # equality in a non-duck-typing way # See bug #12060 - self.assertEqual(response.context['user'], user) - self.assertEqual(user, response.context['user']) + self.assertEqual(response.context["user"], user) + self.assertEqual(user, response.context["user"]) diff --git a/tests/auth_tests/test_decorators.py b/tests/auth_tests/test_decorators.py index 469b1ad0ac..ae43adcb0a 100644 --- a/tests/auth_tests/test_decorators.py +++ b/tests/auth_tests/test_decorators.py @@ -9,7 +9,7 @@ from django.test.client import RequestFactory from .test_views import AuthViewsTestCase -@override_settings(ROOT_URLCONF='auth_tests.urls') +@override_settings(ROOT_URLCONF="auth_tests.urls") class LoginRequiredTestCase(AuthViewsTestCase): """ Tests the login_required decorators @@ -19,20 +19,24 @@ class LoginRequiredTestCase(AuthViewsTestCase): """ login_required is assignable to callable objects. """ + class CallableView: def __call__(self, *args, **kwargs): pass + login_required(CallableView()) def test_view(self): """ login_required is assignable to normal views. """ + def normal_view(request): pass + login_required(normal_view) - def test_login_required(self, view_url='/login_required/', login_url=None): + def test_login_required(self, view_url="/login_required/", login_url=None): """ login_required works on a simple view wrapped in a login_required decorator. @@ -51,70 +55,90 @@ class LoginRequiredTestCase(AuthViewsTestCase): login_required works on a simple view wrapped in a login_required decorator with a login_url set. """ - self.test_login_required(view_url='/login_required_login_url/', login_url='/somewhere/') + self.test_login_required( + view_url="/login_required_login_url/", login_url="/somewhere/" + ) class PermissionsRequiredDecoratorTest(TestCase): """ Tests for the permission_required decorator """ + factory = RequestFactory() @classmethod def setUpTestData(cls): - cls.user = models.User.objects.create(username='joe', password='qwerty') + cls.user = models.User.objects.create(username="joe", password="qwerty") # Add permissions auth.add_customuser and auth.change_customuser - perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser')) + perms = models.Permission.objects.filter( + codename__in=("add_customuser", "change_customuser") + ) cls.user.user_permissions.add(*perms) def test_many_permissions_pass(self): - - @permission_required(['auth_tests.add_customuser', 'auth_tests.change_customuser']) + @permission_required( + ["auth_tests.add_customuser", "auth_tests.change_customuser"] + ) def a_view(request): return HttpResponse() - request = self.factory.get('/rand') + + request = self.factory.get("/rand") request.user = self.user resp = a_view(request) self.assertEqual(resp.status_code, 200) def test_many_permissions_in_set_pass(self): - - @permission_required({'auth_tests.add_customuser', 'auth_tests.change_customuser'}) + @permission_required( + {"auth_tests.add_customuser", "auth_tests.change_customuser"} + ) def a_view(request): return HttpResponse() - request = self.factory.get('/rand') + + request = self.factory.get("/rand") request.user = self.user resp = a_view(request) self.assertEqual(resp.status_code, 200) def test_single_permission_pass(self): - - @permission_required('auth_tests.add_customuser') + @permission_required("auth_tests.add_customuser") def a_view(request): return HttpResponse() - request = self.factory.get('/rand') + + request = self.factory.get("/rand") request.user = self.user resp = a_view(request) self.assertEqual(resp.status_code, 200) def test_permissioned_denied_redirect(self): - - @permission_required(['auth_tests.add_customuser', 'auth_tests.change_customuser', 'nonexistent-permission']) + @permission_required( + [ + "auth_tests.add_customuser", + "auth_tests.change_customuser", + "nonexistent-permission", + ] + ) def a_view(request): return HttpResponse() - request = self.factory.get('/rand') + + request = self.factory.get("/rand") request.user = self.user resp = a_view(request) self.assertEqual(resp.status_code, 302) def test_permissioned_denied_exception_raised(self): - - @permission_required([ - 'auth_tests.add_customuser', 'auth_tests.change_customuser', 'nonexistent-permission' - ], raise_exception=True) + @permission_required( + [ + "auth_tests.add_customuser", + "auth_tests.change_customuser", + "nonexistent-permission", + ], + raise_exception=True, + ) def a_view(request): return HttpResponse() - request = self.factory.get('/rand') + + request = self.factory.get("/rand") request.user = self.user with self.assertRaises(PermissionDenied): a_view(request) diff --git a/tests/auth_tests/test_forms.py b/tests/auth_tests/test_forms.py index e208305fc6..1713d367c3 100644 --- a/tests/auth_tests/test_forms.py +++ b/tests/auth_tests/test_forms.py @@ -3,9 +3,15 @@ import re from unittest import mock from django.contrib.auth.forms import ( - AdminPasswordChangeForm, AuthenticationForm, PasswordChangeForm, - PasswordResetForm, ReadOnlyPasswordHashField, ReadOnlyPasswordHashWidget, - SetPasswordForm, UserChangeForm, UserCreationForm, + AdminPasswordChangeForm, + AuthenticationForm, + PasswordChangeForm, + PasswordResetForm, + ReadOnlyPasswordHashField, + ReadOnlyPasswordHashWidget, + SetPasswordForm, + UserChangeForm, + UserCreationForm, ) from django.contrib.auth.models import User from django.contrib.auth.signals import user_login_failed @@ -21,7 +27,9 @@ from django.utils.text import capfirst from django.utils.translation import gettext as _ from .models.custom_user import ( - CustomUser, CustomUserWithoutIsActiveField, ExtensionUser, + CustomUser, + CustomUserWithoutIsActiveField, + ExtensionUser, ) from .models.with_custom_email_field import CustomEmailField from .models.with_integer_username import IntegerUsernameUser @@ -29,75 +37,84 @@ from .settings import AUTH_TEMPLATES class TestDataMixin: - @classmethod def setUpTestData(cls): - cls.u1 = User.objects.create_user(username='testclient', password='password', email='testclient@example.com') - cls.u2 = User.objects.create_user(username='inactive', password='password', is_active=False) - cls.u3 = User.objects.create_user(username='staff', password='password') - cls.u4 = User.objects.create(username='empty_password', password='') - cls.u5 = User.objects.create(username='unmanageable_password', password='$') - cls.u6 = User.objects.create(username='unknown_password', password='foo$bar') + cls.u1 = User.objects.create_user( + username="testclient", password="password", email="testclient@example.com" + ) + cls.u2 = User.objects.create_user( + username="inactive", password="password", is_active=False + ) + cls.u3 = User.objects.create_user(username="staff", password="password") + cls.u4 = User.objects.create(username="empty_password", password="") + cls.u5 = User.objects.create(username="unmanageable_password", password="$") + cls.u6 = User.objects.create(username="unknown_password", password="foo$bar") class UserCreationFormTest(TestDataMixin, TestCase): - def test_user_already_exists(self): data = { - 'username': 'testclient', - 'password1': 'test123', - 'password2': 'test123', + "username": "testclient", + "password1": "test123", + "password2": "test123", } form = UserCreationForm(data) self.assertFalse(form.is_valid()) - self.assertEqual(form["username"].errors, - [str(User._meta.get_field('username').error_messages['unique'])]) + self.assertEqual( + form["username"].errors, + [str(User._meta.get_field("username").error_messages["unique"])], + ) def test_invalid_data(self): data = { - 'username': 'jsmith!', - 'password1': 'test123', - 'password2': 'test123', + "username": "jsmith!", + "password1": "test123", + "password2": "test123", } form = UserCreationForm(data) self.assertFalse(form.is_valid()) - validator = next(v for v in User._meta.get_field('username').validators if v.code == 'invalid') + validator = next( + v + for v in User._meta.get_field("username").validators + if v.code == "invalid" + ) self.assertEqual(form["username"].errors, [str(validator.message)]) def test_password_verification(self): # The verification password is incorrect. data = { - 'username': 'jsmith', - 'password1': 'test123', - 'password2': 'test', + "username": "jsmith", + "password1": "test123", + "password2": "test", } form = UserCreationForm(data) self.assertFalse(form.is_valid()) - self.assertEqual(form["password2"].errors, - [str(form.error_messages['password_mismatch'])]) + self.assertEqual( + form["password2"].errors, [str(form.error_messages["password_mismatch"])] + ) def test_both_passwords(self): # One (or both) passwords weren't given - data = {'username': 'jsmith'} + data = {"username": "jsmith"} form = UserCreationForm(data) - required_error = [str(Field.default_error_messages['required'])] + required_error = [str(Field.default_error_messages["required"])] self.assertFalse(form.is_valid()) - self.assertEqual(form['password1'].errors, required_error) - self.assertEqual(form['password2'].errors, required_error) + self.assertEqual(form["password1"].errors, required_error) + self.assertEqual(form["password2"].errors, required_error) - data['password2'] = 'test123' + data["password2"] = "test123" form = UserCreationForm(data) self.assertFalse(form.is_valid()) - self.assertEqual(form['password1'].errors, required_error) - self.assertEqual(form['password2'].errors, []) + self.assertEqual(form["password1"].errors, required_error) + self.assertEqual(form["password2"].errors, []) - @mock.patch('django.contrib.auth.password_validation.password_changed') + @mock.patch("django.contrib.auth.password_validation.password_changed") def test_success(self, password_changed): # The success case. data = { - 'username': 'jsmith@example.com', - 'password1': 'test123', - 'password2': 'test123', + "username": "jsmith@example.com", + "password1": "test123", + "password2": "test123", } form = UserCreationForm(data) self.assertTrue(form.is_valid()) @@ -105,33 +122,33 @@ class UserCreationFormTest(TestDataMixin, TestCase): self.assertEqual(password_changed.call_count, 0) u = form.save() self.assertEqual(password_changed.call_count, 1) - self.assertEqual(repr(u), '<User: jsmith@example.com>') + self.assertEqual(repr(u), "<User: jsmith@example.com>") def test_unicode_username(self): data = { - 'username': '宝', - 'password1': 'test123', - 'password2': 'test123', + "username": "宝", + "password1": "test123", + "password2": "test123", } form = UserCreationForm(data) self.assertTrue(form.is_valid()) u = form.save() - self.assertEqual(u.username, '宝') + self.assertEqual(u.username, "宝") def test_normalize_username(self): # The normalization happens in AbstractBaseUser.clean() and ModelForm # validation calls Model.clean(). - ohm_username = 'testΩ' # U+2126 OHM SIGN + ohm_username = "testΩ" # U+2126 OHM SIGN data = { - 'username': ohm_username, - 'password1': 'pwd2', - 'password2': 'pwd2', + "username": ohm_username, + "password1": "pwd2", + "password2": "pwd2", } form = UserCreationForm(data) self.assertTrue(form.is_valid()) user = form.save() self.assertNotEqual(user.username, ohm_username) - self.assertEqual(user.username, 'testΩ') # U+03A9 GREEK CAPITAL LETTER OMEGA + self.assertEqual(user.username, "testΩ") # U+03A9 GREEK CAPITAL LETTER OMEGA def test_duplicate_normalized_unicode(self): """ @@ -139,53 +156,62 @@ class UserCreationFormTest(TestDataMixin, TestCase): by their unicode code points only, Unicode NFKC normalization should make appear them equal to Django. """ - omega_username = 'iamtheΩ' # U+03A9 GREEK CAPITAL LETTER OMEGA - ohm_username = 'iamtheΩ' # U+2126 OHM SIGN + omega_username = "iamtheΩ" # U+03A9 GREEK CAPITAL LETTER OMEGA + ohm_username = "iamtheΩ" # U+2126 OHM SIGN self.assertNotEqual(omega_username, ohm_username) - User.objects.create_user(username=omega_username, password='pwd') + User.objects.create_user(username=omega_username, password="pwd") data = { - 'username': ohm_username, - 'password1': 'pwd2', - 'password2': 'pwd2', + "username": ohm_username, + "password1": "pwd2", + "password2": "pwd2", } form = UserCreationForm(data) self.assertFalse(form.is_valid()) self.assertEqual( - form.errors['username'], ["A user with that username already exists."] + form.errors["username"], ["A user with that username already exists."] ) - @override_settings(AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': { - 'min_length': 12, - }}, - ]) + @override_settings( + AUTH_PASSWORD_VALIDATORS=[ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + "OPTIONS": { + "min_length": 12, + }, + }, + ] + ) def test_validates_password(self): data = { - 'username': 'testclient', - 'password1': 'testclient', - 'password2': 'testclient', + "username": "testclient", + "password1": "testclient", + "password2": "testclient", } form = UserCreationForm(data) self.assertFalse(form.is_valid()) - self.assertEqual(len(form['password2'].errors), 2) - self.assertIn('The password is too similar to the username.', form['password2'].errors) + self.assertEqual(len(form["password2"].errors), 2) + self.assertIn( + "The password is too similar to the username.", form["password2"].errors + ) self.assertIn( - 'This password is too short. It must contain at least 12 characters.', - form['password2'].errors + "This password is too short. It must contain at least 12 characters.", + form["password2"].errors, ) def test_custom_form(self): class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = ExtensionUser - fields = UserCreationForm.Meta.fields + ('date_of_birth',) + fields = UserCreationForm.Meta.fields + ("date_of_birth",) data = { - 'username': 'testclient', - 'password1': 'testclient', - 'password2': 'testclient', - 'date_of_birth': '1988-02-24', + "username": "testclient", + "password1": "testclient", + "password2": "testclient", + "date_of_birth": "1988-02-24", } form = CustomUserCreationForm(data) self.assertTrue(form.is_valid()) @@ -194,13 +220,13 @@ class UserCreationFormTest(TestDataMixin, TestCase): class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = CustomUser - fields = ('email', 'date_of_birth') + fields = ("email", "date_of_birth") data = { - 'email': 'test@client222.com', - 'password1': 'testclient', - 'password2': 'testclient', - 'date_of_birth': '1988-02-24', + "email": "test@client222.com", + "password1": "testclient", + "password2": "testclient", + "date_of_birth": "1988-02-24", } form = CustomUserCreationForm(data) self.assertTrue(form.is_valid()) @@ -209,123 +235,144 @@ class UserCreationFormTest(TestDataMixin, TestCase): class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = CustomUserWithoutIsActiveField - fields = ('email',) # without USERNAME_FIELD + fields = ("email",) # without USERNAME_FIELD data = { - 'email': 'testclient@example.com', - 'password1': 'testclient', - 'password2': 'testclient', + "email": "testclient@example.com", + "password1": "testclient", + "password2": "testclient", } form = CustomUserCreationForm(data) self.assertTrue(form.is_valid()) def test_password_whitespace_not_stripped(self): data = { - 'username': 'testuser', - 'password1': ' testpassword ', - 'password2': ' testpassword ', + "username": "testuser", + "password1": " testpassword ", + "password2": " testpassword ", } form = UserCreationForm(data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['password1'], data['password1']) - self.assertEqual(form.cleaned_data['password2'], data['password2']) - - @override_settings(AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - ]) + self.assertEqual(form.cleaned_data["password1"], data["password1"]) + self.assertEqual(form.cleaned_data["password2"], data["password2"]) + + @override_settings( + AUTH_PASSWORD_VALIDATORS=[ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + ] + ) def test_password_help_text(self): form = UserCreationForm() self.assertEqual( - form.fields['password1'].help_text, - '<ul><li>Your password can’t be too similar to your other personal information.</li></ul>' + form.fields["password1"].help_text, + "<ul><li>Your password can’t be too similar to your other personal information.</li></ul>", ) - @override_settings(AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - ]) + @override_settings( + AUTH_PASSWORD_VALIDATORS=[ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + ] + ) def test_user_create_form_validates_password_with_all_data(self): """UserCreationForm password validation uses all of the form's data.""" + class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = User - fields = ('username', 'email', 'first_name', 'last_name') - form = CustomUserCreationForm({ - 'username': 'testuser', - 'password1': 'testpassword', - 'password2': 'testpassword', - 'first_name': 'testpassword', - 'last_name': 'lastname', - }) + fields = ("username", "email", "first_name", "last_name") + + form = CustomUserCreationForm( + { + "username": "testuser", + "password1": "testpassword", + "password2": "testpassword", + "first_name": "testpassword", + "last_name": "lastname", + } + ) self.assertFalse(form.is_valid()) self.assertEqual( - form.errors['password2'], - ['The password is too similar to the first name.'], + form.errors["password2"], + ["The password is too similar to the first name."], ) def test_username_field_autocapitalize_none(self): form = UserCreationForm() - self.assertEqual(form.fields['username'].widget.attrs.get('autocapitalize'), 'none') + self.assertEqual( + form.fields["username"].widget.attrs.get("autocapitalize"), "none" + ) def test_html_autocomplete_attributes(self): form = UserCreationForm() tests = ( - ('username', 'username'), - ('password1', 'new-password'), - ('password2', 'new-password'), + ("username", "username"), + ("password1", "new-password"), + ("password2", "new-password"), ) for field_name, autocomplete in tests: with self.subTest(field_name=field_name, autocomplete=autocomplete): - self.assertEqual(form.fields[field_name].widget.attrs['autocomplete'], autocomplete) + self.assertEqual( + form.fields[field_name].widget.attrs["autocomplete"], autocomplete + ) # To verify that the login form rejects inactive users, use an authentication # backend that allows them. -@override_settings(AUTHENTICATION_BACKENDS=['django.contrib.auth.backends.AllowAllUsersModelBackend']) +@override_settings( + AUTHENTICATION_BACKENDS=["django.contrib.auth.backends.AllowAllUsersModelBackend"] +) class AuthenticationFormTest(TestDataMixin, TestCase): - def test_invalid_username(self): # The user submits an invalid username. data = { - 'username': 'jsmith_does_not_exist', - 'password': 'test123', + "username": "jsmith_does_not_exist", + "password": "test123", } form = AuthenticationForm(None, data) self.assertFalse(form.is_valid()) self.assertEqual( - form.non_field_errors(), [ - form.error_messages['invalid_login'] % { - 'username': User._meta.get_field('username').verbose_name - } - ] + form.non_field_errors(), + [ + form.error_messages["invalid_login"] + % {"username": User._meta.get_field("username").verbose_name} + ], ) def test_inactive_user(self): # The user is inactive. data = { - 'username': 'inactive', - 'password': 'password', + "username": "inactive", + "password": "password", } form = AuthenticationForm(None, data) self.assertFalse(form.is_valid()) - self.assertEqual(form.non_field_errors(), [str(form.error_messages['inactive'])]) + self.assertEqual( + form.non_field_errors(), [str(form.error_messages["inactive"])] + ) # Use an authentication backend that rejects inactive users. - @override_settings(AUTHENTICATION_BACKENDS=['django.contrib.auth.backends.ModelBackend']) + @override_settings( + AUTHENTICATION_BACKENDS=["django.contrib.auth.backends.ModelBackend"] + ) def test_inactive_user_incorrect_password(self): """An invalid login doesn't leak the inactive status of a user.""" data = { - 'username': 'inactive', - 'password': 'incorrect', + "username": "inactive", + "password": "incorrect", } form = AuthenticationForm(None, data) self.assertFalse(form.is_valid()) self.assertEqual( - form.non_field_errors(), [ - form.error_messages['invalid_login'] % { - 'username': User._meta.get_field('username').verbose_name - } - ] + form.non_field_errors(), + [ + form.error_messages["invalid_login"] + % {"username": User._meta.get_field("username").verbose_name} + ], ) def test_login_failed(self): @@ -337,33 +384,44 @@ class AuthenticationFormTest(TestDataMixin, TestCase): user_login_failed.connect(signal_handler) fake_request = object() try: - form = AuthenticationForm(fake_request, { - 'username': 'testclient', - 'password': 'incorrect', - }) + form = AuthenticationForm( + fake_request, + { + "username": "testclient", + "password": "incorrect", + }, + ) self.assertFalse(form.is_valid()) - self.assertIs(signal_calls[0]['request'], fake_request) + self.assertIs(signal_calls[0]["request"], fake_request) finally: user_login_failed.disconnect(signal_handler) def test_inactive_user_i18n(self): - with self.settings(USE_I18N=True), translation.override('pt-br', deactivate=True): + with self.settings(USE_I18N=True), translation.override( + "pt-br", deactivate=True + ): # The user is inactive. data = { - 'username': 'inactive', - 'password': 'password', + "username": "inactive", + "password": "password", } form = AuthenticationForm(None, data) self.assertFalse(form.is_valid()) - self.assertEqual(form.non_field_errors(), [str(form.error_messages['inactive'])]) + self.assertEqual( + form.non_field_errors(), [str(form.error_messages["inactive"])] + ) # Use an authentication backend that allows inactive users. - @override_settings(AUTHENTICATION_BACKENDS=['django.contrib.auth.backends.AllowAllUsersModelBackend']) + @override_settings( + AUTHENTICATION_BACKENDS=[ + "django.contrib.auth.backends.AllowAllUsersModelBackend" + ] + ) def test_custom_login_allowed_policy(self): # The user is inactive, but our custom form policy allows them to log in. data = { - 'username': 'inactive', - 'password': 'password', + "username": "inactive", + "password": "password", } class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm): @@ -383,11 +441,11 @@ class AuthenticationFormTest(TestDataMixin, TestCase): form = PickyAuthenticationForm(None, data) self.assertFalse(form.is_valid()) - self.assertEqual(form.non_field_errors(), ['This user is disallowed.']) + self.assertEqual(form.non_field_errors(), ["This user is disallowed."]) data = { - 'username': 'testclient', - 'password': 'password', + "username": "testclient", + "password": "password", } form = PickyAuthenticationForm(None, data) self.assertFalse(form.is_valid()) @@ -396,102 +454,103 @@ class AuthenticationFormTest(TestDataMixin, TestCase): def test_success(self): # The success case data = { - 'username': 'testclient', - 'password': 'password', + "username": "testclient", + "password": "password", } form = AuthenticationForm(None, data) self.assertTrue(form.is_valid()) self.assertEqual(form.non_field_errors(), []) def test_unicode_username(self): - User.objects.create_user(username='Σαρα', password='pwd') + User.objects.create_user(username="Σαρα", password="pwd") data = { - 'username': 'Σαρα', - 'password': 'pwd', + "username": "Σαρα", + "password": "pwd", } form = AuthenticationForm(None, data) self.assertTrue(form.is_valid()) self.assertEqual(form.non_field_errors(), []) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomEmailField') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomEmailField") def test_username_field_max_length_matches_user_model(self): - self.assertEqual(CustomEmailField._meta.get_field('username').max_length, 255) + self.assertEqual(CustomEmailField._meta.get_field("username").max_length, 255) data = { - 'username': 'u' * 255, - 'password': 'pwd', - 'email': 'test@example.com', + "username": "u" * 255, + "password": "pwd", + "email": "test@example.com", } CustomEmailField.objects.create_user(**data) form = AuthenticationForm(None, data) - self.assertEqual(form.fields['username'].max_length, 255) - self.assertEqual(form.fields['username'].widget.attrs.get('maxlength'), 255) + self.assertEqual(form.fields["username"].max_length, 255) + self.assertEqual(form.fields["username"].widget.attrs.get("maxlength"), 255) self.assertEqual(form.errors, {}) - @override_settings(AUTH_USER_MODEL='auth_tests.IntegerUsernameUser') + @override_settings(AUTH_USER_MODEL="auth_tests.IntegerUsernameUser") def test_username_field_max_length_defaults_to_254(self): - self.assertIsNone(IntegerUsernameUser._meta.get_field('username').max_length) + self.assertIsNone(IntegerUsernameUser._meta.get_field("username").max_length) data = { - 'username': '0123456', - 'password': 'password', + "username": "0123456", + "password": "password", } IntegerUsernameUser.objects.create_user(**data) form = AuthenticationForm(None, data) - self.assertEqual(form.fields['username'].max_length, 254) - self.assertEqual(form.fields['username'].widget.attrs.get('maxlength'), 254) + self.assertEqual(form.fields["username"].max_length, 254) + self.assertEqual(form.fields["username"].widget.attrs.get("maxlength"), 254) self.assertEqual(form.errors, {}) def test_username_field_label(self): - class CustomAuthenticationForm(AuthenticationForm): username = CharField(label="Name", max_length=75) form = CustomAuthenticationForm() - self.assertEqual(form['username'].label, "Name") + self.assertEqual(form["username"].label, "Name") def test_username_field_label_not_set(self): - class CustomAuthenticationForm(AuthenticationForm): username = CharField() form = CustomAuthenticationForm() username_field = User._meta.get_field(User.USERNAME_FIELD) - self.assertEqual(form.fields['username'].label, capfirst(username_field.verbose_name)) + self.assertEqual( + form.fields["username"].label, capfirst(username_field.verbose_name) + ) def test_username_field_autocapitalize_none(self): form = AuthenticationForm() - self.assertEqual(form.fields['username'].widget.attrs.get('autocapitalize'), 'none') + self.assertEqual( + form.fields["username"].widget.attrs.get("autocapitalize"), "none" + ) def test_username_field_label_empty_string(self): - class CustomAuthenticationForm(AuthenticationForm): - username = CharField(label='') + username = CharField(label="") form = CustomAuthenticationForm() - self.assertEqual(form.fields['username'].label, "") + self.assertEqual(form.fields["username"].label, "") def test_password_whitespace_not_stripped(self): data = { - 'username': 'testuser', - 'password': ' pass ', + "username": "testuser", + "password": " pass ", } form = AuthenticationForm(None, data) form.is_valid() # Not necessary to have valid credentails for the test. - self.assertEqual(form.cleaned_data['password'], data['password']) + self.assertEqual(form.cleaned_data["password"], data["password"]) - @override_settings(AUTH_USER_MODEL='auth_tests.IntegerUsernameUser') + @override_settings(AUTH_USER_MODEL="auth_tests.IntegerUsernameUser") def test_integer_username(self): class CustomAuthenticationForm(AuthenticationForm): username = IntegerField() - user = IntegerUsernameUser.objects.create_user(username=0, password='pwd') + user = IntegerUsernameUser.objects.create_user(username=0, password="pwd") data = { - 'username': 0, - 'password': 'pwd', + "username": 0, + "password": "pwd", } form = CustomAuthenticationForm(None, data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['username'], data['username']) - self.assertEqual(form.cleaned_data['password'], data['password']) + self.assertEqual(form.cleaned_data["username"], data["username"]) + self.assertEqual(form.cleaned_data["password"], data["password"]) self.assertEqual(form.errors, {}) self.assertEqual(form.user_cache, user) @@ -500,45 +559,46 @@ class AuthenticationFormTest(TestDataMixin, TestCase): self.assertIsInstance(error, ValidationError) self.assertEqual( error.message, - 'Please enter a correct %(username)s and password. Note that both ' - 'fields may be case-sensitive.', + "Please enter a correct %(username)s and password. Note that both " + "fields may be case-sensitive.", ) - self.assertEqual(error.code, 'invalid_login') - self.assertEqual(error.params, {'username': 'username'}) + self.assertEqual(error.code, "invalid_login") + self.assertEqual(error.params, {"username": "username"}) def test_html_autocomplete_attributes(self): form = AuthenticationForm() tests = ( - ('username', 'username'), - ('password', 'current-password'), + ("username", "username"), + ("password", "current-password"), ) for field_name, autocomplete in tests: with self.subTest(field_name=field_name, autocomplete=autocomplete): - self.assertEqual(form.fields[field_name].widget.attrs['autocomplete'], autocomplete) + self.assertEqual( + form.fields[field_name].widget.attrs["autocomplete"], autocomplete + ) class SetPasswordFormTest(TestDataMixin, TestCase): - def test_password_verification(self): # The two new passwords do not match. - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'new_password1': 'abc123', - 'new_password2': 'abc', + "new_password1": "abc123", + "new_password2": "abc", } form = SetPasswordForm(user, data) self.assertFalse(form.is_valid()) self.assertEqual( form["new_password2"].errors, - [str(form.error_messages['password_mismatch'])] + [str(form.error_messages["password_mismatch"])], ) - @mock.patch('django.contrib.auth.password_validation.password_changed') + @mock.patch("django.contrib.auth.password_validation.password_changed") def test_success(self, password_changed): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'new_password1': 'abc123', - 'new_password2': 'abc123', + "new_password1": "abc123", + "new_password2": "abc123", } form = SetPasswordForm(user, data) self.assertTrue(form.is_valid()) @@ -547,51 +607,67 @@ class SetPasswordFormTest(TestDataMixin, TestCase): form.save() self.assertEqual(password_changed.call_count, 1) - @override_settings(AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': { - 'min_length': 12, - }}, - ]) + @override_settings( + AUTH_PASSWORD_VALIDATORS=[ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + "OPTIONS": { + "min_length": 12, + }, + }, + ] + ) def test_validates_password(self): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'new_password1': 'testclient', - 'new_password2': 'testclient', + "new_password1": "testclient", + "new_password2": "testclient", } form = SetPasswordForm(user, data) self.assertFalse(form.is_valid()) self.assertEqual(len(form["new_password2"].errors), 2) - self.assertIn('The password is too similar to the username.', form["new_password2"].errors) self.assertIn( - 'This password is too short. It must contain at least 12 characters.', - form["new_password2"].errors + "The password is too similar to the username.", form["new_password2"].errors + ) + self.assertIn( + "This password is too short. It must contain at least 12 characters.", + form["new_password2"].errors, ) def test_password_whitespace_not_stripped(self): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'new_password1': ' password ', - 'new_password2': ' password ', + "new_password1": " password ", + "new_password2": " password ", } form = SetPasswordForm(user, data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['new_password1'], data['new_password1']) - self.assertEqual(form.cleaned_data['new_password2'], data['new_password2']) - - @override_settings(AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': { - 'min_length': 12, - }}, - ]) + self.assertEqual(form.cleaned_data["new_password1"], data["new_password1"]) + self.assertEqual(form.cleaned_data["new_password2"], data["new_password2"]) + + @override_settings( + AUTH_PASSWORD_VALIDATORS=[ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + "OPTIONS": { + "min_length": 12, + }, + }, + ] + ) def test_help_text_translation(self): french_help_texts = [ - 'Votre mot de passe ne peut pas trop ressembler à vos autres informations personnelles.', - 'Votre mot de passe doit contenir au minimum 12 caractères.', + "Votre mot de passe ne peut pas trop ressembler à vos autres informations personnelles.", + "Votre mot de passe doit contenir au minimum 12 caractères.", ] form = SetPasswordForm(self.u1) - with translation.override('fr'): + with translation.override("fr"): html = form.as_p() for french_text in french_help_texts: self.assertIn(french_text, html) @@ -599,47 +675,54 @@ class SetPasswordFormTest(TestDataMixin, TestCase): def test_html_autocomplete_attributes(self): form = SetPasswordForm(self.u1) tests = ( - ('new_password1', 'new-password'), - ('new_password2', 'new-password'), + ("new_password1", "new-password"), + ("new_password2", "new-password"), ) for field_name, autocomplete in tests: with self.subTest(field_name=field_name, autocomplete=autocomplete): - self.assertEqual(form.fields[field_name].widget.attrs['autocomplete'], autocomplete) + self.assertEqual( + form.fields[field_name].widget.attrs["autocomplete"], autocomplete + ) class PasswordChangeFormTest(TestDataMixin, TestCase): - def test_incorrect_password(self): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'old_password': 'test', - 'new_password1': 'abc123', - 'new_password2': 'abc123', + "old_password": "test", + "new_password1": "abc123", + "new_password2": "abc123", } form = PasswordChangeForm(user, data) self.assertFalse(form.is_valid()) - self.assertEqual(form["old_password"].errors, [str(form.error_messages['password_incorrect'])]) + self.assertEqual( + form["old_password"].errors, + [str(form.error_messages["password_incorrect"])], + ) def test_password_verification(self): # The two new passwords do not match. - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'old_password': 'password', - 'new_password1': 'abc123', - 'new_password2': 'abc', + "old_password": "password", + "new_password1": "abc123", + "new_password2": "abc", } form = PasswordChangeForm(user, data) self.assertFalse(form.is_valid()) - self.assertEqual(form["new_password2"].errors, [str(form.error_messages['password_mismatch'])]) + self.assertEqual( + form["new_password2"].errors, + [str(form.error_messages["password_mismatch"])], + ) - @mock.patch('django.contrib.auth.password_validation.password_changed') + @mock.patch("django.contrib.auth.password_validation.password_changed") def test_success(self, password_changed): # The success case. - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'old_password': 'password', - 'new_password1': 'abc123', - 'new_password2': 'abc123', + "old_password": "password", + "new_password1": "abc123", + "new_password2": "abc123", } form = PasswordChangeForm(user, data) self.assertTrue(form.is_valid()) @@ -650,37 +733,45 @@ class PasswordChangeFormTest(TestDataMixin, TestCase): def test_field_order(self): # Regression test - check the order of fields: - user = User.objects.get(username='testclient') - self.assertEqual(list(PasswordChangeForm(user, {}).fields), ['old_password', 'new_password1', 'new_password2']) + user = User.objects.get(username="testclient") + self.assertEqual( + list(PasswordChangeForm(user, {}).fields), + ["old_password", "new_password1", "new_password2"], + ) def test_password_whitespace_not_stripped(self): - user = User.objects.get(username='testclient') - user.set_password(' oldpassword ') + user = User.objects.get(username="testclient") + user.set_password(" oldpassword ") data = { - 'old_password': ' oldpassword ', - 'new_password1': ' pass ', - 'new_password2': ' pass ', + "old_password": " oldpassword ", + "new_password1": " pass ", + "new_password2": " pass ", } form = PasswordChangeForm(user, data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['old_password'], data['old_password']) - self.assertEqual(form.cleaned_data['new_password1'], data['new_password1']) - self.assertEqual(form.cleaned_data['new_password2'], data['new_password2']) + self.assertEqual(form.cleaned_data["old_password"], data["old_password"]) + self.assertEqual(form.cleaned_data["new_password1"], data["new_password1"]) + self.assertEqual(form.cleaned_data["new_password2"], data["new_password2"]) def test_html_autocomplete_attributes(self): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") form = PasswordChangeForm(user) - self.assertEqual(form.fields['old_password'].widget.attrs['autocomplete'], 'current-password') + self.assertEqual( + form.fields["old_password"].widget.attrs["autocomplete"], "current-password" + ) class UserChangeFormTest(TestDataMixin, TestCase): - def test_username_validity(self): - user = User.objects.get(username='testclient') - data = {'username': 'not valid'} + user = User.objects.get(username="testclient") + data = {"username": "not valid"} form = UserChangeForm(data, instance=user) self.assertFalse(form.is_valid()) - validator = next(v for v in User._meta.get_field('username').validators if v.code == 'invalid') + validator = next( + v + for v in User._meta.get_field("username").validators + if v.code == "invalid" + ) self.assertEqual(form["username"].errors, [str(validator.message)]) def test_bug_14242(self): @@ -690,40 +781,46 @@ class UserChangeFormTest(TestDataMixin, TestCase): class MyUserForm(UserChangeForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['groups'].help_text = 'These groups give users different permissions' + self.fields[ + "groups" + ].help_text = "These groups give users different permissions" class Meta(UserChangeForm.Meta): - fields = ('groups',) + fields = ("groups",) # Just check we can create it MyUserForm({}) def test_unusable_password(self): - user = User.objects.get(username='empty_password') + user = User.objects.get(username="empty_password") user.set_unusable_password() user.save() form = UserChangeForm(instance=user) self.assertIn(_("No password set."), form.as_table()) def test_bug_17944_empty_password(self): - user = User.objects.get(username='empty_password') + user = User.objects.get(username="empty_password") form = UserChangeForm(instance=user) self.assertIn(_("No password set."), form.as_table()) def test_bug_17944_unmanageable_password(self): - user = User.objects.get(username='unmanageable_password') + user = User.objects.get(username="unmanageable_password") form = UserChangeForm(instance=user) - self.assertIn(_("Invalid password format or unknown hashing algorithm."), form.as_table()) + self.assertIn( + _("Invalid password format or unknown hashing algorithm."), form.as_table() + ) def test_bug_17944_unknown_password_algorithm(self): - user = User.objects.get(username='unknown_password') + user = User.objects.get(username="unknown_password") form = UserChangeForm(instance=user) - self.assertIn(_("Invalid password format or unknown hashing algorithm."), form.as_table()) + self.assertIn( + _("Invalid password format or unknown hashing algorithm."), form.as_table() + ) def test_bug_19133(self): "The change form does not return the password value" # Use the form to construct the POST data - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") form_for_data = UserChangeForm(instance=user) post_data = form_for_data.initial @@ -731,38 +828,42 @@ class UserChangeFormTest(TestDataMixin, TestCase): # posted here should be ignored; the form will be # valid, and give back the 'initial' value for the # password field. - post_data['password'] = 'new password' + post_data["password"] = "new password" form = UserChangeForm(instance=user, data=post_data) self.assertTrue(form.is_valid()) # original hashed password contains $ - self.assertIn('$', form.cleaned_data['password']) + self.assertIn("$", form.cleaned_data["password"]) def test_bug_19349_bound_password_field(self): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") form = UserChangeForm(data={}, instance=user) # When rendering the bound password field, # ReadOnlyPasswordHashWidget needs the initial # value to render correctly - self.assertEqual(form.initial['password'], form['password'].value()) + self.assertEqual(form.initial["password"], form["password"].value()) def test_custom_form(self): class CustomUserChangeForm(UserChangeForm): class Meta(UserChangeForm.Meta): model = ExtensionUser - fields = ('username', 'password', 'date_of_birth',) + fields = ( + "username", + "password", + "date_of_birth", + ) - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'username': 'testclient', - 'password': 'testclient', - 'date_of_birth': '1998-02-24', + "username": "testclient", + "password": "testclient", + "date_of_birth": "1998-02-24", } form = CustomUserChangeForm(data, instance=user) self.assertTrue(form.is_valid()) form.save() - self.assertEqual(form.cleaned_data['username'], 'testclient') - self.assertEqual(form.cleaned_data['date_of_birth'], datetime.date(1998, 2, 24)) + self.assertEqual(form.cleaned_data["username"], "testclient") + self.assertEqual(form.cleaned_data["date_of_birth"], datetime.date(1998, 2, 24)) def test_password_excluded(self): class UserChangeFormWithoutPassword(UserChangeForm): @@ -770,19 +871,20 @@ class UserChangeFormTest(TestDataMixin, TestCase): class Meta: model = User - exclude = ['password'] + exclude = ["password"] form = UserChangeFormWithoutPassword() - self.assertNotIn('password', form.fields) + self.assertNotIn("password", form.fields) def test_username_field_autocapitalize_none(self): form = UserChangeForm() - self.assertEqual(form.fields['username'].widget.attrs.get('autocapitalize'), 'none') + self.assertEqual( + form.fields["username"].widget.attrs.get("autocapitalize"), "none" + ) @override_settings(TEMPLATES=AUTH_TEMPLATES) class PasswordResetFormTest(TestDataMixin, TestCase): - @classmethod def setUpClass(cls): super().setUpClass() @@ -794,48 +896,48 @@ class PasswordResetFormTest(TestDataMixin, TestCase): """ Create a user and return a tuple (user_object, username, email). """ - username = 'jsmith' - email = 'jsmith@example.com' - user = User.objects.create_user(username, email, 'test123') + username = "jsmith" + email = "jsmith@example.com" + user = User.objects.create_user(username, email, "test123") return (user, username, email) def test_invalid_email(self): - data = {'email': 'not valid'} + data = {"email": "not valid"} form = PasswordResetForm(data) self.assertFalse(form.is_valid()) - self.assertEqual(form['email'].errors, [_('Enter a valid email address.')]) + self.assertEqual(form["email"].errors, [_("Enter a valid email address.")]) def test_user_email_unicode_collision(self): - User.objects.create_user('mike123', 'mike@example.org', 'test123') - User.objects.create_user('mike456', 'mıke@example.org', 'test123') - data = {'email': 'mıke@example.org'} + User.objects.create_user("mike123", "mike@example.org", "test123") + User.objects.create_user("mike456", "mıke@example.org", "test123") + data = {"email": "mıke@example.org"} form = PasswordResetForm(data) self.assertTrue(form.is_valid()) form.save() self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].to, ['mıke@example.org']) + self.assertEqual(mail.outbox[0].to, ["mıke@example.org"]) def test_user_email_domain_unicode_collision(self): - User.objects.create_user('mike123', 'mike@ixample.org', 'test123') - User.objects.create_user('mike456', 'mike@ıxample.org', 'test123') - data = {'email': 'mike@ıxample.org'} + User.objects.create_user("mike123", "mike@ixample.org", "test123") + User.objects.create_user("mike456", "mike@ıxample.org", "test123") + data = {"email": "mike@ıxample.org"} form = PasswordResetForm(data) self.assertTrue(form.is_valid()) form.save() self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].to, ['mike@ıxample.org']) + self.assertEqual(mail.outbox[0].to, ["mike@ıxample.org"]) def test_user_email_unicode_collision_nonexistent(self): - User.objects.create_user('mike123', 'mike@example.org', 'test123') - data = {'email': 'mıke@example.org'} + User.objects.create_user("mike123", "mike@example.org", "test123") + data = {"email": "mıke@example.org"} form = PasswordResetForm(data) self.assertTrue(form.is_valid()) form.save() self.assertEqual(len(mail.outbox), 0) def test_user_email_domain_unicode_collision_nonexistent(self): - User.objects.create_user('mike123', 'mike@ixample.org', 'test123') - data = {'email': 'mike@ıxample.org'} + User.objects.create_user("mike123", "mike@ixample.org", "test123") + data = {"email": "mike@ıxample.org"} form = PasswordResetForm(data) self.assertTrue(form.is_valid()) form.save() @@ -846,44 +948,51 @@ class PasswordResetFormTest(TestDataMixin, TestCase): Test nonexistent email address. This should not fail because it would expose information about registered users. """ - data = {'email': 'foo@bar.com'} + data = {"email": "foo@bar.com"} form = PasswordResetForm(data) self.assertTrue(form.is_valid()) self.assertEqual(len(mail.outbox), 0) def test_cleaned_data(self): (user, username, email) = self.create_dummy_user() - data = {'email': email} + data = {"email": email} form = PasswordResetForm(data) self.assertTrue(form.is_valid()) - form.save(domain_override='example.com') - self.assertEqual(form.cleaned_data['email'], email) + form.save(domain_override="example.com") + self.assertEqual(form.cleaned_data["email"], email) self.assertEqual(len(mail.outbox), 1) def test_custom_email_subject(self): - data = {'email': 'testclient@example.com'} + data = {"email": "testclient@example.com"} form = PasswordResetForm(data) self.assertTrue(form.is_valid()) # Since we're not providing a request object, we must provide a # domain_override to prevent the save operation from failing in the # potential case where contrib.sites is not installed. Refs #16412. - form.save(domain_override='example.com') + form.save(domain_override="example.com") self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].subject, 'Custom password reset on example.com') + self.assertEqual(mail.outbox[0].subject, "Custom password reset on example.com") def test_custom_email_constructor(self): - data = {'email': 'testclient@example.com'} + data = {"email": "testclient@example.com"} class CustomEmailPasswordResetForm(PasswordResetForm): - def send_mail(self, subject_template_name, email_template_name, - context, from_email, to_email, - html_email_template_name=None): + def send_mail( + self, + subject_template_name, + email_template_name, + context, + from_email, + to_email, + html_email_template_name=None, + ): EmailMultiAlternatives( "Forgot your password?", "Sorry to hear you forgot your password.", - None, [to_email], - ['site_monitor@example.com'], - headers={'Reply-To': 'webmaster@example.com'}, + None, + [to_email], + ["site_monitor@example.com"], + headers={"Reply-To": "webmaster@example.com"}, alternatives=[ ("Really sorry to hear you forgot your password.", "text/html") ], @@ -894,10 +1003,10 @@ class PasswordResetFormTest(TestDataMixin, TestCase): # Since we're not providing a request object, we must provide a # domain_override to prevent the save operation from failing in the # potential case where contrib.sites is not installed. Refs #16412. - form.save(domain_override='example.com') + form.save(domain_override="example.com") self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].subject, 'Forgot your password?') - self.assertEqual(mail.outbox[0].bcc, ['site_monitor@example.com']) + self.assertEqual(mail.outbox[0].subject, "Forgot your password?") + self.assertEqual(mail.outbox[0].bcc, ["site_monitor@example.com"]) self.assertEqual(mail.outbox[0].content_subtype, "plain") def test_preserve_username_case(self): @@ -905,10 +1014,10 @@ class PasswordResetFormTest(TestDataMixin, TestCase): Preserve the case of the user name (before the @ in the email address) when creating a user (#5605). """ - user = User.objects.create_user('forms_test2', 'tesT@EXAMple.com', 'test') - self.assertEqual(user.email, 'tesT@example.com') - user = User.objects.create_user('forms_test3', 'tesT', 'test') - self.assertEqual(user.email, 'tesT') + user = User.objects.create_user("forms_test2", "tesT@EXAMple.com", "test") + self.assertEqual(user.email, "tesT@example.com") + user = User.objects.create_user("forms_test3", "tesT", "test") + self.assertEqual(user.email, "tesT") def test_inactive_user(self): """ @@ -917,13 +1026,13 @@ class PasswordResetFormTest(TestDataMixin, TestCase): (user, username, email) = self.create_dummy_user() user.is_active = False user.save() - form = PasswordResetForm({'email': email}) + form = PasswordResetForm({"email": email}) self.assertTrue(form.is_valid()) form.save() self.assertEqual(len(mail.outbox), 0) def test_unusable_password(self): - user = User.objects.create_user('testuser', 'test@example.com', 'test') + user = User.objects.create_user("testuser", "test@example.com", "test") data = {"email": "test@example.com"} form = PasswordResetForm(data) self.assertTrue(form.is_valid()) @@ -948,11 +1057,13 @@ class PasswordResetFormTest(TestDataMixin, TestCase): self.assertEqual(len(mail.outbox), 1) message = mail.outbox[0].message() self.assertFalse(message.is_multipart()) - self.assertEqual(message.get_content_type(), 'text/plain') - self.assertEqual(message.get('subject'), 'Custom password reset on example.com') + self.assertEqual(message.get_content_type(), "text/plain") + self.assertEqual(message.get("subject"), "Custom password reset on example.com") self.assertEqual(len(mail.outbox[0].alternatives), 0) - self.assertEqual(message.get_all('to'), [email]) - self.assertTrue(re.match(r'^http://example.com/reset/[\w+/-]', message.get_payload())) + self.assertEqual(message.get_all("to"), [email]) + self.assertTrue( + re.match(r"^http://example.com/reset/[\w+/-]", message.get_payload()) + ) def test_save_html_email_template_name(self): """ @@ -964,53 +1075,63 @@ class PasswordResetFormTest(TestDataMixin, TestCase): (user, username, email) = self.create_dummy_user() form = PasswordResetForm({"email": email}) self.assertTrue(form.is_valid()) - form.save(html_email_template_name='registration/html_password_reset_email.html') + form.save( + html_email_template_name="registration/html_password_reset_email.html" + ) self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox[0].alternatives), 1) message = mail.outbox[0].message() - self.assertEqual(message.get('subject'), 'Custom password reset on example.com') + self.assertEqual(message.get("subject"), "Custom password reset on example.com") self.assertEqual(len(message.get_payload()), 2) self.assertTrue(message.is_multipart()) - self.assertEqual(message.get_payload(0).get_content_type(), 'text/plain') - self.assertEqual(message.get_payload(1).get_content_type(), 'text/html') - self.assertEqual(message.get_all('to'), [email]) - self.assertTrue(re.match(r'^http://example.com/reset/[\w/-]+', message.get_payload(0).get_payload())) - self.assertTrue(re.match( - r'^<html><a href="http://example.com/reset/[\w/-]+/">Link</a></html>$', - message.get_payload(1).get_payload() - )) - - @override_settings(AUTH_USER_MODEL='auth_tests.CustomEmailField') + self.assertEqual(message.get_payload(0).get_content_type(), "text/plain") + self.assertEqual(message.get_payload(1).get_content_type(), "text/html") + self.assertEqual(message.get_all("to"), [email]) + self.assertTrue( + re.match( + r"^http://example.com/reset/[\w/-]+", + message.get_payload(0).get_payload(), + ) + ) + self.assertTrue( + re.match( + r'^<html><a href="http://example.com/reset/[\w/-]+/">Link</a></html>$', + message.get_payload(1).get_payload(), + ) + ) + + @override_settings(AUTH_USER_MODEL="auth_tests.CustomEmailField") def test_custom_email_field(self): - email = 'test@mail.com' - CustomEmailField.objects.create_user('test name', 'test password', email) - form = PasswordResetForm({'email': email}) + email = "test@mail.com" + CustomEmailField.objects.create_user("test name", "test password", email) + form = PasswordResetForm({"email": email}) self.assertTrue(form.is_valid()) form.save() - self.assertEqual(form.cleaned_data['email'], email) + self.assertEqual(form.cleaned_data["email"], email) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].to, [email]) def test_html_autocomplete_attributes(self): form = PasswordResetForm() - self.assertEqual(form.fields['email'].widget.attrs['autocomplete'], 'email') + self.assertEqual(form.fields["email"].widget.attrs["autocomplete"], "email") class ReadOnlyPasswordHashTest(SimpleTestCase): - def test_bug_19349_render_with_none_value(self): # Rendering the widget with value set to None # mustn't raise an exception. widget = ReadOnlyPasswordHashWidget() - html = widget.render(name='password', value=None, attrs={}) + html = widget.render(name="password", value=None, attrs={}) self.assertIn(_("No password set."), html) - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.PBKDF2PasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.PBKDF2PasswordHasher"] + ) def test_render(self): widget = ReadOnlyPasswordHashWidget() - value = 'pbkdf2_sha256$100000$a6Pucb1qSFcD$WmCkn9Hqidj48NVe5x0FEM6A9YiOqQcl/83m2Z5udm0=' + value = "pbkdf2_sha256$100000$a6Pucb1qSFcD$WmCkn9Hqidj48NVe5x0FEM6A9YiOqQcl/83m2Z5udm0=" self.assertHTMLEqual( - widget.render('name', value, {'id': 'id_password'}), + widget.render("name", value, {"id": "id_password"}), """ <div id="id_password"> <strong>algorithm</strong>: pbkdf2_sha256 @@ -1018,35 +1139,35 @@ class ReadOnlyPasswordHashTest(SimpleTestCase): <strong>salt</strong>: a6Pucb****** <strong>hash</strong>: WmCkn9************************************** </div> - """ + """, ) def test_readonly_field_has_changed(self): field = ReadOnlyPasswordHashField() self.assertIs(field.disabled, True) - self.assertFalse(field.has_changed('aaa', 'bbb')) + self.assertFalse(field.has_changed("aaa", "bbb")) def test_label(self): """ ReadOnlyPasswordHashWidget doesn't contain a for attribute in the <label> because it doesn't have any labelable elements. """ + class TestForm(forms.Form): hash_field = ReadOnlyPasswordHashField() - bound_field = TestForm()['hash_field'] - self.assertIsNone(bound_field.field.widget.id_for_label('id')) - self.assertEqual(bound_field.label_tag(), '<label>Hash field:</label>') + bound_field = TestForm()["hash_field"] + self.assertIsNone(bound_field.field.widget.id_for_label("id")) + self.assertEqual(bound_field.label_tag(), "<label>Hash field:</label>") class AdminPasswordChangeFormTest(TestDataMixin, TestCase): - - @mock.patch('django.contrib.auth.password_validation.password_changed') + @mock.patch("django.contrib.auth.password_validation.password_changed") def test_success(self, password_changed): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'password1': 'test123', - 'password2': 'test123', + "password1": "test123", + "password2": "test123", } form = AdminPasswordChangeForm(user, data) self.assertTrue(form.is_valid()) @@ -1056,47 +1177,51 @@ class AdminPasswordChangeFormTest(TestDataMixin, TestCase): self.assertEqual(password_changed.call_count, 1) def test_password_whitespace_not_stripped(self): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") data = { - 'password1': ' pass ', - 'password2': ' pass ', + "password1": " pass ", + "password2": " pass ", } form = AdminPasswordChangeForm(user, data) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['password1'], data['password1']) - self.assertEqual(form.cleaned_data['password2'], data['password2']) + self.assertEqual(form.cleaned_data["password1"], data["password1"]) + self.assertEqual(form.cleaned_data["password2"], data["password2"]) def test_non_matching_passwords(self): - user = User.objects.get(username='testclient') - data = {'password1': 'password1', 'password2': 'password2'} + user = User.objects.get(username="testclient") + data = {"password1": "password1", "password2": "password2"} form = AdminPasswordChangeForm(user, data) - self.assertEqual(form.errors['password2'], [form.error_messages['password_mismatch']]) + self.assertEqual( + form.errors["password2"], [form.error_messages["password_mismatch"]] + ) def test_missing_passwords(self): - user = User.objects.get(username='testclient') - data = {'password1': '', 'password2': ''} + user = User.objects.get(username="testclient") + data = {"password1": "", "password2": ""} form = AdminPasswordChangeForm(user, data) - required_error = [Field.default_error_messages['required']] - self.assertEqual(form.errors['password1'], required_error) - self.assertEqual(form.errors['password2'], required_error) + required_error = [Field.default_error_messages["required"]] + self.assertEqual(form.errors["password1"], required_error) + self.assertEqual(form.errors["password2"], required_error) def test_one_password(self): - user = User.objects.get(username='testclient') - form1 = AdminPasswordChangeForm(user, {'password1': '', 'password2': 'test'}) - required_error = [Field.default_error_messages['required']] - self.assertEqual(form1.errors['password1'], required_error) - self.assertNotIn('password2', form1.errors) - form2 = AdminPasswordChangeForm(user, {'password1': 'test', 'password2': ''}) - self.assertEqual(form2.errors['password2'], required_error) - self.assertNotIn('password1', form2.errors) + user = User.objects.get(username="testclient") + form1 = AdminPasswordChangeForm(user, {"password1": "", "password2": "test"}) + required_error = [Field.default_error_messages["required"]] + self.assertEqual(form1.errors["password1"], required_error) + self.assertNotIn("password2", form1.errors) + form2 = AdminPasswordChangeForm(user, {"password1": "test", "password2": ""}) + self.assertEqual(form2.errors["password2"], required_error) + self.assertNotIn("password1", form2.errors) def test_html_autocomplete_attributes(self): - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") form = AdminPasswordChangeForm(user) tests = ( - ('password1', 'new-password'), - ('password2', 'new-password'), + ("password1", "new-password"), + ("password2", "new-password"), ) for field_name, autocomplete in tests: with self.subTest(field_name=field_name, autocomplete=autocomplete): - self.assertEqual(form.fields[field_name].widget.attrs['autocomplete'], autocomplete) + self.assertEqual( + form.fields[field_name].widget.attrs["autocomplete"], autocomplete + ) diff --git a/tests/auth_tests/test_handlers.py b/tests/auth_tests/test_handlers.py index 57a43f877f..a6b53a9ef1 100644 --- a/tests/auth_tests/test_handlers.py +++ b/tests/auth_tests/test_handlers.py @@ -1,6 +1,4 @@ -from django.contrib.auth.handlers.modwsgi import ( - check_password, groups_for_user, -) +from django.contrib.auth.handlers.modwsgi import check_password, groups_for_user from django.contrib.auth.models import Group, User from django.test import TransactionTestCase, override_settings @@ -15,9 +13,9 @@ class ModWsgiHandlerTestCase(TransactionTestCase): """ available_apps = [ - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'auth_tests', + "django.contrib.auth", + "django.contrib.contenttypes", + "auth_tests", ] def test_check_password(self): @@ -25,51 +23,53 @@ class ModWsgiHandlerTestCase(TransactionTestCase): check_password() returns the correct values as per https://modwsgi.readthedocs.io/en/develop/user-guides/access-control-mechanisms.html#apache-authentication-provider """ - User.objects.create_user('test', 'test@example.com', 'test') + User.objects.create_user("test", "test@example.com", "test") # User not in database - self.assertIsNone(check_password({}, 'unknown', '')) + self.assertIsNone(check_password({}, "unknown", "")) # Valid user with correct password - self.assertTrue(check_password({}, 'test', 'test')) + self.assertTrue(check_password({}, "test", "test")) # correct password, but user is inactive - User.objects.filter(username='test').update(is_active=False) - self.assertFalse(check_password({}, 'test', 'test')) + User.objects.filter(username="test").update(is_active=False) + self.assertFalse(check_password({}, "test", "test")) # Valid user with incorrect password - self.assertFalse(check_password({}, 'test', 'incorrect')) + self.assertFalse(check_password({}, "test", "incorrect")) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUser") def test_check_password_custom_user(self): """ check_password() returns the correct values as per https://modwsgi.readthedocs.io/en/develop/user-guides/access-control-mechanisms.html#apache-authentication-provider with a custom user installed. """ - CustomUser._default_manager.create_user('test@example.com', '1990-01-01', 'test') + CustomUser._default_manager.create_user( + "test@example.com", "1990-01-01", "test" + ) # User not in database - self.assertIsNone(check_password({}, 'unknown', '')) + self.assertIsNone(check_password({}, "unknown", "")) # Valid user with correct password' - self.assertTrue(check_password({}, 'test@example.com', 'test')) + self.assertTrue(check_password({}, "test@example.com", "test")) # Valid user with incorrect password - self.assertFalse(check_password({}, 'test@example.com', 'incorrect')) + self.assertFalse(check_password({}, "test@example.com", "incorrect")) def test_groups_for_user(self): """ groups_for_user() returns correct values as per https://modwsgi.readthedocs.io/en/develop/user-guides/access-control-mechanisms.html#apache-group-authorisation """ - user1 = User.objects.create_user('test', 'test@example.com', 'test') - User.objects.create_user('test1', 'test1@example.com', 'test1') - group = Group.objects.create(name='test_group') + user1 = User.objects.create_user("test", "test@example.com", "test") + User.objects.create_user("test1", "test1@example.com", "test1") + group = Group.objects.create(name="test_group") user1.groups.add(group) # User not in database - self.assertEqual(groups_for_user({}, 'unknown'), []) + self.assertEqual(groups_for_user({}, "unknown"), []) - self.assertEqual(groups_for_user({}, 'test'), [b'test_group']) - self.assertEqual(groups_for_user({}, 'test1'), []) + self.assertEqual(groups_for_user({}, "test"), [b"test_group"]) + self.assertEqual(groups_for_user({}, "test1"), []) diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py index 2b8b953026..7650548d2b 100644 --- a/tests/auth_tests/test_hashers.py +++ b/tests/auth_tests/test_hashers.py @@ -2,11 +2,21 @@ from unittest import mock, skipUnless from django.conf.global_settings import PASSWORD_HASHERS from django.contrib.auth.hashers import ( - UNUSABLE_PASSWORD_PREFIX, UNUSABLE_PASSWORD_SUFFIX_LENGTH, - BasePasswordHasher, BCryptPasswordHasher, BCryptSHA256PasswordHasher, - MD5PasswordHasher, PBKDF2PasswordHasher, PBKDF2SHA1PasswordHasher, - ScryptPasswordHasher, SHA1PasswordHasher, check_password, get_hasher, - identify_hasher, is_password_usable, make_password, + UNUSABLE_PASSWORD_PREFIX, + UNUSABLE_PASSWORD_SUFFIX_LENGTH, + BasePasswordHasher, + BCryptPasswordHasher, + BCryptSHA256PasswordHasher, + MD5PasswordHasher, + PBKDF2PasswordHasher, + PBKDF2SHA1PasswordHasher, + ScryptPasswordHasher, + SHA1PasswordHasher, + check_password, + get_hasher, + identify_hasher, + is_password_usable, + make_password, ) from django.test import SimpleTestCase from django.test.utils import override_settings @@ -17,7 +27,7 @@ except ImportError: crypt = None else: # On some platforms (e.g. OpenBSD), crypt.crypt() always return None. - if crypt.crypt('') is None: + if crypt.crypt("") is None: crypt = None try: @@ -37,262 +47,291 @@ class PBKDF2SingleIterationHasher(PBKDF2PasswordHasher): @override_settings(PASSWORD_HASHERS=PASSWORD_HASHERS) class TestUtilsHashPass(SimpleTestCase): - def test_simple(self): - encoded = make_password('lètmein') - self.assertTrue(encoded.startswith('pbkdf2_sha256$')) + encoded = make_password("lètmein") + self.assertTrue(encoded.startswith("pbkdf2_sha256$")) self.assertTrue(is_password_usable(encoded)) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) # Blank passwords - blank_encoded = make_password('') - self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$')) + blank_encoded = make_password("") + self.assertTrue(blank_encoded.startswith("pbkdf2_sha256$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) def test_bytes(self): - encoded = make_password(b'bytes_password') - self.assertTrue(encoded.startswith('pbkdf2_sha256$')) + encoded = make_password(b"bytes_password") + self.assertTrue(encoded.startswith("pbkdf2_sha256$")) self.assertIs(is_password_usable(encoded), True) - self.assertIs(check_password(b'bytes_password', encoded), True) + self.assertIs(check_password(b"bytes_password", encoded), True) def test_invalid_password(self): - msg = 'Password must be a string or bytes, got int.' + msg = "Password must be a string or bytes, got int." with self.assertRaisesMessage(TypeError, msg): make_password(1) def test_pbkdf2(self): - encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256') - self.assertEqual(encoded, 'pbkdf2_sha256$390000$seasalt$8xBlGd3jVgvJ+92hWPxi5ww0uuAuAnKgC45eudxro7c=') + encoded = make_password("lètmein", "seasalt", "pbkdf2_sha256") + self.assertEqual( + encoded, + "pbkdf2_sha256$390000$seasalt$8xBlGd3jVgvJ+92hWPxi5ww0uuAuAnKgC45eudxro7c=", + ) self.assertTrue(is_password_usable(encoded)) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256") # Blank passwords - blank_encoded = make_password('', 'seasalt', 'pbkdf2_sha256') - self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$')) + blank_encoded = make_password("", "seasalt", "pbkdf2_sha256") + self.assertTrue(blank_encoded.startswith("pbkdf2_sha256$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) # Salt entropy check. - hasher = get_hasher('pbkdf2_sha256') - encoded_weak_salt = make_password('lètmein', 'iodizedsalt', 'pbkdf2_sha256') - encoded_strong_salt = make_password('lètmein', hasher.salt(), 'pbkdf2_sha256') + hasher = get_hasher("pbkdf2_sha256") + encoded_weak_salt = make_password("lètmein", "iodizedsalt", "pbkdf2_sha256") + encoded_strong_salt = make_password("lètmein", hasher.salt(), "pbkdf2_sha256") self.assertIs(hasher.must_update(encoded_weak_salt), True) self.assertIs(hasher.must_update(encoded_strong_salt), False) - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.SHA1PasswordHasher"] + ) def test_sha1(self): - encoded = make_password('lètmein', 'seasalt', 'sha1') - self.assertEqual(encoded, 'sha1$seasalt$cff36ea83f5706ce9aa7454e63e431fc726b2dc8') + encoded = make_password("lètmein", "seasalt", "sha1") + self.assertEqual( + encoded, "sha1$seasalt$cff36ea83f5706ce9aa7454e63e431fc726b2dc8" + ) self.assertTrue(is_password_usable(encoded)) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "sha1") # Blank passwords - blank_encoded = make_password('', 'seasalt', 'sha1') - self.assertTrue(blank_encoded.startswith('sha1$')) + blank_encoded = make_password("", "seasalt", "sha1") + self.assertTrue(blank_encoded.startswith("sha1$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) # Salt entropy check. - hasher = get_hasher('sha1') - encoded_weak_salt = make_password('lètmein', 'iodizedsalt', 'sha1') - encoded_strong_salt = make_password('lètmein', hasher.salt(), 'sha1') + hasher = get_hasher("sha1") + encoded_weak_salt = make_password("lètmein", "iodizedsalt", "sha1") + encoded_strong_salt = make_password("lètmein", hasher.salt(), "sha1") self.assertIs(hasher.must_update(encoded_weak_salt), True) self.assertIs(hasher.must_update(encoded_strong_salt), False) - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.MD5PasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.MD5PasswordHasher"] + ) def test_md5(self): - encoded = make_password('lètmein', 'seasalt', 'md5') - self.assertEqual(encoded, 'md5$seasalt$3f86d0d3d465b7b458c231bf3555c0e3') + encoded = make_password("lètmein", "seasalt", "md5") + self.assertEqual(encoded, "md5$seasalt$3f86d0d3d465b7b458c231bf3555c0e3") self.assertTrue(is_password_usable(encoded)) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "md5") # Blank passwords - blank_encoded = make_password('', 'seasalt', 'md5') - self.assertTrue(blank_encoded.startswith('md5$')) + blank_encoded = make_password("", "seasalt", "md5") + self.assertTrue(blank_encoded.startswith("md5$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) # Salt entropy check. - hasher = get_hasher('md5') - encoded_weak_salt = make_password('lètmein', 'iodizedsalt', 'md5') - encoded_strong_salt = make_password('lètmein', hasher.salt(), 'md5') + hasher = get_hasher("md5") + encoded_weak_salt = make_password("lètmein", "iodizedsalt", "md5") + encoded_strong_salt = make_password("lètmein", hasher.salt(), "md5") self.assertIs(hasher.must_update(encoded_weak_salt), True) self.assertIs(hasher.must_update(encoded_strong_salt), False) - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.UnsaltedMD5PasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"] + ) def test_unsalted_md5(self): - encoded = make_password('lètmein', '', 'unsalted_md5') - self.assertEqual(encoded, '88a434c88cca4e900f7874cd98123f43') + encoded = make_password("lètmein", "", "unsalted_md5") + self.assertEqual(encoded, "88a434c88cca4e900f7874cd98123f43") self.assertTrue(is_password_usable(encoded)) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5") # Alternate unsalted syntax alt_encoded = "md5$$%s" % encoded self.assertTrue(is_password_usable(alt_encoded)) - self.assertTrue(check_password('lètmein', alt_encoded)) - self.assertFalse(check_password('lètmeinz', alt_encoded)) + self.assertTrue(check_password("lètmein", alt_encoded)) + self.assertFalse(check_password("lètmeinz", alt_encoded)) # Blank passwords - blank_encoded = make_password('', '', 'unsalted_md5') + blank_encoded = make_password("", "", "unsalted_md5") self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.UnsaltedMD5PasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"] + ) def test_unsalted_md5_encode_invalid_salt(self): - hasher = get_hasher('unsalted_md5') - msg = 'salt must be empty.' + hasher = get_hasher("unsalted_md5") + msg = "salt must be empty." with self.assertRaisesMessage(ValueError, msg): - hasher.encode('password', salt='salt') + hasher.encode("password", salt="salt") - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"] + ) def test_unsalted_sha1(self): - encoded = make_password('lètmein', '', 'unsalted_sha1') - self.assertEqual(encoded, 'sha1$$6d138ca3ae545631b3abd71a4f076ce759c5700b') + encoded = make_password("lètmein", "", "unsalted_sha1") + self.assertEqual(encoded, "sha1$$6d138ca3ae545631b3abd71a4f076ce759c5700b") self.assertTrue(is_password_usable(encoded)) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_sha1") # Raw SHA1 isn't acceptable alt_encoded = encoded[6:] - self.assertFalse(check_password('lètmein', alt_encoded)) + self.assertFalse(check_password("lètmein", alt_encoded)) # Blank passwords - blank_encoded = make_password('', '', 'unsalted_sha1') - self.assertTrue(blank_encoded.startswith('sha1$')) + blank_encoded = make_password("", "", "unsalted_sha1") + self.assertTrue(blank_encoded.startswith("sha1$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"] + ) def test_unsalted_sha1_encode_invalid_salt(self): - hasher = get_hasher('unsalted_sha1') - msg = 'salt must be empty.' + hasher = get_hasher("unsalted_sha1") + msg = "salt must be empty." with self.assertRaisesMessage(ValueError, msg): - hasher.encode('password', salt='salt') + hasher.encode("password", salt="salt") @skipUnless(crypt, "no crypt module to generate password.") - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.CryptPasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.CryptPasswordHasher"] + ) def test_crypt(self): - encoded = make_password('lètmei', 'ab', 'crypt') - self.assertEqual(encoded, 'crypt$$ab1Hv2Lg7ltQo') + encoded = make_password("lètmei", "ab", "crypt") + self.assertEqual(encoded, "crypt$$ab1Hv2Lg7ltQo") self.assertTrue(is_password_usable(encoded)) - self.assertTrue(check_password('lètmei', encoded)) - self.assertFalse(check_password('lètmeiz', encoded)) + self.assertTrue(check_password("lètmei", encoded)) + self.assertFalse(check_password("lètmeiz", encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "crypt") # Blank passwords - blank_encoded = make_password('', 'ab', 'crypt') - self.assertTrue(blank_encoded.startswith('crypt$')) + blank_encoded = make_password("", "ab", "crypt") + self.assertTrue(blank_encoded.startswith("crypt$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) - @skipUnless(crypt, 'no crypt module to generate password.') - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.CryptPasswordHasher']) + @skipUnless(crypt, "no crypt module to generate password.") + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.CryptPasswordHasher"] + ) def test_crypt_encode_invalid_salt(self): - hasher = get_hasher('crypt') - msg = 'salt must be of length 2.' + hasher = get_hasher("crypt") + msg = "salt must be of length 2." with self.assertRaisesMessage(ValueError, msg): - hasher.encode('password', salt='a') + hasher.encode("password", salt="a") - @skipUnless(crypt, 'no crypt module to generate password.') - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.CryptPasswordHasher']) + @skipUnless(crypt, "no crypt module to generate password.") + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.CryptPasswordHasher"] + ) def test_crypt_encode_invalid_hash(self): - hasher = get_hasher('crypt') - msg = 'hash must be provided.' - with mock.patch('crypt.crypt', return_value=None): + hasher = get_hasher("crypt") + msg = "hash must be provided." + with mock.patch("crypt.crypt", return_value=None): with self.assertRaisesMessage(TypeError, msg): - hasher.encode('password', salt='ab') + hasher.encode("password", salt="ab") @skipUnless(bcrypt, "bcrypt not installed") def test_bcrypt_sha256(self): - encoded = make_password('lètmein', hasher='bcrypt_sha256') + encoded = make_password("lètmein", hasher="bcrypt_sha256") self.assertTrue(is_password_usable(encoded)) - self.assertTrue(encoded.startswith('bcrypt_sha256$')) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) + self.assertTrue(encoded.startswith("bcrypt_sha256$")) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt_sha256") # password truncation no longer works password = ( - 'VSK0UYV6FFQVZ0KG88DYN9WADAADZO1CTSIVDJUNZSUML6IBX7LN7ZS3R5' - 'JGB3RGZ7VI7G7DJQ9NI8BQFSRPTG6UWTTVESA5ZPUN' + "VSK0UYV6FFQVZ0KG88DYN9WADAADZO1CTSIVDJUNZSUML6IBX7LN7ZS3R5" + "JGB3RGZ7VI7G7DJQ9NI8BQFSRPTG6UWTTVESA5ZPUN" ) - encoded = make_password(password, hasher='bcrypt_sha256') + encoded = make_password(password, hasher="bcrypt_sha256") self.assertTrue(check_password(password, encoded)) self.assertFalse(check_password(password[:72], encoded)) # Blank passwords - blank_encoded = make_password('', hasher='bcrypt_sha256') - self.assertTrue(blank_encoded.startswith('bcrypt_sha256$')) + blank_encoded = make_password("", hasher="bcrypt_sha256") + self.assertTrue(blank_encoded.startswith("bcrypt_sha256$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) @skipUnless(bcrypt, "bcrypt not installed") - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.BCryptPasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.BCryptPasswordHasher"] + ) def test_bcrypt(self): - encoded = make_password('lètmein', hasher='bcrypt') + encoded = make_password("lètmein", hasher="bcrypt") self.assertTrue(is_password_usable(encoded)) - self.assertTrue(encoded.startswith('bcrypt$')) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) + self.assertTrue(encoded.startswith("bcrypt$")) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt") # Blank passwords - blank_encoded = make_password('', hasher='bcrypt') - self.assertTrue(blank_encoded.startswith('bcrypt$')) + blank_encoded = make_password("", hasher="bcrypt") + self.assertTrue(blank_encoded.startswith("bcrypt$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) @skipUnless(bcrypt, "bcrypt not installed") - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.BCryptPasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.BCryptPasswordHasher"] + ) def test_bcrypt_upgrade(self): - hasher = get_hasher('bcrypt') - self.assertEqual('bcrypt', hasher.algorithm) + hasher = get_hasher("bcrypt") + self.assertEqual("bcrypt", hasher.algorithm) self.assertNotEqual(hasher.rounds, 4) old_rounds = hasher.rounds try: # Generate a password with 4 rounds. hasher.rounds = 4 - encoded = make_password('letmein', hasher='bcrypt') - rounds = hasher.safe_summary(encoded)['work factor'] + encoded = make_password("letmein", hasher="bcrypt") + rounds = hasher.safe_summary(encoded)["work factor"] self.assertEqual(rounds, 4) - state = {'upgraded': False} + state = {"upgraded": False} def setter(password): - state['upgraded'] = True + state["upgraded"] = True # No upgrade is triggered. - self.assertTrue(check_password('letmein', encoded, setter, 'bcrypt')) - self.assertFalse(state['upgraded']) + self.assertTrue(check_password("letmein", encoded, setter, "bcrypt")) + self.assertFalse(state["upgraded"]) # Revert to the old rounds count and ... hasher.rounds = old_rounds # ... check if the password would get updated to the new count. - self.assertTrue(check_password('letmein', encoded, setter, 'bcrypt')) - self.assertTrue(state['upgraded']) + self.assertTrue(check_password("letmein", encoded, setter, "bcrypt")) + self.assertTrue(state["upgraded"]) finally: hasher.rounds = old_rounds @skipUnless(bcrypt, "bcrypt not installed") - @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.BCryptPasswordHasher']) + @override_settings( + PASSWORD_HASHERS=["django.contrib.auth.hashers.BCryptPasswordHasher"] + ) def test_bcrypt_harden_runtime(self): - hasher = get_hasher('bcrypt') - self.assertEqual('bcrypt', hasher.algorithm) + hasher = get_hasher("bcrypt") + self.assertEqual("bcrypt", hasher.algorithm) - with mock.patch.object(hasher, 'rounds', 4): - encoded = make_password('letmein', hasher='bcrypt') + with mock.patch.object(hasher, "rounds", 4): + encoded = make_password("letmein", hasher="bcrypt") - with mock.patch.object(hasher, 'rounds', 6), \ - mock.patch.object(hasher, 'encode', side_effect=hasher.encode): - hasher.harden_runtime('wrong_password', encoded) + with mock.patch.object(hasher, "rounds", 6), mock.patch.object( + hasher, "encode", side_effect=hasher.encode + ): + hasher.harden_runtime("wrong_password", encoded) # Increasing rounds from 4 to 6 means an increase of 4 in workload, # therefore hardening should run 3 times to make the timing the @@ -300,21 +339,24 @@ class TestUtilsHashPass(SimpleTestCase): self.assertEqual(hasher.encode.call_count, 3) # Get the original salt (includes the original workload factor) - algorithm, data = encoded.split('$', 1) - expected_call = (('wrong_password', data[:29].encode()),) + algorithm, data = encoded.split("$", 1) + expected_call = (("wrong_password", data[:29].encode()),) self.assertEqual(hasher.encode.call_args_list, [expected_call] * 3) def test_unusable(self): encoded = make_password(None) - self.assertEqual(len(encoded), len(UNUSABLE_PASSWORD_PREFIX) + UNUSABLE_PASSWORD_SUFFIX_LENGTH) + self.assertEqual( + len(encoded), + len(UNUSABLE_PASSWORD_PREFIX) + UNUSABLE_PASSWORD_SUFFIX_LENGTH, + ) self.assertFalse(is_password_usable(encoded)) self.assertFalse(check_password(None, encoded)) self.assertFalse(check_password(encoded, encoded)) self.assertFalse(check_password(UNUSABLE_PASSWORD_PREFIX, encoded)) - self.assertFalse(check_password('', encoded)) - self.assertFalse(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) - with self.assertRaisesMessage(ValueError, 'Unknown password hashing algorith'): + self.assertFalse(check_password("", encoded)) + self.assertFalse(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) + with self.assertRaisesMessage(ValueError, "Unknown password hashing algorith"): identify_hasher(encoded) # Assert that the unusable passwords actually contain a random part. # This might fail one day due to a hash collision. @@ -325,185 +367,199 @@ class TestUtilsHashPass(SimpleTestCase): Makes sure specifying no plain password with a valid encoded password returns `False`. """ - self.assertFalse(check_password(None, make_password('lètmein'))) + self.assertFalse(check_password(None, make_password("lètmein"))) def test_bad_algorithm(self): msg = ( "Unknown password hashing algorithm '%s'. Did you specify it in " "the PASSWORD_HASHERS setting?" ) - with self.assertRaisesMessage(ValueError, msg % 'lolcat'): - make_password('lètmein', hasher='lolcat') - with self.assertRaisesMessage(ValueError, msg % 'lolcat'): - identify_hasher('lolcat$salt$hash') + with self.assertRaisesMessage(ValueError, msg % "lolcat"): + make_password("lètmein", hasher="lolcat") + with self.assertRaisesMessage(ValueError, msg % "lolcat"): + identify_hasher("lolcat$salt$hash") def test_is_password_usable(self): - passwords = ('lètmein_badencoded', '', None) + passwords = ("lètmein_badencoded", "", None) for password in passwords: with self.subTest(password=password): self.assertIs(is_password_usable(password), True) def test_low_level_pbkdf2(self): hasher = PBKDF2PasswordHasher() - encoded = hasher.encode('lètmein', 'seasalt2') - self.assertEqual(encoded, 'pbkdf2_sha256$390000$seasalt2$geC/uZ92nRXDSjSxeoiBqYyRcrLzMm8xK3ro1QS1uo8=') - self.assertTrue(hasher.verify('lètmein', encoded)) + encoded = hasher.encode("lètmein", "seasalt2") + self.assertEqual( + encoded, + "pbkdf2_sha256$390000$seasalt2$geC/uZ92nRXDSjSxeoiBqYyRcrLzMm8xK3ro1QS1uo8=", + ) + self.assertTrue(hasher.verify("lètmein", encoded)) def test_low_level_pbkdf2_sha1(self): hasher = PBKDF2SHA1PasswordHasher() - encoded = hasher.encode('lètmein', 'seasalt2') - self.assertEqual(encoded, 'pbkdf2_sha1$390000$seasalt2$aDapRanzW8aHTz97v2TcfHzWD+I=') - self.assertTrue(hasher.verify('lètmein', encoded)) + encoded = hasher.encode("lètmein", "seasalt2") + self.assertEqual( + encoded, "pbkdf2_sha1$390000$seasalt2$aDapRanzW8aHTz97v2TcfHzWD+I=" + ) + self.assertTrue(hasher.verify("lètmein", encoded)) - @skipUnless(bcrypt, 'bcrypt not installed') + @skipUnless(bcrypt, "bcrypt not installed") def test_bcrypt_salt_check(self): hasher = BCryptPasswordHasher() - encoded = hasher.encode('lètmein', hasher.salt()) + encoded = hasher.encode("lètmein", hasher.salt()) self.assertIs(hasher.must_update(encoded), False) - @skipUnless(bcrypt, 'bcrypt not installed') + @skipUnless(bcrypt, "bcrypt not installed") def test_bcryptsha256_salt_check(self): hasher = BCryptSHA256PasswordHasher() - encoded = hasher.encode('lètmein', hasher.salt()) + encoded = hasher.encode("lètmein", hasher.salt()) self.assertIs(hasher.must_update(encoded), False) @override_settings( PASSWORD_HASHERS=[ - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'django.contrib.auth.hashers.SHA1PasswordHasher', - 'django.contrib.auth.hashers.MD5PasswordHasher', + "django.contrib.auth.hashers.PBKDF2PasswordHasher", + "django.contrib.auth.hashers.SHA1PasswordHasher", + "django.contrib.auth.hashers.MD5PasswordHasher", ], ) def test_upgrade(self): - self.assertEqual('pbkdf2_sha256', get_hasher('default').algorithm) - for algo in ('sha1', 'md5'): + self.assertEqual("pbkdf2_sha256", get_hasher("default").algorithm) + for algo in ("sha1", "md5"): with self.subTest(algo=algo): - encoded = make_password('lètmein', hasher=algo) - state = {'upgraded': False} + encoded = make_password("lètmein", hasher=algo) + state = {"upgraded": False} def setter(password): - state['upgraded'] = True - self.assertTrue(check_password('lètmein', encoded, setter)) - self.assertTrue(state['upgraded']) + state["upgraded"] = True + + self.assertTrue(check_password("lètmein", encoded, setter)) + self.assertTrue(state["upgraded"]) def test_no_upgrade(self): - encoded = make_password('lètmein') - state = {'upgraded': False} + encoded = make_password("lètmein") + state = {"upgraded": False} def setter(): - state['upgraded'] = True - self.assertFalse(check_password('WRONG', encoded, setter)) - self.assertFalse(state['upgraded']) + state["upgraded"] = True + + self.assertFalse(check_password("WRONG", encoded, setter)) + self.assertFalse(state["upgraded"]) @override_settings( PASSWORD_HASHERS=[ - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'django.contrib.auth.hashers.SHA1PasswordHasher', - 'django.contrib.auth.hashers.MD5PasswordHasher', + "django.contrib.auth.hashers.PBKDF2PasswordHasher", + "django.contrib.auth.hashers.SHA1PasswordHasher", + "django.contrib.auth.hashers.MD5PasswordHasher", ], ) def test_no_upgrade_on_incorrect_pass(self): - self.assertEqual('pbkdf2_sha256', get_hasher('default').algorithm) - for algo in ('sha1', 'md5'): + self.assertEqual("pbkdf2_sha256", get_hasher("default").algorithm) + for algo in ("sha1", "md5"): with self.subTest(algo=algo): - encoded = make_password('lètmein', hasher=algo) - state = {'upgraded': False} + encoded = make_password("lètmein", hasher=algo) + state = {"upgraded": False} def setter(): - state['upgraded'] = True - self.assertFalse(check_password('WRONG', encoded, setter)) - self.assertFalse(state['upgraded']) + state["upgraded"] = True + + self.assertFalse(check_password("WRONG", encoded, setter)) + self.assertFalse(state["upgraded"]) def test_pbkdf2_upgrade(self): - hasher = get_hasher('default') - self.assertEqual('pbkdf2_sha256', hasher.algorithm) + hasher = get_hasher("default") + self.assertEqual("pbkdf2_sha256", hasher.algorithm) self.assertNotEqual(hasher.iterations, 1) old_iterations = hasher.iterations try: # Generate a password with 1 iteration. hasher.iterations = 1 - encoded = make_password('letmein') - algo, iterations, salt, hash = encoded.split('$', 3) - self.assertEqual(iterations, '1') + encoded = make_password("letmein") + algo, iterations, salt, hash = encoded.split("$", 3) + self.assertEqual(iterations, "1") - state = {'upgraded': False} + state = {"upgraded": False} def setter(password): - state['upgraded'] = True + state["upgraded"] = True # No upgrade is triggered - self.assertTrue(check_password('letmein', encoded, setter)) - self.assertFalse(state['upgraded']) + self.assertTrue(check_password("letmein", encoded, setter)) + self.assertFalse(state["upgraded"]) # Revert to the old iteration count and ... hasher.iterations = old_iterations # ... check if the password would get updated to the new iteration count. - self.assertTrue(check_password('letmein', encoded, setter)) - self.assertTrue(state['upgraded']) + self.assertTrue(check_password("letmein", encoded, setter)) + self.assertTrue(state["upgraded"]) finally: hasher.iterations = old_iterations def test_pbkdf2_harden_runtime(self): - hasher = get_hasher('default') - self.assertEqual('pbkdf2_sha256', hasher.algorithm) + hasher = get_hasher("default") + self.assertEqual("pbkdf2_sha256", hasher.algorithm) - with mock.patch.object(hasher, 'iterations', 1): - encoded = make_password('letmein') + with mock.patch.object(hasher, "iterations", 1): + encoded = make_password("letmein") - with mock.patch.object(hasher, 'iterations', 6), \ - mock.patch.object(hasher, 'encode', side_effect=hasher.encode): - hasher.harden_runtime('wrong_password', encoded) + with mock.patch.object(hasher, "iterations", 6), mock.patch.object( + hasher, "encode", side_effect=hasher.encode + ): + hasher.harden_runtime("wrong_password", encoded) # Encode should get called once ... self.assertEqual(hasher.encode.call_count, 1) # ... with the original salt and 5 iterations. - algorithm, iterations, salt, hash = encoded.split('$', 3) - expected_call = (('wrong_password', salt, 5),) + algorithm, iterations, salt, hash = encoded.split("$", 3) + expected_call = (("wrong_password", salt, 5),) self.assertEqual(hasher.encode.call_args, expected_call) def test_pbkdf2_upgrade_new_hasher(self): - hasher = get_hasher('default') - self.assertEqual('pbkdf2_sha256', hasher.algorithm) + hasher = get_hasher("default") + self.assertEqual("pbkdf2_sha256", hasher.algorithm) self.assertNotEqual(hasher.iterations, 1) - state = {'upgraded': False} + state = {"upgraded": False} def setter(password): - state['upgraded'] = True + state["upgraded"] = True - with self.settings(PASSWORD_HASHERS=[ - 'auth_tests.test_hashers.PBKDF2SingleIterationHasher']): - encoded = make_password('letmein') - algo, iterations, salt, hash = encoded.split('$', 3) - self.assertEqual(iterations, '1') + with self.settings( + PASSWORD_HASHERS=["auth_tests.test_hashers.PBKDF2SingleIterationHasher"] + ): + encoded = make_password("letmein") + algo, iterations, salt, hash = encoded.split("$", 3) + self.assertEqual(iterations, "1") # No upgrade is triggered - self.assertTrue(check_password('letmein', encoded, setter)) - self.assertFalse(state['upgraded']) + self.assertTrue(check_password("letmein", encoded, setter)) + self.assertFalse(state["upgraded"]) # Revert to the old iteration count and check if the password would get # updated to the new iteration count. - with self.settings(PASSWORD_HASHERS=[ - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'auth_tests.test_hashers.PBKDF2SingleIterationHasher']): - self.assertTrue(check_password('letmein', encoded, setter)) - self.assertTrue(state['upgraded']) + with self.settings( + PASSWORD_HASHERS=[ + "django.contrib.auth.hashers.PBKDF2PasswordHasher", + "auth_tests.test_hashers.PBKDF2SingleIterationHasher", + ] + ): + self.assertTrue(check_password("letmein", encoded, setter)) + self.assertTrue(state["upgraded"]) def test_check_password_calls_harden_runtime(self): - hasher = get_hasher('default') - encoded = make_password('letmein') + hasher = get_hasher("default") + encoded = make_password("letmein") - with mock.patch.object(hasher, 'harden_runtime'), \ - mock.patch.object(hasher, 'must_update', return_value=True): + with mock.patch.object(hasher, "harden_runtime"), mock.patch.object( + hasher, "must_update", return_value=True + ): # Correct password supplied, no hardening needed - check_password('letmein', encoded) + check_password("letmein", encoded) self.assertEqual(hasher.harden_runtime.call_count, 0) # Wrong password supplied, hardening needed - check_password('wrong_password', encoded) + check_password("wrong_password", encoded) self.assertEqual(hasher.harden_runtime.call_count, 1) def test_encode_invalid_salt(self): @@ -514,13 +570,13 @@ class TestUtilsHashPass(SimpleTestCase): ScryptPasswordHasher, SHA1PasswordHasher, ] - msg = 'salt must be provided and cannot contain $.' + msg = "salt must be provided and cannot contain $." for hasher_class in hasher_classes: hasher = hasher_class() - for salt in [None, '', 'sea$salt']: + for salt in [None, "", "sea$salt"]: with self.subTest(hasher_class.__name__, salt=salt): with self.assertRaisesMessage(ValueError, msg): - hasher.encode('password', salt) + hasher.encode("password", salt) def test_encode_password_required(self): hasher_classes = [ @@ -530,16 +586,16 @@ class TestUtilsHashPass(SimpleTestCase): ScryptPasswordHasher, SHA1PasswordHasher, ] - msg = 'password must be provided.' + msg = "password must be provided." for hasher_class in hasher_classes: hasher = hasher_class() with self.subTest(hasher_class.__name__): with self.assertRaisesMessage(TypeError, msg): - hasher.encode(None, 'seasalt') + hasher.encode(None, "seasalt") class BasePasswordHasherTests(SimpleTestCase): - not_implemented_msg = 'subclasses of BasePasswordHasher must provide %s() method' + not_implemented_msg = "subclasses of BasePasswordHasher must provide %s() method" def setUp(self): self.hasher = BasePasswordHasher() @@ -550,7 +606,11 @@ class BasePasswordHasherTests(SimpleTestCase): self.hasher._load_library() def test_load_library_importerror(self): - PlainHasher = type('PlainHasher', (BasePasswordHasher,), {'algorithm': 'plain', 'library': 'plain'}) + PlainHasher = type( + "PlainHasher", + (BasePasswordHasher,), + {"algorithm": "plain", "library": "plain"}, + ) msg = "Couldn't load 'PlainHasher' algorithm library: No module named 'plain'" with self.assertRaisesMessage(ValueError, msg): PlainHasher()._load_library() @@ -560,96 +620,95 @@ class BasePasswordHasherTests(SimpleTestCase): self.assertIsNone(self.hasher.library) def test_encode(self): - msg = self.not_implemented_msg % 'an encode' + msg = self.not_implemented_msg % "an encode" with self.assertRaisesMessage(NotImplementedError, msg): - self.hasher.encode('password', 'salt') + self.hasher.encode("password", "salt") def test_decode(self): - msg = self.not_implemented_msg % 'a decode' + msg = self.not_implemented_msg % "a decode" with self.assertRaisesMessage(NotImplementedError, msg): - self.hasher.decode('encoded') + self.hasher.decode("encoded") def test_harden_runtime(self): - msg = 'subclasses of BasePasswordHasher should provide a harden_runtime() method' + msg = ( + "subclasses of BasePasswordHasher should provide a harden_runtime() method" + ) with self.assertWarnsMessage(Warning, msg): - self.hasher.harden_runtime('password', 'encoded') + self.hasher.harden_runtime("password", "encoded") def test_must_update(self): - self.assertIs(self.hasher.must_update('encoded'), False) + self.assertIs(self.hasher.must_update("encoded"), False) def test_safe_summary(self): - msg = self.not_implemented_msg % 'a safe_summary' + msg = self.not_implemented_msg % "a safe_summary" with self.assertRaisesMessage(NotImplementedError, msg): - self.hasher.safe_summary('encoded') + self.hasher.safe_summary("encoded") def test_verify(self): - msg = self.not_implemented_msg % 'a verify' + msg = self.not_implemented_msg % "a verify" with self.assertRaisesMessage(NotImplementedError, msg): - self.hasher.verify('password', 'encoded') + self.hasher.verify("password", "encoded") @skipUnless(argon2, "argon2-cffi not installed") @override_settings(PASSWORD_HASHERS=PASSWORD_HASHERS) class TestUtilsHashPassArgon2(SimpleTestCase): - def test_argon2(self): - encoded = make_password('lètmein', hasher='argon2') + encoded = make_password("lètmein", hasher="argon2") self.assertTrue(is_password_usable(encoded)) - self.assertTrue(encoded.startswith('argon2$argon2id$')) - self.assertTrue(check_password('lètmein', encoded)) - self.assertFalse(check_password('lètmeinz', encoded)) - self.assertEqual(identify_hasher(encoded).algorithm, 'argon2') + self.assertTrue(encoded.startswith("argon2$argon2id$")) + self.assertTrue(check_password("lètmein", encoded)) + self.assertFalse(check_password("lètmeinz", encoded)) + self.assertEqual(identify_hasher(encoded).algorithm, "argon2") # Blank passwords - blank_encoded = make_password('', hasher='argon2') - self.assertTrue(blank_encoded.startswith('argon2$argon2id$')) + blank_encoded = make_password("", hasher="argon2") + self.assertTrue(blank_encoded.startswith("argon2$argon2id$")) self.assertTrue(is_password_usable(blank_encoded)) - self.assertTrue(check_password('', blank_encoded)) - self.assertFalse(check_password(' ', blank_encoded)) + self.assertTrue(check_password("", blank_encoded)) + self.assertFalse(check_password(" ", blank_encoded)) # Old hashes without version attribute encoded = ( - 'argon2$argon2i$m=8,t=1,p=1$c29tZXNhbHQ$gwQOXSNhxiOxPOA0+PY10P9QFO' - '4NAYysnqRt1GSQLE55m+2GYDt9FEjPMHhP2Cuf0nOEXXMocVrsJAtNSsKyfg' + "argon2$argon2i$m=8,t=1,p=1$c29tZXNhbHQ$gwQOXSNhxiOxPOA0+PY10P9QFO" + "4NAYysnqRt1GSQLE55m+2GYDt9FEjPMHhP2Cuf0nOEXXMocVrsJAtNSsKyfg" ) - self.assertTrue(check_password('secret', encoded)) - self.assertFalse(check_password('wrong', encoded)) + self.assertTrue(check_password("secret", encoded)) + self.assertFalse(check_password("wrong", encoded)) # Old hashes with version attribute. - encoded = ( - 'argon2$argon2i$v=19$m=8,t=1,p=1$c2FsdHNhbHQ$YC9+jJCrQhs5R6db7LlN8Q' - ) - self.assertIs(check_password('secret', encoded), True) - self.assertIs(check_password('wrong', encoded), False) + encoded = "argon2$argon2i$v=19$m=8,t=1,p=1$c2FsdHNhbHQ$YC9+jJCrQhs5R6db7LlN8Q" + self.assertIs(check_password("secret", encoded), True) + self.assertIs(check_password("wrong", encoded), False) # Salt entropy check. - hasher = get_hasher('argon2') - encoded_weak_salt = make_password('lètmein', 'iodizedsalt', 'argon2') - encoded_strong_salt = make_password('lètmein', hasher.salt(), 'argon2') + hasher = get_hasher("argon2") + encoded_weak_salt = make_password("lètmein", "iodizedsalt", "argon2") + encoded_strong_salt = make_password("lètmein", hasher.salt(), "argon2") self.assertIs(hasher.must_update(encoded_weak_salt), True) self.assertIs(hasher.must_update(encoded_strong_salt), False) def test_argon2_decode(self): - salt = 'abcdefghijk' - encoded = make_password('lètmein', salt=salt, hasher='argon2') - hasher = get_hasher('argon2') + salt = "abcdefghijk" + encoded = make_password("lètmein", salt=salt, hasher="argon2") + hasher = get_hasher("argon2") decoded = hasher.decode(encoded) - self.assertEqual(decoded['memory_cost'], hasher.memory_cost) - self.assertEqual(decoded['parallelism'], hasher.parallelism) - self.assertEqual(decoded['salt'], salt) - self.assertEqual(decoded['time_cost'], hasher.time_cost) + self.assertEqual(decoded["memory_cost"], hasher.memory_cost) + self.assertEqual(decoded["parallelism"], hasher.parallelism) + self.assertEqual(decoded["salt"], salt) + self.assertEqual(decoded["time_cost"], hasher.time_cost) def test_argon2_upgrade(self): - self._test_argon2_upgrade('time_cost', 'time cost', 1) - self._test_argon2_upgrade('memory_cost', 'memory cost', 64) - self._test_argon2_upgrade('parallelism', 'parallelism', 1) + self._test_argon2_upgrade("time_cost", "time cost", 1) + self._test_argon2_upgrade("memory_cost", "memory cost", 64) + self._test_argon2_upgrade("parallelism", "parallelism", 1) def test_argon2_version_upgrade(self): - hasher = get_hasher('argon2') - state = {'upgraded': False} + hasher = get_hasher("argon2") + state = {"upgraded": False} encoded = ( - 'argon2$argon2id$v=19$m=102400,t=2,p=8$Y041dExhNkljRUUy$TMa6A8fPJh' - 'CAUXRhJXCXdw' + "argon2$argon2id$v=19$m=102400,t=2,p=8$Y041dExhNkljRUUy$TMa6A8fPJh" + "CAUXRhJXCXdw" ) def setter(password): - state['upgraded'] = True + state["upgraded"] = True old_m = hasher.memory_cost old_t = hasher.time_cost @@ -658,114 +717,113 @@ class TestUtilsHashPassArgon2(SimpleTestCase): hasher.memory_cost = 8 hasher.time_cost = 1 hasher.parallelism = 1 - self.assertTrue(check_password('secret', encoded, setter, 'argon2')) - self.assertTrue(state['upgraded']) + self.assertTrue(check_password("secret", encoded, setter, "argon2")) + self.assertTrue(state["upgraded"]) finally: hasher.memory_cost = old_m hasher.time_cost = old_t hasher.parallelism = old_p def _test_argon2_upgrade(self, attr, summary_key, new_value): - hasher = get_hasher('argon2') - self.assertEqual('argon2', hasher.algorithm) + hasher = get_hasher("argon2") + self.assertEqual("argon2", hasher.algorithm) self.assertNotEqual(getattr(hasher, attr), new_value) old_value = getattr(hasher, attr) try: # Generate hash with attr set to 1 setattr(hasher, attr, new_value) - encoded = make_password('letmein', hasher='argon2') + encoded = make_password("letmein", hasher="argon2") attr_value = hasher.safe_summary(encoded)[summary_key] self.assertEqual(attr_value, new_value) - state = {'upgraded': False} + state = {"upgraded": False} def setter(password): - state['upgraded'] = True + state["upgraded"] = True # No upgrade is triggered. - self.assertTrue(check_password('letmein', encoded, setter, 'argon2')) - self.assertFalse(state['upgraded']) + self.assertTrue(check_password("letmein", encoded, setter, "argon2")) + self.assertFalse(state["upgraded"]) # Revert to the old rounds count and ... setattr(hasher, attr, old_value) # ... check if the password would get updated to the new count. - self.assertTrue(check_password('letmein', encoded, setter, 'argon2')) - self.assertTrue(state['upgraded']) + self.assertTrue(check_password("letmein", encoded, setter, "argon2")) + self.assertTrue(state["upgraded"]) finally: setattr(hasher, attr, old_value) @override_settings(PASSWORD_HASHERS=PASSWORD_HASHERS) class TestUtilsHashPassScrypt(SimpleTestCase): - def test_scrypt(self): - encoded = make_password('lètmein', 'seasalt', 'scrypt') + encoded = make_password("lètmein", "seasalt", "scrypt") self.assertEqual( encoded, - 'scrypt$16384$seasalt$8$1$Qj3+9PPyRjSJIebHnG81TMjsqtaIGxNQG/aEB/NY' - 'afTJ7tibgfYz71m0ldQESkXFRkdVCBhhY8mx7rQwite/Pw==' + "scrypt$16384$seasalt$8$1$Qj3+9PPyRjSJIebHnG81TMjsqtaIGxNQG/aEB/NY" + "afTJ7tibgfYz71m0ldQESkXFRkdVCBhhY8mx7rQwite/Pw==", ) self.assertIs(is_password_usable(encoded), True) - self.assertIs(check_password('lètmein', encoded), True) - self.assertIs(check_password('lètmeinz', encoded), False) + self.assertIs(check_password("lètmein", encoded), True) + self.assertIs(check_password("lètmeinz", encoded), False) self.assertEqual(identify_hasher(encoded).algorithm, "scrypt") # Blank passwords. - blank_encoded = make_password('', 'seasalt', 'scrypt') - self.assertIs(blank_encoded.startswith('scrypt$'), True) + blank_encoded = make_password("", "seasalt", "scrypt") + self.assertIs(blank_encoded.startswith("scrypt$"), True) self.assertIs(is_password_usable(blank_encoded), True) - self.assertIs(check_password('', blank_encoded), True) - self.assertIs(check_password(' ', blank_encoded), False) + self.assertIs(check_password("", blank_encoded), True) + self.assertIs(check_password(" ", blank_encoded), False) def test_scrypt_decode(self): - encoded = make_password('lètmein', 'seasalt', 'scrypt') - hasher = get_hasher('scrypt') + encoded = make_password("lètmein", "seasalt", "scrypt") + hasher = get_hasher("scrypt") decoded = hasher.decode(encoded) tests = [ - ('block_size', hasher.block_size), - ('parallelism', hasher.parallelism), - ('salt', 'seasalt'), - ('work_factor', hasher.work_factor), + ("block_size", hasher.block_size), + ("parallelism", hasher.parallelism), + ("salt", "seasalt"), + ("work_factor", hasher.work_factor), ] for key, excepted in tests: with self.subTest(key=key): self.assertEqual(decoded[key], excepted) def _test_scrypt_upgrade(self, attr, summary_key, new_value): - hasher = get_hasher('scrypt') - self.assertEqual(hasher.algorithm, 'scrypt') + hasher = get_hasher("scrypt") + self.assertEqual(hasher.algorithm, "scrypt") self.assertNotEqual(getattr(hasher, attr), new_value) old_value = getattr(hasher, attr) try: # Generate hash with attr set to the new value. setattr(hasher, attr, new_value) - encoded = make_password('lètmein', 'seasalt', 'scrypt') + encoded = make_password("lètmein", "seasalt", "scrypt") attr_value = hasher.safe_summary(encoded)[summary_key] self.assertEqual(attr_value, new_value) - state = {'upgraded': False} + state = {"upgraded": False} def setter(password): - state['upgraded'] = True + state["upgraded"] = True # No update is triggered. - self.assertIs(check_password('lètmein', encoded, setter, 'scrypt'), True) - self.assertIs(state['upgraded'], False) + self.assertIs(check_password("lètmein", encoded, setter, "scrypt"), True) + self.assertIs(state["upgraded"], False) # Revert to the old value. setattr(hasher, attr, old_value) # Password is updated. - self.assertIs(check_password('lètmein', encoded, setter, 'scrypt'), True) - self.assertIs(state['upgraded'], True) + self.assertIs(check_password("lètmein", encoded, setter, "scrypt"), True) + self.assertIs(state["upgraded"], True) finally: setattr(hasher, attr, old_value) def test_scrypt_upgrade(self): tests = [ - ('work_factor', 'work factor', 2 ** 11), - ('block_size', 'block size', 10), - ('parallelism', 'parallelism', 2), + ("work_factor", "work factor", 2**11), + ("block_size", "block size", 10), + ("parallelism", "parallelism", 2), ] for attr, summary_key, new_value in tests: with self.subTest(attr=attr): diff --git a/tests/auth_tests/test_management.py b/tests/auth_tests/test_management.py index 16da9eb4ad..41596a2210 100644 --- a/tests/auth_tests/test_management.py +++ b/tests/auth_tests/test_management.py @@ -8,12 +8,8 @@ from unittest import mock from django.apps import apps from django.contrib.auth import get_permission_codename, management -from django.contrib.auth.management import ( - create_permissions, get_default_username, -) -from django.contrib.auth.management.commands import ( - changepassword, createsuperuser, -) +from django.contrib.auth.management import create_permissions, get_default_username +from django.contrib.auth.management.commands import changepassword, createsuperuser from django.contrib.auth.models import Group, Permission, User from django.contrib.contenttypes.models import ContentType from django.core.management import call_command @@ -23,17 +19,25 @@ from django.test import TestCase, override_settings from django.utils.translation import gettext_lazy as _ from .models import ( - CustomUser, CustomUserNonUniqueUsername, CustomUserWithFK, - CustomUserWithM2M, Email, Organization, UserProxy, + CustomUser, + CustomUserNonUniqueUsername, + CustomUserWithFK, + CustomUserWithM2M, + Email, + Organization, + UserProxy, ) MOCK_INPUT_KEY_TO_PROMPTS = { # @mock_inputs dict key: [expected prompt messages], - 'bypass': ['Bypass password validation and create user anyway? [y/N]: '], - 'email': ['Email address: '], - 'date_of_birth': ['Date of birth: '], - 'first_name': ['First name: '], - 'username': ['Username: ', lambda: "Username (leave blank to use '%s'): " % get_default_username()], + "bypass": ["Bypass password validation and create user anyway? [y/N]: "], + "email": ["Email address: "], + "date_of_birth": ["Date of birth: "], + "first_name": ["First name: "], + "username": [ + "Username: ", + lambda: "Username (leave blank to use '%s'): " % get_default_username(), + ], } @@ -42,26 +46,29 @@ def mock_inputs(inputs): Decorator to temporarily replace input/getpass to allow interactive createsuperuser. """ + def inner(test_func): def wrapped(*args): class mock_getpass: @staticmethod - def getpass(prompt=b'Password: ', stream=None): - if callable(inputs['password']): - return inputs['password']() - return inputs['password'] + def getpass(prompt=b"Password: ", stream=None): + if callable(inputs["password"]): + return inputs["password"]() + return inputs["password"] def mock_input(prompt): - assert '__proxy__' not in prompt + assert "__proxy__" not in prompt response = None for key, val in inputs.items(): - if val == 'KeyboardInterrupt': + if val == "KeyboardInterrupt": raise KeyboardInterrupt # get() fallback because sometimes 'key' is the actual # prompt rather than a shortcut name. prompt_msgs = MOCK_INPUT_KEY_TO_PROMPTS.get(key, key) if isinstance(prompt_msgs, list): - prompt_msgs = [msg() if callable(msg) else msg for msg in prompt_msgs] + prompt_msgs = [ + msg() if callable(msg) else msg for msg in prompt_msgs + ] if prompt in prompt_msgs: if callable(val): response = val() @@ -69,7 +76,7 @@ def mock_inputs(inputs): response = val break if response is None: - raise ValueError('Mock input for %r not found.' % prompt) + raise ValueError("Mock input for %r not found." % prompt) return response old_getpass = createsuperuser.getpass @@ -81,7 +88,9 @@ def mock_inputs(inputs): finally: createsuperuser.getpass = old_getpass builtins.input = old_input + return wrapped + return inner @@ -90,19 +99,22 @@ class MockTTY: A fake stdin object that pretends to be a TTY to be used in conjunction with mock_inputs. """ + def isatty(self): return True class MockInputTests(TestCase): - @mock_inputs({'username': 'alice'}) + @mock_inputs({"username": "alice"}) def test_input_not_found(self): - with self.assertRaisesMessage(ValueError, "Mock input for 'Email address: ' not found."): - call_command('createsuperuser', stdin=MockTTY()) + with self.assertRaisesMessage( + ValueError, "Mock input for 'Email address: ' not found." + ): + call_command("createsuperuser", stdin=MockTTY()) class GetDefaultUsernameTestCase(TestCase): - databases = {'default', 'other'} + databases = {"default", "other"} def setUp(self): self.old_get_system_username = management.get_system_username @@ -114,39 +126,39 @@ class GetDefaultUsernameTestCase(TestCase): self.assertIsInstance(management.get_system_username(), str) def test_simple(self): - management.get_system_username = lambda: 'joe' - self.assertEqual(management.get_default_username(), 'joe') + management.get_system_username = lambda: "joe" + self.assertEqual(management.get_default_username(), "joe") def test_existing(self): - User.objects.create(username='joe') - management.get_system_username = lambda: 'joe' - self.assertEqual(management.get_default_username(), '') - self.assertEqual( - management.get_default_username(check_db=False), 'joe') + User.objects.create(username="joe") + management.get_system_username = lambda: "joe" + self.assertEqual(management.get_default_username(), "") + self.assertEqual(management.get_default_username(check_db=False), "joe") def test_i18n(self): # 'Julia' with accented 'u': - management.get_system_username = lambda: 'J\xfalia' - self.assertEqual(management.get_default_username(), 'julia') + management.get_system_username = lambda: "J\xfalia" + self.assertEqual(management.get_default_username(), "julia") def test_with_database(self): - User.objects.create(username='joe') - management.get_system_username = lambda: 'joe' - self.assertEqual(management.get_default_username(), '') - self.assertEqual(management.get_default_username(database='other'), 'joe') + User.objects.create(username="joe") + management.get_system_username = lambda: "joe" + self.assertEqual(management.get_default_username(), "") + self.assertEqual(management.get_default_username(database="other"), "joe") - User.objects.using('other').create(username='joe') - self.assertEqual(management.get_default_username(database='other'), '') + User.objects.using("other").create(username="joe") + self.assertEqual(management.get_default_username(database="other"), "") -@override_settings(AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, -]) +@override_settings( + AUTH_PASSWORD_VALIDATORS=[ + {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, + ] +) class ChangepasswordManagementCommandTestCase(TestCase): - @classmethod def setUpTestData(cls): - cls.user = User.objects.create_user(username='joe', password='qwerty') + cls.user = User.objects.create_user(username="joe", password="qwerty") def setUp(self): self.stdout = StringIO() @@ -156,43 +168,47 @@ class ChangepasswordManagementCommandTestCase(TestCase): self.stdout.close() self.stderr.close() - @mock.patch.object(getpass, 'getpass', return_value='password') + @mock.patch.object(getpass, "getpass", return_value="password") def test_get_pass(self, mock_get_pass): - call_command('changepassword', username='joe', stdout=self.stdout) - self.assertIs(User.objects.get(username='joe').check_password('password'), True) + call_command("changepassword", username="joe", stdout=self.stdout) + self.assertIs(User.objects.get(username="joe").check_password("password"), True) - @mock.patch.object(getpass, 'getpass', return_value='') + @mock.patch.object(getpass, "getpass", return_value="") def test_get_pass_no_input(self, mock_get_pass): - with self.assertRaisesMessage(CommandError, 'aborted'): - call_command('changepassword', username='joe', stdout=self.stdout) + with self.assertRaisesMessage(CommandError, "aborted"): + call_command("changepassword", username="joe", stdout=self.stdout) - @mock.patch.object(changepassword.Command, '_get_pass', return_value='new_password') + @mock.patch.object(changepassword.Command, "_get_pass", return_value="new_password") def test_system_username(self, mock_get_pass): """The system username is used if --username isn't provided.""" username = getpass.getuser() - User.objects.create_user(username=username, password='qwerty') - call_command('changepassword', stdout=self.stdout) - self.assertIs(User.objects.get(username=username).check_password('new_password'), True) + User.objects.create_user(username=username, password="qwerty") + call_command("changepassword", stdout=self.stdout) + self.assertIs( + User.objects.get(username=username).check_password("new_password"), True + ) def test_nonexistent_username(self): with self.assertRaisesMessage(CommandError, "user 'test' does not exist"): - call_command('changepassword', username='test', stdout=self.stdout) + call_command("changepassword", username="test", stdout=self.stdout) - @mock.patch.object(changepassword.Command, '_get_pass', return_value='not qwerty') + @mock.patch.object(changepassword.Command, "_get_pass", return_value="not qwerty") def test_that_changepassword_command_changes_joes_password(self, mock_get_pass): "Executing the changepassword management command should change joe's password" - self.assertTrue(self.user.check_password('qwerty')) + self.assertTrue(self.user.check_password("qwerty")) - call_command('changepassword', username='joe', stdout=self.stdout) + call_command("changepassword", username="joe", stdout=self.stdout) command_output = self.stdout.getvalue().strip() self.assertEqual( command_output, - "Changing password for user 'joe'\nPassword changed successfully for user 'joe'" + "Changing password for user 'joe'\nPassword changed successfully for user 'joe'", ) self.assertTrue(User.objects.get(username="joe").check_password("not qwerty")) - @mock.patch.object(changepassword.Command, '_get_pass', side_effect=lambda *args: str(args)) + @mock.patch.object( + changepassword.Command, "_get_pass", side_effect=lambda *args: str(args) + ) def test_that_max_tries_exits_1(self, mock_get_pass): """ A CommandError should be thrown by handle() if the user enters in @@ -200,9 +216,11 @@ class ChangepasswordManagementCommandTestCase(TestCase): """ msg = "Aborting password change for user 'joe' after 3 attempts" with self.assertRaisesMessage(CommandError, msg): - call_command('changepassword', username='joe', stdout=self.stdout, stderr=self.stderr) + call_command( + "changepassword", username="joe", stdout=self.stdout, stderr=self.stderr + ) - @mock.patch.object(changepassword.Command, '_get_pass', return_value='1234567890') + @mock.patch.object(changepassword.Command, "_get_pass", return_value="1234567890") def test_password_validation(self, mock_get_pass): """ A CommandError should be raised if the user enters in passwords which @@ -210,52 +228,67 @@ class ChangepasswordManagementCommandTestCase(TestCase): """ abort_msg = "Aborting password change for user 'joe' after 3 attempts" with self.assertRaisesMessage(CommandError, abort_msg): - call_command('changepassword', username='joe', stdout=self.stdout, stderr=self.stderr) - self.assertIn('This password is entirely numeric.', self.stderr.getvalue()) + call_command( + "changepassword", username="joe", stdout=self.stdout, stderr=self.stderr + ) + self.assertIn("This password is entirely numeric.", self.stderr.getvalue()) - @mock.patch.object(changepassword.Command, '_get_pass', return_value='not qwerty') - def test_that_changepassword_command_works_with_nonascii_output(self, mock_get_pass): + @mock.patch.object(changepassword.Command, "_get_pass", return_value="not qwerty") + def test_that_changepassword_command_works_with_nonascii_output( + self, mock_get_pass + ): """ #21627 -- Executing the changepassword management command should allow non-ASCII characters from the User object representation. """ # 'Julia' with accented 'u': - User.objects.create_user(username='J\xfalia', password='qwerty') - call_command('changepassword', username='J\xfalia', stdout=self.stdout) + User.objects.create_user(username="J\xfalia", password="qwerty") + call_command("changepassword", username="J\xfalia", stdout=self.stdout) class MultiDBChangepasswordManagementCommandTestCase(TestCase): - databases = {'default', 'other'} + databases = {"default", "other"} - @mock.patch.object(changepassword.Command, '_get_pass', return_value='not qwerty') - def test_that_changepassword_command_with_database_option_uses_given_db(self, mock_get_pass): + @mock.patch.object(changepassword.Command, "_get_pass", return_value="not qwerty") + def test_that_changepassword_command_with_database_option_uses_given_db( + self, mock_get_pass + ): """ changepassword --database should operate on the specified DB. """ - user = User.objects.db_manager('other').create_user(username='joe', password='qwerty') - self.assertTrue(user.check_password('qwerty')) + user = User.objects.db_manager("other").create_user( + username="joe", password="qwerty" + ) + self.assertTrue(user.check_password("qwerty")) out = StringIO() - call_command('changepassword', username='joe', database='other', stdout=out) + call_command("changepassword", username="joe", database="other", stdout=out) command_output = out.getvalue().strip() self.assertEqual( command_output, - "Changing password for user 'joe'\nPassword changed successfully for user 'joe'" + "Changing password for user 'joe'\nPassword changed successfully for user 'joe'", + ) + self.assertTrue( + User.objects.using("other").get(username="joe").check_password("not qwerty") ) - self.assertTrue(User.objects.using('other').get(username="joe").check_password('not qwerty')) @override_settings( - SILENCED_SYSTEM_CHECKS=['fields.W342'], # ForeignKey(unique=True) - AUTH_PASSWORD_VALIDATORS=[{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}], + SILENCED_SYSTEM_CHECKS=["fields.W342"], # ForeignKey(unique=True) + AUTH_PASSWORD_VALIDATORS=[ + {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"} + ], ) class CreatesuperuserManagementCommandTestCase(TestCase): - def test_no_email_argument(self): new_io = StringIO() - with self.assertRaisesMessage(CommandError, 'You must use --email with --noinput.'): - call_command('createsuperuser', interactive=False, username='joe', stdout=new_io) + with self.assertRaisesMessage( + CommandError, "You must use --email with --noinput." + ): + call_command( + "createsuperuser", interactive=False, username="joe", stdout=new_io + ) def test_basic_usage(self): "Check the operation of the createsuperuser management command" @@ -266,26 +299,29 @@ class CreatesuperuserManagementCommandTestCase(TestCase): interactive=False, username="joe", email="joe@somewhere.org", - stdout=new_io + stdout=new_io, ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') + self.assertEqual(command_output, "Superuser created successfully.") u = User.objects.get(username="joe") - self.assertEqual(u.email, 'joe@somewhere.org') + self.assertEqual(u.email, "joe@somewhere.org") # created password should be unusable self.assertFalse(u.has_usable_password()) def test_non_ascii_verbose_name(self): - @mock_inputs({ - 'password': "nopasswd", - "Uživatel (leave blank to use '%s'): " % get_default_username(): 'foo', # username (cz) - 'email': 'nolocale@somewhere.org', - }) + @mock_inputs( + { + "password": "nopasswd", + "Uživatel (leave blank to use '%s'): " + % get_default_username(): "foo", # username (cz) + "email": "nolocale@somewhere.org", + } + ) def test(self): - username_field = User._meta.get_field('username') + username_field = User._meta.get_field("username") old_verbose_name = username_field.verbose_name - username_field.verbose_name = _('u\u017eivatel') + username_field.verbose_name = _("u\u017eivatel") new_io = StringIO() try: call_command( @@ -298,7 +334,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase): username_field.verbose_name = old_verbose_name command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') + self.assertEqual(command_output, "Superuser created successfully.") test(self) @@ -311,12 +347,12 @@ class CreatesuperuserManagementCommandTestCase(TestCase): username="joe2", email="joe2@somewhere.org", verbosity=0, - stdout=new_io + stdout=new_io, ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, '') + self.assertEqual(command_output, "") u = User.objects.get(username="joe2") - self.assertEqual(u.email, 'joe2@somewhere.org') + self.assertEqual(u.email, "joe2@somewhere.org") self.assertFalse(u.has_usable_password()) def test_email_in_username(self): @@ -328,10 +364,10 @@ class CreatesuperuserManagementCommandTestCase(TestCase): verbosity=0, ) u = User._default_manager.get(username="joe+admin@somewhere.org") - self.assertEqual(u.email, 'joe@somewhere.org') + self.assertEqual(u.email, "joe@somewhere.org") self.assertFalse(u.has_usable_password()) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUser") def test_swappable_user(self): "A superuser can be created when a custom user model is in use" # We can use the management command to create a superuser @@ -343,25 +379,27 @@ class CreatesuperuserManagementCommandTestCase(TestCase): interactive=False, email="joe@somewhere.org", date_of_birth="1976-04-01", - first_name='Joe', + first_name="Joe", stdout=new_io, ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') + self.assertEqual(command_output, "Superuser created successfully.") u = CustomUser._default_manager.get(email="joe@somewhere.org") self.assertEqual(u.date_of_birth, date(1976, 4, 1)) # created password should be unusable self.assertFalse(u.has_usable_password()) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUser") def test_swappable_user_missing_required_field(self): "A Custom superuser won't be created when a required field isn't provided" # We can use the management command to create a superuser # We skip validation because the temporary substitution of the # swappable User model messes with validation. new_io = StringIO() - with self.assertRaisesMessage(CommandError, 'You must use --email with --noinput.'): + with self.assertRaisesMessage( + CommandError, "You must use --email with --noinput." + ): call_command( "createsuperuser", interactive=False, @@ -372,14 +410,16 @@ class CreatesuperuserManagementCommandTestCase(TestCase): self.assertEqual(CustomUser._default_manager.count(), 0) @override_settings( - AUTH_USER_MODEL='auth_tests.CustomUserNonUniqueUsername', - AUTHENTICATION_BACKENDS=['my.custom.backend'], + AUTH_USER_MODEL="auth_tests.CustomUserNonUniqueUsername", + AUTHENTICATION_BACKENDS=["my.custom.backend"], ) def test_swappable_user_username_non_unique(self): - @mock_inputs({ - 'username': 'joe', - 'password': 'nopasswd', - }) + @mock_inputs( + { + "username": "joe", + "password": "nopasswd", + } + ) def createsuperuser(): new_io = StringIO() call_command( @@ -390,7 +430,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase): stdin=MockTTY(), ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') + self.assertEqual(command_output, "Superuser created successfully.") for i in range(2): createsuperuser() @@ -403,8 +443,10 @@ class CreatesuperuserManagementCommandTestCase(TestCase): If the command is not called from a TTY, it should be skipped and a message should be displayed (#7423). """ + class FakeStdin: """A fake stdin object that has isatty() return False.""" + def isatty(self): return False @@ -432,8 +474,8 @@ class CreatesuperuserManagementCommandTestCase(TestCase): stdin=sentinel, interactive=False, verbosity=0, - username='janet', - email='janet@example.com', + username="janet", + email="janet@example.com", ) self.assertIs(command.stdin, sentinel) @@ -442,18 +484,18 @@ class CreatesuperuserManagementCommandTestCase(TestCase): command, interactive=False, verbosity=0, - username='joe', - email='joe@example.com', + username="joe", + email="joe@example.com", ) self.assertIs(command.stdin, sys.stdin) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithFK") def test_fields_with_fk(self): new_io = StringIO() - group = Group.objects.create(name='mygroup') - email = Email.objects.create(email='mymail@gmail.com') + group = Group.objects.create(name="mygroup") + email = Email.objects.create(email="mymail@gmail.com") call_command( - 'createsuperuser', + "createsuperuser", interactive=False, username=email.pk, email=email.email, @@ -461,60 +503,62 @@ class CreatesuperuserManagementCommandTestCase(TestCase): stdout=new_io, ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') + self.assertEqual(command_output, "Superuser created successfully.") u = CustomUserWithFK._default_manager.get(email=email) self.assertEqual(u.username, email) self.assertEqual(u.group, group) - non_existent_email = 'mymail2@gmail.com' - msg = 'email instance with email %r does not exist.' % non_existent_email + non_existent_email = "mymail2@gmail.com" + msg = "email instance with email %r does not exist." % non_existent_email with self.assertRaisesMessage(CommandError, msg): call_command( - 'createsuperuser', + "createsuperuser", interactive=False, username=email.pk, email=non_existent_email, stdout=new_io, ) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithFK") def test_fields_with_fk_interactive(self): new_io = StringIO() - group = Group.objects.create(name='mygroup') - email = Email.objects.create(email='mymail@gmail.com') - - @mock_inputs({ - 'password': 'nopasswd', - 'Username (Email.id): ': email.pk, - 'Email (Email.email): ': email.email, - 'Group (Group.id): ': group.pk, - }) + group = Group.objects.create(name="mygroup") + email = Email.objects.create(email="mymail@gmail.com") + + @mock_inputs( + { + "password": "nopasswd", + "Username (Email.id): ": email.pk, + "Email (Email.email): ": email.email, + "Group (Group.id): ": group.pk, + } + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdout=new_io, stdin=MockTTY(), ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') + self.assertEqual(command_output, "Superuser created successfully.") u = CustomUserWithFK._default_manager.get(email=email) self.assertEqual(u.username, email) self.assertEqual(u.group, group) test(self) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithFK") def test_fields_with_fk_via_option_interactive(self): new_io = StringIO() - group = Group.objects.create(name='mygroup') - email = Email.objects.create(email='mymail@gmail.com') + group = Group.objects.create(name="mygroup") + email = Email.objects.create(email="mymail@gmail.com") - @mock_inputs({'password': 'nopasswd'}) + @mock_inputs({"password": "nopasswd"}) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, username=email.pk, email=email.email, @@ -524,23 +568,23 @@ class CreatesuperuserManagementCommandTestCase(TestCase): ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') + self.assertEqual(command_output, "Superuser created successfully.") u = CustomUserWithFK._default_manager.get(email=email) self.assertEqual(u.username, email) self.assertEqual(u.group, group) test(self) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithFK") def test_validate_fk(self): - email = Email.objects.create(email='mymail@gmail.com') + email = Email.objects.create(email="mymail@gmail.com") Group.objects.all().delete() nonexistent_group_id = 1 - msg = f'group instance with id {nonexistent_group_id} does not exist.' + msg = f"group instance with id {nonexistent_group_id} does not exist." with self.assertRaisesMessage(CommandError, msg): call_command( - 'createsuperuser', + "createsuperuser", interactive=False, username=email.pk, email=email.email, @@ -548,42 +592,44 @@ class CreatesuperuserManagementCommandTestCase(TestCase): verbosity=0, ) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithFK") def test_validate_fk_environment_variable(self): - email = Email.objects.create(email='mymail@gmail.com') + email = Email.objects.create(email="mymail@gmail.com") Group.objects.all().delete() nonexistent_group_id = 1 - msg = f'group instance with id {nonexistent_group_id} does not exist.' + msg = f"group instance with id {nonexistent_group_id} does not exist." with mock.patch.dict( os.environ, - {'DJANGO_SUPERUSER_GROUP': str(nonexistent_group_id)}, + {"DJANGO_SUPERUSER_GROUP": str(nonexistent_group_id)}, ): with self.assertRaisesMessage(CommandError, msg): call_command( - 'createsuperuser', + "createsuperuser", interactive=False, username=email.pk, email=email.email, verbosity=0, ) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithFK') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithFK") def test_validate_fk_via_option_interactive(self): - email = Email.objects.create(email='mymail@gmail.com') + email = Email.objects.create(email="mymail@gmail.com") Group.objects.all().delete() nonexistent_group_id = 1 - msg = f'group instance with id {nonexistent_group_id} does not exist.' - - @mock_inputs({ - 'password': 'nopasswd', - 'Username (Email.id): ': email.pk, - 'Email (Email.email): ': email.email, - }) + msg = f"group instance with id {nonexistent_group_id} does not exist." + + @mock_inputs( + { + "password": "nopasswd", + "Username (Email.id): ": email.pk, + "Email (Email.email): ": email.email, + } + ) def test(self): with self.assertRaisesMessage(CommandError, msg): call_command( - 'createsuperuser', + "createsuperuser", group=nonexistent_group_id, stdin=MockTTY(), verbosity=0, @@ -591,65 +637,69 @@ class CreatesuperuserManagementCommandTestCase(TestCase): test(self) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithM2m') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithM2m") def test_fields_with_m2m(self): new_io = StringIO() - org_id_1 = Organization.objects.create(name='Organization 1').pk - org_id_2 = Organization.objects.create(name='Organization 2').pk + org_id_1 = Organization.objects.create(name="Organization 1").pk + org_id_2 = Organization.objects.create(name="Organization 2").pk call_command( - 'createsuperuser', + "createsuperuser", interactive=False, - username='joe', + username="joe", orgs=[org_id_1, org_id_2], stdout=new_io, ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') - user = CustomUserWithM2M._default_manager.get(username='joe') + self.assertEqual(command_output, "Superuser created successfully.") + user = CustomUserWithM2M._default_manager.get(username="joe") self.assertEqual(user.orgs.count(), 2) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithM2M') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithM2M") def test_fields_with_m2m_interactive(self): new_io = StringIO() - org_id_1 = Organization.objects.create(name='Organization 1').pk - org_id_2 = Organization.objects.create(name='Organization 2').pk - - @mock_inputs({ - 'password': 'nopasswd', - 'Username: ': 'joe', - 'Orgs (Organization.id): ': '%s, %s' % (org_id_1, org_id_2), - }) + org_id_1 = Organization.objects.create(name="Organization 1").pk + org_id_2 = Organization.objects.create(name="Organization 2").pk + + @mock_inputs( + { + "password": "nopasswd", + "Username: ": "joe", + "Orgs (Organization.id): ": "%s, %s" % (org_id_1, org_id_2), + } + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdout=new_io, stdin=MockTTY(), ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') - user = CustomUserWithM2M._default_manager.get(username='joe') + self.assertEqual(command_output, "Superuser created successfully.") + user = CustomUserWithM2M._default_manager.get(username="joe") self.assertEqual(user.orgs.count(), 2) test(self) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithM2M') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithM2M") def test_fields_with_m2m_interactive_blank(self): new_io = StringIO() - org_id = Organization.objects.create(name='Organization').pk - entered_orgs = [str(org_id), ' '] + org_id = Organization.objects.create(name="Organization").pk + entered_orgs = [str(org_id), " "] def return_orgs(): return entered_orgs.pop() - @mock_inputs({ - 'password': 'nopasswd', - 'Username: ': 'joe', - 'Orgs (Organization.id): ': return_orgs, - }) + @mock_inputs( + { + "password": "nopasswd", + "Username: ": "joe", + "Orgs (Organization.id): ": return_orgs, + } + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdout=new_io, stderr=new_io, @@ -657,41 +707,43 @@ class CreatesuperuserManagementCommandTestCase(TestCase): ) self.assertEqual( new_io.getvalue().strip(), - 'Error: This field cannot be blank.\n' - 'Superuser created successfully.', + "Error: This field cannot be blank.\n" + "Superuser created successfully.", ) test(self) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithM2MThrough') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithM2MThrough") def test_fields_with_m2m_and_through(self): msg = ( "Required field 'orgs' specifies a many-to-many relation through " "model, which is not supported." ) with self.assertRaisesMessage(CommandError, msg): - call_command('createsuperuser') + call_command("createsuperuser") def test_default_username(self): """createsuperuser uses a default username when one isn't provided.""" # Get the default username before creating a user. default_username = get_default_username() new_io = StringIO() - entered_passwords = ['password', 'password'] + entered_passwords = ["password", "password"] def return_passwords(): return entered_passwords.pop(0) - @mock_inputs({'password': return_passwords, 'username': '', 'email': ''}) + @mock_inputs({"password": return_passwords, "username": "", "email": ""}) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), stdout=new_io, stderr=new_io, ) - self.assertEqual(new_io.getvalue().strip(), 'Superuser created successfully.') + self.assertEqual( + new_io.getvalue().strip(), "Superuser created successfully." + ) self.assertTrue(User.objects.filter(username=default_username).exists()) test(self) @@ -701,17 +753,19 @@ class CreatesuperuserManagementCommandTestCase(TestCase): Creation should fail if the password fails validation. """ new_io = StringIO() - entered_passwords = ['1234567890', '1234567890', 'password', 'password'] + entered_passwords = ["1234567890", "1234567890", "password", "password"] def bad_then_good_password(): return entered_passwords.pop(0) - @mock_inputs({ - 'password': bad_then_good_password, - 'username': 'joe1234567890', - 'email': '', - 'bypass': 'n', - }) + @mock_inputs( + { + "password": bad_then_good_password, + "username": "joe1234567890", + "email": "", + "bypass": "n", + } + ) def test(self): call_command( "createsuperuser", @@ -723,31 +777,42 @@ class CreatesuperuserManagementCommandTestCase(TestCase): self.assertEqual( new_io.getvalue().strip(), "This password is entirely numeric.\n" - "Superuser created successfully." + "Superuser created successfully.", ) test(self) - @override_settings(AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - ]) + @override_settings( + AUTH_PASSWORD_VALIDATORS=[ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + ] + ) def test_validate_password_against_username(self): new_io = StringIO() - username = 'supremelycomplex' - entered_passwords = [username, username, 'superduperunguessablepassword', 'superduperunguessablepassword'] + username = "supremelycomplex" + entered_passwords = [ + username, + username, + "superduperunguessablepassword", + "superduperunguessablepassword", + ] def bad_then_good_password(): return entered_passwords.pop(0) - @mock_inputs({ - 'password': bad_then_good_password, - 'username': username, - 'email': '', - 'bypass': 'n', - }) + @mock_inputs( + { + "password": bad_then_good_password, + "username": username, + "email": "", + "bypass": "n", + } + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), stdout=new_io, @@ -755,37 +820,46 @@ class CreatesuperuserManagementCommandTestCase(TestCase): ) self.assertEqual( new_io.getvalue().strip(), - 'The password is too similar to the username.\n' - 'Superuser created successfully.' + "The password is too similar to the username.\n" + "Superuser created successfully.", ) test(self) @override_settings( - AUTH_USER_MODEL='auth_tests.CustomUser', + AUTH_USER_MODEL="auth_tests.CustomUser", AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - ] + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + ], ) def test_validate_password_against_required_fields(self): new_io = StringIO() - first_name = 'josephine' - entered_passwords = [first_name, first_name, 'superduperunguessablepassword', 'superduperunguessablepassword'] + first_name = "josephine" + entered_passwords = [ + first_name, + first_name, + "superduperunguessablepassword", + "superduperunguessablepassword", + ] def bad_then_good_password(): return entered_passwords.pop(0) - @mock_inputs({ - 'password': bad_then_good_password, - 'username': 'whatever', - 'first_name': first_name, - 'date_of_birth': '1970-01-01', - 'email': 'joey@example.com', - 'bypass': 'n', - }) + @mock_inputs( + { + "password": bad_then_good_password, + "username": "whatever", + "first_name": first_name, + "date_of_birth": "1970-01-01", + "email": "joey@example.com", + "bypass": "n", + } + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), stdout=new_io, @@ -794,47 +868,53 @@ class CreatesuperuserManagementCommandTestCase(TestCase): self.assertEqual( new_io.getvalue().strip(), "The password is too similar to the first name.\n" - "Superuser created successfully." + "Superuser created successfully.", ) test(self) @override_settings( - AUTH_USER_MODEL='auth_tests.CustomUser', + AUTH_USER_MODEL="auth_tests.CustomUser", AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - ] + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + ], ) def test_validate_password_against_required_fields_via_option(self): new_io = StringIO() - first_name = 'josephine' + first_name = "josephine" entered_passwords = [ - first_name, first_name, - 'superduperunguessablepassword', 'superduperunguessablepassword', + first_name, + first_name, + "superduperunguessablepassword", + "superduperunguessablepassword", ] def bad_then_good_password(): return entered_passwords.pop(0) - @mock_inputs({ - 'password': bad_then_good_password, - 'bypass': 'n', - }) + @mock_inputs( + { + "password": bad_then_good_password, + "bypass": "n", + } + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, first_name=first_name, - date_of_birth='1970-01-01', - email='joey@example.com', + date_of_birth="1970-01-01", + email="joey@example.com", stdin=MockTTY(), stdout=new_io, stderr=new_io, ) self.assertEqual( new_io.getvalue().strip(), - 'The password is too similar to the first name.\n' - 'Superuser created successfully.' + "The password is too similar to the first name.\n" + "Superuser created successfully.", ) test(self) @@ -842,10 +922,10 @@ class CreatesuperuserManagementCommandTestCase(TestCase): def test_blank_username(self): """Creation fails if --username is blank.""" new_io = StringIO() - with self.assertRaisesMessage(CommandError, 'Username cannot be blank.'): + with self.assertRaisesMessage(CommandError, "Username cannot be blank."): call_command( - 'createsuperuser', - username='', + "createsuperuser", + username="", stdin=MockTTY(), stdout=new_io, stderr=new_io, @@ -853,10 +933,10 @@ class CreatesuperuserManagementCommandTestCase(TestCase): def test_blank_username_non_interactive(self): new_io = StringIO() - with self.assertRaisesMessage(CommandError, 'Username cannot be blank.'): + with self.assertRaisesMessage(CommandError, "Username cannot be blank."): call_command( - 'createsuperuser', - username='', + "createsuperuser", + username="", interactive=False, stdin=MockTTY(), stdout=new_io, @@ -869,15 +949,17 @@ class CreatesuperuserManagementCommandTestCase(TestCase): """ new_io = StringIO() - @mock_inputs({ - 'password': '1234567890', - 'username': 'joe1234567890', - 'email': '', - 'bypass': 'y', - }) + @mock_inputs( + { + "password": "1234567890", + "username": "joe1234567890", + "email": "", + "bypass": "y", + } + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), stdout=new_io, @@ -885,8 +967,8 @@ class CreatesuperuserManagementCommandTestCase(TestCase): ) self.assertEqual( new_io.getvalue().strip(), - 'This password is entirely numeric.\n' - 'Superuser created successfully.' + "This password is entirely numeric.\n" + "Superuser created successfully.", ) test(self) @@ -895,10 +977,10 @@ class CreatesuperuserManagementCommandTestCase(TestCase): """Creation fails if the username fails validation.""" user_field = User._meta.get_field(User.USERNAME_FIELD) new_io = StringIO() - entered_passwords = ['password', 'password'] + entered_passwords = ["password", "password"] # Enter an invalid (too long) username first and then a valid one. - invalid_username = ('x' * user_field.max_length) + 'y' - entered_usernames = [invalid_username, 'janet'] + invalid_username = ("x" * user_field.max_length) + "y" + entered_usernames = [invalid_username, "janet"] def return_passwords(): return entered_passwords.pop(0) @@ -906,10 +988,12 @@ class CreatesuperuserManagementCommandTestCase(TestCase): def return_usernames(): return entered_usernames.pop(0) - @mock_inputs({'password': return_passwords, 'username': return_usernames, 'email': ''}) + @mock_inputs( + {"password": return_passwords, "username": return_usernames, "email": ""} + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), stdout=new_io, @@ -917,32 +1001,33 @@ class CreatesuperuserManagementCommandTestCase(TestCase): ) self.assertEqual( new_io.getvalue().strip(), - 'Error: Ensure this value has at most %s characters (it has %s).\n' - 'Superuser created successfully.' % (user_field.max_length, len(invalid_username)) + "Error: Ensure this value has at most %s characters (it has %s).\n" + "Superuser created successfully." + % (user_field.max_length, len(invalid_username)), ) test(self) - @mock_inputs({'username': 'KeyboardInterrupt'}) + @mock_inputs({"username": "KeyboardInterrupt"}) def test_keyboard_interrupt(self): new_io = StringIO() with self.assertRaises(SystemExit): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), stdout=new_io, stderr=new_io, ) - self.assertEqual(new_io.getvalue(), '\nOperation cancelled.\n') + self.assertEqual(new_io.getvalue(), "\nOperation cancelled.\n") def test_existing_username(self): """Creation fails if the username already exists.""" - user = User.objects.create(username='janet') + user = User.objects.create(username="janet") new_io = StringIO() - entered_passwords = ['password', 'password'] + entered_passwords = ["password", "password"] # Enter the existing username first and then a new one. - entered_usernames = [user.username, 'joe'] + entered_usernames = [user.username, "joe"] def return_passwords(): return entered_passwords.pop(0) @@ -950,10 +1035,12 @@ class CreatesuperuserManagementCommandTestCase(TestCase): def return_usernames(): return entered_usernames.pop(0) - @mock_inputs({'password': return_passwords, 'username': return_usernames, 'email': ''}) + @mock_inputs( + {"password": return_passwords, "username": return_usernames, "email": ""} + ) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), stdout=new_io, @@ -961,21 +1048,23 @@ class CreatesuperuserManagementCommandTestCase(TestCase): ) self.assertEqual( new_io.getvalue().strip(), - 'Error: That username is already taken.\n' - 'Superuser created successfully.' + "Error: That username is already taken.\n" + "Superuser created successfully.", ) test(self) def test_existing_username_non_interactive(self): """Creation fails if the username already exists.""" - User.objects.create(username='janet') + User.objects.create(username="janet") new_io = StringIO() - with self.assertRaisesMessage(CommandError, "Error: That username is already taken."): + with self.assertRaisesMessage( + CommandError, "Error: That username is already taken." + ): call_command( - 'createsuperuser', - username='janet', - email='', + "createsuperuser", + username="janet", + email="", interactive=False, stdout=new_io, ) @@ -983,27 +1072,29 @@ class CreatesuperuserManagementCommandTestCase(TestCase): def test_existing_username_provided_via_option_and_interactive(self): """call_command() gets username='janet' and interactive=True.""" new_io = StringIO() - entered_passwords = ['password', 'password'] - User.objects.create(username='janet') + entered_passwords = ["password", "password"] + User.objects.create(username="janet") def return_passwords(): return entered_passwords.pop(0) - @mock_inputs({ - 'password': return_passwords, - 'username': 'janet1', - 'email': 'test@test.com' - }) + @mock_inputs( + { + "password": return_passwords, + "username": "janet1", + "email": "test@test.com", + } + ) def test(self): call_command( - 'createsuperuser', - username='janet', + "createsuperuser", + username="janet", interactive=True, stdin=MockTTY(), stdout=new_io, stderr=new_io, ) - msg = 'Error: That username is already taken.\nSuperuser created successfully.' + msg = "Error: That username is already taken.\nSuperuser created successfully." self.assertEqual(new_io.getvalue().strip(), msg) test(self) @@ -1021,11 +1112,13 @@ class CreatesuperuserManagementCommandTestCase(TestCase): def mismatched_passwords_then_matched(): return entered_passwords.pop(0) - @mock_inputs({ - 'password': mismatched_passwords_then_matched, - 'username': 'joe1234567890', - 'email': '', - }) + @mock_inputs( + { + "password": mismatched_passwords_then_matched, + "username": "joe1234567890", + "email": "", + } + ) def test(self): call_command( "createsuperuser", @@ -1037,7 +1130,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase): self.assertEqual( new_io.getvalue().strip(), "Error: Your passwords didn't match.\n" - "Superuser created successfully." + "Superuser created successfully.", ) test(self) @@ -1055,11 +1148,13 @@ class CreatesuperuserManagementCommandTestCase(TestCase): def blank_passwords_then_valid(): return entered_passwords.pop(0) - @mock_inputs({ - 'password': blank_passwords_then_valid, - 'username': 'joe1234567890', - 'email': '', - }) + @mock_inputs( + { + "password": blank_passwords_then_valid, + "username": "joe1234567890", + "email": "", + } + ) def test(self): call_command( "createsuperuser", @@ -1071,118 +1166,132 @@ class CreatesuperuserManagementCommandTestCase(TestCase): self.assertEqual( new_io.getvalue().strip(), "Error: Blank passwords aren't allowed.\n" - "Superuser created successfully." + "Superuser created successfully.", ) test(self) - @override_settings(AUTH_USER_MODEL='auth_tests.NoPasswordUser') + @override_settings(AUTH_USER_MODEL="auth_tests.NoPasswordUser") def test_usermodel_without_password(self): new_io = StringIO() call_command( - 'createsuperuser', + "createsuperuser", interactive=False, stdin=MockTTY(), stdout=new_io, stderr=new_io, - username='username', + username="username", ) - self.assertEqual(new_io.getvalue().strip(), 'Superuser created successfully.') + self.assertEqual(new_io.getvalue().strip(), "Superuser created successfully.") - @override_settings(AUTH_USER_MODEL='auth_tests.NoPasswordUser') + @override_settings(AUTH_USER_MODEL="auth_tests.NoPasswordUser") def test_usermodel_without_password_interactive(self): new_io = StringIO() - @mock_inputs({'username': 'username'}) + @mock_inputs({"username": "username"}) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), stdout=new_io, stderr=new_io, ) - self.assertEqual(new_io.getvalue().strip(), 'Superuser created successfully.') + self.assertEqual( + new_io.getvalue().strip(), "Superuser created successfully." + ) test(self) - @mock.patch.dict(os.environ, { - 'DJANGO_SUPERUSER_PASSWORD': 'test_password', - 'DJANGO_SUPERUSER_USERNAME': 'test_superuser', - 'DJANGO_SUPERUSER_EMAIL': 'joe@somewhere.org', - 'DJANGO_SUPERUSER_FIRST_NAME': 'ignored_first_name', - }) + @mock.patch.dict( + os.environ, + { + "DJANGO_SUPERUSER_PASSWORD": "test_password", + "DJANGO_SUPERUSER_USERNAME": "test_superuser", + "DJANGO_SUPERUSER_EMAIL": "joe@somewhere.org", + "DJANGO_SUPERUSER_FIRST_NAME": "ignored_first_name", + }, + ) def test_environment_variable_non_interactive(self): - call_command('createsuperuser', interactive=False, verbosity=0) - user = User.objects.get(username='test_superuser') - self.assertEqual(user.email, 'joe@somewhere.org') - self.assertTrue(user.check_password('test_password')) + call_command("createsuperuser", interactive=False, verbosity=0) + user = User.objects.get(username="test_superuser") + self.assertEqual(user.email, "joe@somewhere.org") + self.assertTrue(user.check_password("test_password")) # Environment variables are ignored for non-required fields. - self.assertEqual(user.first_name, '') + self.assertEqual(user.first_name, "") - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserWithM2m') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUserWithM2m") def test_environment_variable_m2m_non_interactive(self): new_io = StringIO() - org_id_1 = Organization.objects.create(name='Organization 1').pk - org_id_2 = Organization.objects.create(name='Organization 2').pk - with mock.patch.dict(os.environ, { - 'DJANGO_SUPERUSER_ORGS': f'{org_id_1},{org_id_2}', - }): + org_id_1 = Organization.objects.create(name="Organization 1").pk + org_id_2 = Organization.objects.create(name="Organization 2").pk + with mock.patch.dict( + os.environ, + { + "DJANGO_SUPERUSER_ORGS": f"{org_id_1},{org_id_2}", + }, + ): call_command( - 'createsuperuser', + "createsuperuser", interactive=False, - username='joe', + username="joe", stdout=new_io, ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') - user = CustomUserWithM2M._default_manager.get(username='joe') + self.assertEqual(command_output, "Superuser created successfully.") + user = CustomUserWithM2M._default_manager.get(username="joe") self.assertEqual(user.orgs.count(), 2) - @mock.patch.dict(os.environ, { - 'DJANGO_SUPERUSER_USERNAME': 'test_superuser', - 'DJANGO_SUPERUSER_EMAIL': 'joe@somewhere.org', - }) + @mock.patch.dict( + os.environ, + { + "DJANGO_SUPERUSER_USERNAME": "test_superuser", + "DJANGO_SUPERUSER_EMAIL": "joe@somewhere.org", + }, + ) def test_ignore_environment_variable_non_interactive(self): # Environment variables are ignored in non-interactive mode, if # provided by a command line arguments. call_command( - 'createsuperuser', + "createsuperuser", interactive=False, - username='cmd_superuser', - email='cmd@somewhere.org', + username="cmd_superuser", + email="cmd@somewhere.org", verbosity=0, ) - user = User.objects.get(username='cmd_superuser') - self.assertEqual(user.email, 'cmd@somewhere.org') + user = User.objects.get(username="cmd_superuser") + self.assertEqual(user.email, "cmd@somewhere.org") self.assertFalse(user.has_usable_password()) - @mock.patch.dict(os.environ, { - 'DJANGO_SUPERUSER_PASSWORD': 'test_password', - 'DJANGO_SUPERUSER_USERNAME': 'test_superuser', - 'DJANGO_SUPERUSER_EMAIL': 'joe@somewhere.org', - }) + @mock.patch.dict( + os.environ, + { + "DJANGO_SUPERUSER_PASSWORD": "test_password", + "DJANGO_SUPERUSER_USERNAME": "test_superuser", + "DJANGO_SUPERUSER_EMAIL": "joe@somewhere.org", + }, + ) def test_ignore_environment_variable_interactive(self): # Environment variables are ignored in interactive mode. - @mock_inputs({'password': 'cmd_password'}) + @mock_inputs({"password": "cmd_password"}) def test(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, - username='cmd_superuser', - email='cmd@somewhere.org', + username="cmd_superuser", + email="cmd@somewhere.org", stdin=MockTTY(), verbosity=0, ) - user = User.objects.get(username='cmd_superuser') - self.assertEqual(user.email, 'cmd@somewhere.org') - self.assertTrue(user.check_password('cmd_password')) + user = User.objects.get(username="cmd_superuser") + self.assertEqual(user.email, "cmd@somewhere.org") + self.assertTrue(user.check_password("cmd_password")) test(self) class MultiDBCreatesuperuserTestCase(TestCase): - databases = {'default', 'other'} + databases = {"default", "other"} def test_createsuperuser_command_with_database_option(self): """ @@ -1190,55 +1299,54 @@ class MultiDBCreatesuperuserTestCase(TestCase): """ new_io = StringIO() call_command( - 'createsuperuser', + "createsuperuser", interactive=False, - username='joe', - email='joe@somewhere.org', - database='other', + username="joe", + email="joe@somewhere.org", + database="other", stdout=new_io, ) command_output = new_io.getvalue().strip() - self.assertEqual(command_output, 'Superuser created successfully.') - user = User.objects.using('other').get(username='joe') - self.assertEqual(user.email, 'joe@somewhere.org') + self.assertEqual(command_output, "Superuser created successfully.") + user = User.objects.using("other").get(username="joe") + self.assertEqual(user.email, "joe@somewhere.org") def test_createsuperuser_command_suggested_username_with_database_option(self): - default_username = get_default_username(database='other') - qs = User.objects.using('other') + default_username = get_default_username(database="other") + qs = User.objects.using("other") - @mock_inputs({'password': 'nopasswd', 'username': '', 'email': ''}) + @mock_inputs({"password": "nopasswd", "username": "", "email": ""}) def test_other_create_with_suggested_username(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), verbosity=0, - database='other', + database="other", ) self.assertIs(qs.filter(username=default_username).exists(), True) test_other_create_with_suggested_username(self) - @mock_inputs({'password': 'nopasswd', 'Username: ': 'other', 'email': ''}) + @mock_inputs({"password": "nopasswd", "Username: ": "other", "email": ""}) def test_other_no_suggestion(self): call_command( - 'createsuperuser', + "createsuperuser", interactive=True, stdin=MockTTY(), verbosity=0, - database='other', + database="other", ) - self.assertIs(qs.filter(username='other').exists(), True) + self.assertIs(qs.filter(username="other").exists(), True) test_other_no_suggestion(self) class CreatePermissionsTests(TestCase): - def setUp(self): self._original_permissions = Permission._meta.permissions[:] self._original_default_permissions = Permission._meta.default_permissions - self.app_config = apps.get_app_config('auth') + self.app_config = apps.get_app_config("auth") def tearDown(self): Permission._meta.permissions = self._original_permissions @@ -1246,25 +1354,33 @@ class CreatePermissionsTests(TestCase): ContentType.objects.clear_cache() def test_default_permissions(self): - permission_content_type = ContentType.objects.get_by_natural_key('auth', 'permission') + permission_content_type = ContentType.objects.get_by_natural_key( + "auth", "permission" + ) Permission._meta.permissions = [ - ('my_custom_permission', 'Some permission'), + ("my_custom_permission", "Some permission"), ] create_permissions(self.app_config, verbosity=0) # view/add/change/delete permission by default + custom permission - self.assertEqual(Permission.objects.filter( - content_type=permission_content_type, - ).count(), 5) + self.assertEqual( + Permission.objects.filter( + content_type=permission_content_type, + ).count(), + 5, + ) Permission.objects.filter(content_type=permission_content_type).delete() Permission._meta.default_permissions = [] create_permissions(self.app_config, verbosity=0) # custom permission only since default permissions is empty - self.assertEqual(Permission.objects.filter( - content_type=permission_content_type, - ).count(), 1) + self.assertEqual( + Permission.objects.filter( + content_type=permission_content_type, + ).count(), + 1, + ) def test_unavailable_models(self): """ @@ -1276,7 +1392,7 @@ class CreatePermissionsTests(TestCase): with self.assertNumQueries(0): create_permissions(self.app_config, verbosity=0, apps=state.apps) # Unavailable auth.Permission - state = migrations.state.ProjectState(real_apps={'contenttypes'}) + state = migrations.state.ProjectState(real_apps={"contenttypes"}) with self.assertNumQueries(0): create_permissions(self.app_config, verbosity=0, apps=state.apps) @@ -1288,9 +1404,9 @@ class CreatePermissionsTests(TestCase): # Warm the manager cache. ContentType.objects.get_for_model(Group) # Apply a deletion as if e.g. a database 'flush' had been executed. - ContentType.objects.filter(app_label='auth', model='group').delete() + ContentType.objects.filter(app_label="auth", model="group").delete() # This fails with a foreign key constraint without the fix. - create_permissions(apps.get_app_config('auth'), interactive=False, verbosity=0) + create_permissions(apps.get_app_config("auth"), interactive=False, verbosity=0) def test_permission_with_proxy_content_type_created(self): """ @@ -1298,7 +1414,7 @@ class CreatePermissionsTests(TestCase): content type of the concrete model. """ opts = UserProxy._meta - codename = get_permission_codename('add', opts) + codename = get_permission_codename("add", opts) self.assertTrue( Permission.objects.filter( content_type__model=opts.model_name, diff --git a/tests/auth_tests/test_middleware.py b/tests/auth_tests/test_middleware.py index 79856bb8b0..3d2d0fcb48 100644 --- a/tests/auth_tests/test_middleware.py +++ b/tests/auth_tests/test_middleware.py @@ -8,7 +8,9 @@ from django.test import TestCase class TestAuthenticationMiddleware(TestCase): @classmethod def setUpTestData(cls): - cls.user = User.objects.create_user('test_user', 'test@example.com', 'test_password') + cls.user = User.objects.create_user( + "test_user", "test@example.com", "test_password" + ) def setUp(self): self.middleware = AuthenticationMiddleware(lambda req: HttpResponse()) @@ -24,7 +26,7 @@ class TestAuthenticationMiddleware(TestCase): def test_changed_password_invalidates_session(self): # After password change, user should be anonymous - self.user.set_password('new_password') + self.user.set_password("new_password") self.user.save() self.middleware(self.request) self.assertIsNotNone(self.request.user) diff --git a/tests/auth_tests/test_migrations.py b/tests/auth_tests/test_migrations.py index a91b9a9146..7fa0487029 100644 --- a/tests/auth_tests/test_migrations.py +++ b/tests/auth_tests/test_migrations.py @@ -9,14 +9,16 @@ from django.test.utils import captured_stdout from .models import Proxy, UserProxy -update_proxy_permissions = import_module('django.contrib.auth.migrations.0011_update_proxy_permissions') +update_proxy_permissions = import_module( + "django.contrib.auth.migrations.0011_update_proxy_permissions" +) class ProxyModelWithDifferentAppLabelTests(TransactionTestCase): available_apps = [ - 'auth_tests', - 'django.contrib.auth', - 'django.contrib.contenttypes', + "auth_tests", + "django.contrib.auth", + "django.contrib.contenttypes", ] def setUp(self): @@ -29,19 +31,25 @@ class ProxyModelWithDifferentAppLabelTests(TransactionTestCase): self.concrete_content_type = ContentType.objects.get_for_model(UserProxy) self.default_permission = Permission.objects.create( content_type=self.concrete_content_type, - codename='add_userproxy', - name='Can add userproxy', + codename="add_userproxy", + name="Can add userproxy", ) self.custom_permission = Permission.objects.create( content_type=self.concrete_content_type, - codename='use_different_app_label', - name='May use a different app label', + codename="use_different_app_label", + name="May use a different app label", ) def test_proxy_model_permissions_contenttype(self): - proxy_model_content_type = ContentType.objects.get_for_model(UserProxy, for_concrete_model=False) - self.assertEqual(self.default_permission.content_type, self.concrete_content_type) - self.assertEqual(self.custom_permission.content_type, self.concrete_content_type) + proxy_model_content_type = ContentType.objects.get_for_model( + UserProxy, for_concrete_model=False + ) + self.assertEqual( + self.default_permission.content_type, self.concrete_content_type + ) + self.assertEqual( + self.custom_permission.content_type, self.concrete_content_type + ) with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) self.default_permission.refresh_from_db() @@ -54,47 +62,51 @@ class ProxyModelWithDifferentAppLabelTests(TransactionTestCase): user.user_permissions.add(self.default_permission) user.user_permissions.add(self.custom_permission) for permission in [self.default_permission, self.custom_permission]: - self.assertTrue(user.has_perm('auth.' + permission.codename)) - self.assertFalse(user.has_perm('auth_tests.' + permission.codename)) + self.assertTrue(user.has_perm("auth." + permission.codename)) + self.assertFalse(user.has_perm("auth_tests." + permission.codename)) with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) # Reload user to purge the _perm_cache. user = User._default_manager.get(pk=user.pk) for permission in [self.default_permission, self.custom_permission]: - self.assertFalse(user.has_perm('auth.' + permission.codename)) - self.assertTrue(user.has_perm('auth_tests.' + permission.codename)) + self.assertFalse(user.has_perm("auth." + permission.codename)) + self.assertTrue(user.has_perm("auth_tests." + permission.codename)) def test_migrate_backwards(self): with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) update_proxy_permissions.revert_proxy_model_permissions(apps, editor) self.default_permission.refresh_from_db() - self.assertEqual(self.default_permission.content_type, self.concrete_content_type) + self.assertEqual( + self.default_permission.content_type, self.concrete_content_type + ) self.custom_permission.refresh_from_db() - self.assertEqual(self.custom_permission.content_type, self.concrete_content_type) + self.assertEqual( + self.custom_permission.content_type, self.concrete_content_type + ) def test_user_keeps_same_permissions_after_migrating_backward(self): user = User.objects.create() user.user_permissions.add(self.default_permission) user.user_permissions.add(self.custom_permission) for permission in [self.default_permission, self.custom_permission]: - self.assertTrue(user.has_perm('auth.' + permission.codename)) - self.assertFalse(user.has_perm('auth_tests.' + permission.codename)) + self.assertTrue(user.has_perm("auth." + permission.codename)) + self.assertFalse(user.has_perm("auth_tests." + permission.codename)) with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) update_proxy_permissions.revert_proxy_model_permissions(apps, editor) # Reload user to purge the _perm_cache. user = User._default_manager.get(pk=user.pk) for permission in [self.default_permission, self.custom_permission]: - self.assertTrue(user.has_perm('auth.' + permission.codename)) - self.assertFalse(user.has_perm('auth_tests.' + permission.codename)) + self.assertTrue(user.has_perm("auth." + permission.codename)) + self.assertFalse(user.has_perm("auth_tests." + permission.codename)) class ProxyModelWithSameAppLabelTests(TransactionTestCase): available_apps = [ - 'auth_tests', - 'django.contrib.auth', - 'django.contrib.contenttypes', + "auth_tests", + "django.contrib.auth", + "django.contrib.contenttypes", ] def setUp(self): @@ -107,19 +119,25 @@ class ProxyModelWithSameAppLabelTests(TransactionTestCase): self.concrete_content_type = ContentType.objects.get_for_model(Proxy) self.default_permission = Permission.objects.create( content_type=self.concrete_content_type, - codename='add_proxy', - name='Can add proxy', + codename="add_proxy", + name="Can add proxy", ) self.custom_permission = Permission.objects.create( content_type=self.concrete_content_type, - codename='display_proxys', - name='May display proxys information', + codename="display_proxys", + name="May display proxys information", ) def test_proxy_model_permissions_contenttype(self): - proxy_model_content_type = ContentType.objects.get_for_model(Proxy, for_concrete_model=False) - self.assertEqual(self.default_permission.content_type, self.concrete_content_type) - self.assertEqual(self.custom_permission.content_type, self.concrete_content_type) + proxy_model_content_type = ContentType.objects.get_for_model( + Proxy, for_concrete_model=False + ) + self.assertEqual( + self.default_permission.content_type, self.concrete_content_type + ) + self.assertEqual( + self.custom_permission.content_type, self.concrete_content_type + ) with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) self.default_permission.refresh_from_db() @@ -132,36 +150,40 @@ class ProxyModelWithSameAppLabelTests(TransactionTestCase): user.user_permissions.add(self.default_permission) user.user_permissions.add(self.custom_permission) for permission in [self.default_permission, self.custom_permission]: - self.assertTrue(user.has_perm('auth_tests.' + permission.codename)) + self.assertTrue(user.has_perm("auth_tests." + permission.codename)) with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) # Reload user to purge the _perm_cache. user = User._default_manager.get(pk=user.pk) for permission in [self.default_permission, self.custom_permission]: - self.assertTrue(user.has_perm('auth_tests.' + permission.codename)) + self.assertTrue(user.has_perm("auth_tests." + permission.codename)) def test_migrate_backwards(self): with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) update_proxy_permissions.revert_proxy_model_permissions(apps, editor) self.default_permission.refresh_from_db() - self.assertEqual(self.default_permission.content_type, self.concrete_content_type) + self.assertEqual( + self.default_permission.content_type, self.concrete_content_type + ) self.custom_permission.refresh_from_db() - self.assertEqual(self.custom_permission.content_type, self.concrete_content_type) + self.assertEqual( + self.custom_permission.content_type, self.concrete_content_type + ) def test_user_keeps_same_permissions_after_migrating_backward(self): user = User.objects.create() user.user_permissions.add(self.default_permission) user.user_permissions.add(self.custom_permission) for permission in [self.default_permission, self.custom_permission]: - self.assertTrue(user.has_perm('auth_tests.' + permission.codename)) + self.assertTrue(user.has_perm("auth_tests." + permission.codename)) with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) update_proxy_permissions.revert_proxy_model_permissions(apps, editor) # Reload user to purge the _perm_cache. user = User._default_manager.get(pk=user.pk) for permission in [self.default_permission, self.custom_permission]: - self.assertTrue(user.has_perm('auth_tests.' + permission.codename)) + self.assertTrue(user.has_perm("auth_tests." + permission.codename)) def test_migrate_with_existing_target_permission(self): """ @@ -172,48 +194,52 @@ class ProxyModelWithSameAppLabelTests(TransactionTestCase): Output a reminder to audit relevant permissions. """ - proxy_model_content_type = ContentType.objects.get_for_model(Proxy, for_concrete_model=False) + proxy_model_content_type = ContentType.objects.get_for_model( + Proxy, for_concrete_model=False + ) Permission.objects.create( content_type=proxy_model_content_type, - codename='add_proxy', - name='Can add proxy', + codename="add_proxy", + name="Can add proxy", ) Permission.objects.create( content_type=proxy_model_content_type, - codename='display_proxys', - name='May display proxys information', + codename="display_proxys", + name="May display proxys information", ) with captured_stdout() as stdout: with connection.schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) - self.assertIn('A problem arose migrating proxy model permissions', stdout.getvalue()) + self.assertIn( + "A problem arose migrating proxy model permissions", stdout.getvalue() + ) class MultiDBProxyModelAppLabelTests(TransactionTestCase): - databases = {'default', 'other'} + databases = {"default", "other"} available_apps = [ - 'auth_tests', - 'django.contrib.auth', - 'django.contrib.contenttypes', + "auth_tests", + "django.contrib.auth", + "django.contrib.contenttypes", ] def setUp(self): ContentType.objects.all().delete() - Permission.objects.using('other').delete() - concrete_content_type = ContentType.objects.db_manager( - 'other' - ).get_for_model(Proxy) - self.permission = Permission.objects.using('other').create( + Permission.objects.using("other").delete() + concrete_content_type = ContentType.objects.db_manager("other").get_for_model( + Proxy + ) + self.permission = Permission.objects.using("other").create( content_type=concrete_content_type, - codename='add_proxy', - name='Can add proxy', + codename="add_proxy", + name="Can add proxy", ) def test_migrate_other_database(self): proxy_model_content_type = ContentType.objects.db_manager( - 'other' + "other" ).get_for_model(Proxy, for_concrete_model=False) - with connections['other'].schema_editor() as editor: + with connections["other"].schema_editor() as editor: update_proxy_permissions.update_proxy_model_permissions(apps, editor) self.permission.refresh_from_db() self.assertEqual(self.permission.content_type, proxy_model_content_type) diff --git a/tests/auth_tests/test_mixins.py b/tests/auth_tests/test_mixins.py index 4f396fc208..fc92175f38 100644 --- a/tests/auth_tests/test_mixins.py +++ b/tests/auth_tests/test_mixins.py @@ -2,7 +2,9 @@ from unittest import mock from django.contrib.auth import models from django.contrib.auth.mixins import ( - LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin, + LoginRequiredMixin, + PermissionRequiredMixin, + UserPassesTestMixin, ) from django.contrib.auth.models import AnonymousUser from django.core.exceptions import PermissionDenied @@ -12,13 +14,11 @@ from django.views.generic import View class AlwaysTrueMixin(UserPassesTestMixin): - def test_func(self): return True class AlwaysFalseMixin(UserPassesTestMixin): - def test_func(self): return False @@ -36,13 +36,17 @@ class AlwaysFalseView(AlwaysFalseMixin, EmptyResponseView): pass -class StackedMixinsView1(LoginRequiredMixin, PermissionRequiredMixin, EmptyResponseView): - permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser'] +class StackedMixinsView1( + LoginRequiredMixin, PermissionRequiredMixin, EmptyResponseView +): + permission_required = ["auth_tests.add_customuser", "auth_tests.change_customuser"] raise_exception = True -class StackedMixinsView2(PermissionRequiredMixin, LoginRequiredMixin, EmptyResponseView): - permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser'] +class StackedMixinsView2( + PermissionRequiredMixin, LoginRequiredMixin, EmptyResponseView +): + permission_required = ["auth_tests.add_customuser", "auth_tests.change_customuser"] raise_exception = True @@ -51,10 +55,12 @@ class AccessMixinTests(TestCase): factory = RequestFactory() def test_stacked_mixins_success(self): - user = models.User.objects.create(username='joe', password='qwerty') - perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser')) + user = models.User.objects.create(username="joe", password="qwerty") + perms = models.Permission.objects.filter( + codename__in=("add_customuser", "change_customuser") + ) user.user_permissions.add(*perms) - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = user view = StackedMixinsView1.as_view() @@ -66,10 +72,10 @@ class AccessMixinTests(TestCase): self.assertEqual(response.status_code, 200) def test_stacked_mixins_missing_permission(self): - user = models.User.objects.create(username='joe', password='qwerty') - perms = models.Permission.objects.filter(codename__in=('add_customuser',)) + user = models.User.objects.create(username="joe", password="qwerty") + perms = models.Permission.objects.filter(codename__in=("add_customuser",)) user.user_permissions.add(*perms) - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = user view = StackedMixinsView1.as_view() @@ -81,9 +87,9 @@ class AccessMixinTests(TestCase): view(request) def test_access_mixin_permission_denied_response(self): - user = models.User.objects.create(username='joe', password='qwerty') + user = models.User.objects.create(username="joe", password="qwerty") # Authenticated users receive PermissionDenied. - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = user view = AlwaysFalseView.as_view() with self.assertRaises(PermissionDenied): @@ -92,28 +98,30 @@ class AccessMixinTests(TestCase): request.user = AnonymousUser() response = view(request) self.assertEqual(response.status_code, 302) - self.assertEqual(response.url, '/accounts/login/?next=/rand') + self.assertEqual(response.url, "/accounts/login/?next=/rand") def test_access_mixin_permission_denied_remote_login_url(self): class AView(AlwaysFalseView): - login_url = 'https://www.remote.example.com/login' + login_url = "https://www.remote.example.com/login" view = AView.as_view() - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = AnonymousUser() response = view(request) self.assertEqual(response.status_code, 302) self.assertEqual( response.url, - 'https://www.remote.example.com/login?next=http%3A//testserver/rand', + "https://www.remote.example.com/login?next=http%3A//testserver/rand", ) - @mock.patch.object(models.User, 'is_authenticated', False) + @mock.patch.object(models.User, "is_authenticated", False) def test_stacked_mixins_not_logged_in(self): - user = models.User.objects.create(username='joe', password='qwerty') - perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser')) + user = models.User.objects.create(username="joe", password="qwerty") + perms = models.Permission.objects.filter( + codename__in=("add_customuser", "change_customuser") + ) user.user_permissions.add(*perms) - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = user view = StackedMixinsView1.as_view() @@ -129,10 +137,10 @@ class UserPassesTestTests(SimpleTestCase): factory = RequestFactory() - def _test_redirect(self, view=None, url='/accounts/login/?next=/rand'): + def _test_redirect(self, view=None, url="/accounts/login/?next=/rand"): if not view: view = AlwaysFalseView.as_view() - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = AnonymousUser() response = view(request) self.assertEqual(response.status_code, 302) @@ -143,27 +151,27 @@ class UserPassesTestTests(SimpleTestCase): def test_custom_redirect_url(self): class AView(AlwaysFalseView): - login_url = '/login/' + login_url = "/login/" - self._test_redirect(AView.as_view(), '/login/?next=/rand') + self._test_redirect(AView.as_view(), "/login/?next=/rand") def test_custom_redirect_parameter(self): class AView(AlwaysFalseView): - redirect_field_name = 'goto' + redirect_field_name = "goto" - self._test_redirect(AView.as_view(), '/accounts/login/?goto=/rand') + self._test_redirect(AView.as_view(), "/accounts/login/?goto=/rand") def test_no_redirect_parameter(self): class AView(AlwaysFalseView): redirect_field_name = None - self._test_redirect(AView.as_view(), '/accounts/login/') + self._test_redirect(AView.as_view(), "/accounts/login/") def test_raise_exception(self): class AView(AlwaysFalseView): raise_exception = True - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = AnonymousUser() with self.assertRaises(PermissionDenied): AView.as_view()(request) @@ -175,7 +183,7 @@ class UserPassesTestTests(SimpleTestCase): raise_exception = True permission_denied_message = msg - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = AnonymousUser() view = AView.as_view() with self.assertRaisesMessage(PermissionDenied, msg): @@ -190,7 +198,7 @@ class UserPassesTestTests(SimpleTestCase): def get_permission_denied_message(self): return msg - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = AnonymousUser() view = AView.as_view() with self.assertRaisesMessage(PermissionDenied, msg): @@ -198,7 +206,7 @@ class UserPassesTestTests(SimpleTestCase): def test_user_passes(self): view = AlwaysTrueView.as_view() - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = AnonymousUser() response = view(request) self.assertEqual(response.status_code, 200) @@ -210,24 +218,25 @@ class LoginRequiredMixinTests(TestCase): @classmethod def setUpTestData(cls): - cls.user = models.User.objects.create(username='joe', password='qwerty') + cls.user = models.User.objects.create(username="joe", password="qwerty") def test_login_required(self): """ login_required works on a simple view wrapped in a login_required decorator. """ + class AView(LoginRequiredMixin, EmptyResponseView): pass view = AView.as_view() - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = AnonymousUser() response = view(request) self.assertEqual(response.status_code, 302) - self.assertEqual('/accounts/login/?next=/rand', response.url) - request = self.factory.get('/rand') + self.assertEqual("/accounts/login/?next=/rand", response.url) + request = self.factory.get("/rand") request.user = self.user response = view(request) self.assertEqual(response.status_code, 200) @@ -239,24 +248,29 @@ class PermissionsRequiredMixinTests(TestCase): @classmethod def setUpTestData(cls): - cls.user = models.User.objects.create(username='joe', password='qwerty') - perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser')) + cls.user = models.User.objects.create(username="joe", password="qwerty") + perms = models.Permission.objects.filter( + codename__in=("add_customuser", "change_customuser") + ) cls.user.user_permissions.add(*perms) def test_many_permissions_pass(self): class AView(PermissionRequiredMixin, EmptyResponseView): - permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser'] + permission_required = [ + "auth_tests.add_customuser", + "auth_tests.change_customuser", + ] - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = self.user resp = AView.as_view()(request) self.assertEqual(resp.status_code, 200) def test_single_permission_pass(self): class AView(PermissionRequiredMixin, EmptyResponseView): - permission_required = 'auth_tests.add_customuser' + permission_required = "auth_tests.add_customuser" - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = self.user resp = AView.as_view()(request) self.assertEqual(resp.status_code, 200) @@ -264,11 +278,13 @@ class PermissionsRequiredMixinTests(TestCase): def test_permissioned_denied_redirect(self): class AView(PermissionRequiredMixin, EmptyResponseView): permission_required = [ - 'auth_tests.add_customuser', 'auth_tests.change_customuser', 'nonexistent-permission', + "auth_tests.add_customuser", + "auth_tests.change_customuser", + "nonexistent-permission", ] # Authenticated users receive PermissionDenied. - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = self.user with self.assertRaises(PermissionDenied): AView.as_view()(request) @@ -280,11 +296,13 @@ class PermissionsRequiredMixinTests(TestCase): def test_permissioned_denied_exception_raised(self): class AView(PermissionRequiredMixin, EmptyResponseView): permission_required = [ - 'auth_tests.add_customuser', 'auth_tests.change_customuser', 'nonexistent-permission', + "auth_tests.add_customuser", + "auth_tests.change_customuser", + "nonexistent-permission", ] raise_exception = True - request = self.factory.get('/rand') + request = self.factory.get("/rand") request.user = self.user with self.assertRaises(PermissionDenied): AView.as_view()(request) diff --git a/tests/auth_tests/test_models.py b/tests/auth_tests/test_models.py index 01f523fdf2..f3fe553c66 100644 --- a/tests/auth_tests/test_models.py +++ b/tests/auth_tests/test_models.py @@ -6,73 +6,74 @@ 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, + 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 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',)) + 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",)) def test_group_natural_key(self): - users_group = Group.objects.create(name='users') - self.assertEqual(Group.objects.get_by_natural_key('users'), users_group) + users_group = Group.objects.create(name="users") + self.assertEqual(Group.objects.get_by_natural_key("users"), users_group) class LoadDataWithoutNaturalKeysTestCase(TestCase): - fixtures = ['regular.json'] + 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') + 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'] + 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') + 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'} + 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="examplemodela", + app_label="app_a", ), - ContentType.objects.db_manager('default').create( - model='examplemodelb', - app_label='app_b', + 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="examplemodelb", + app_label="app_b", ), - ContentType.objects.db_manager('other').create( - model='examplemodela', - app_label='app_a', + ContentType.objects.db_manager("other").create( + model="examplemodela", + app_label="app_a", ), ] @@ -89,15 +90,15 @@ class LoadDataWithNaturalKeysAndMultipleDatabasesTestCase(TestCase): ) perm_default = Permission.objects.get_by_natural_key( - 'delete_examplemodelb', - 'app_b', - 'examplemodelb', + "delete_examplemodelb", + "app_b", + "examplemodelb", ) - perm_other = Permission.objects.db_manager('other').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) @@ -106,59 +107,65 @@ class LoadDataWithNaturalKeysAndMultipleDatabasesTestCase(TestCase): class UserManagerTestCase(TransactionTestCase): available_apps = [ - 'auth_tests', - 'django.contrib.auth', - 'django.contrib.contenttypes', + "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) + 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.assertEqual(user.username, "user") self.assertFalse(user.has_usable_password()) def test_create_user_email_domain_normalize_rfc3696(self): # According to https://tools.ietf.org/html/rfc3696#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') + 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') + 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') + 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='') + 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) + 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.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.'): + 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, + 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.'): + 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, + username="test", + email="test@test.com", + password="test", + is_staff=False, ) def test_make_random_password(self): - allowed_chars = 'abcdefg' + allowed_chars = "abcdefg" password = UserManager().make_random_password(5, allowed_chars) self.assertEqual(len(password), 5) for char in password: @@ -166,8 +173,8 @@ class UserManagerTestCase(TransactionTestCase): 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') + 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) @@ -178,47 +185,48 @@ class UserManagerTestCase(TransactionTestCase): 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.state_forwards("test_manager_methods", new_state) operation.database_forwards( - 'test_manager_methods', + "test_manager_methods", editor, project_state, new_state, ) - user = User.objects.get(username='user1') - self.assertTrue(user.check_password('secure')) + 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) + 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'): + 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 = 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 + self.assertEqual( + username, "iamtheΩ" + ) # U+03A9 GREEK CAPITAL LETTER OMEGA def test_default_email(self): - self.assertEqual(AbstractBaseUser.get_email_field_name(), 'email') + self.assertEqual(AbstractBaseUser.get_email_field_name(), "email") def test_custom_email(self): user = CustomEmailField() - self.assertEqual(user.get_email_field_name(), 'email_address') + self.assertEqual(user.get_email_field_name(), "email_address") class AbstractUserTestCase(TestCase): @@ -231,12 +239,12 @@ class AbstractUserTestCase(TestCase): "connection": None, "html_message": None, } - user = User(email='foo@bar.com') + user = User(email="foo@bar.com") user.email_user( subject="Subject here", message="This is a message", from_email="from@domain.com", - **kwargs + **kwargs, ) self.assertEqual(len(mail.outbox), 1) message = mail.outbox[0] @@ -246,24 +254,26 @@ class AbstractUserTestCase(TestCase): self.assertEqual(message.to, [user.email]) def test_last_login_default(self): - user1 = User.objects.create(username='user1') + user1 = User.objects.create(username="user1") self.assertIsNone(user1.last_login) - user2 = User.objects.create_user(username='user2') + 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 = User(username="user", password="foo", email="foo@BAR.com") user.clean() - self.assertEqual(user.email, 'foo@bar.com') + 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 = 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() @@ -275,18 +285,20 @@ class AbstractUserTestCase(TestCase): password_changed() shouldn't be called if User.check_password() triggers a hash iteration upgrade. """ - user = User.objects.create_user(username='user', password='foo') + 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) + 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') + 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: @@ -294,137 +306,154 @@ class AbstractUserTestCase(TestCase): 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': + 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') + 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', + 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.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 = Group.objects.create(name="group 1") group1.permissions.add(cls.permission) - group2 = Group.objects.create(name='group 2') + 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 = 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') + 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', + "superuser", + "superuser@example.com", + "superpassword", ) # Inactive user with permission. cls.inactive_user = User.objects.create_user( - 'inactive_user', 'baz@example.com', is_active=False, + "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', '...', ''): + 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): + 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()): + 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) + 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}, []), + ({"obj": self.user1}, []), # Only inactive users. - ({'is_active': False}, [self.inactive_user]), + ({"is_active": False}, [self.inactive_user]), # All users. - ({'is_active': None}, [*active_users, self.superuser, self.inactive_user]), + ({"is_active": None}, [*active_users, self.superuser, self.inactive_user]), # Exclude superusers. - ({'include_superusers': False}, active_users), + ({"include_superusers": False}, active_users), ( - {'include_superusers': False, 'is_active': False}, + {"include_superusers": False, "is_active": False}, [self.inactive_user], ), ( - {'include_superusers': False, 'is_active': None}, + {"include_superusers": False, "is_active": None}, [*active_users, self.inactive_user], ), ] for kwargs, expected_users in tests: - for perm in ('auth.test', self.permission): + 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']) + @override_settings( + AUTHENTICATION_BACKENDS=["django.contrib.auth.backends.BaseBackend"] + ) def test_backend_without_with_perm(self): - self.assertSequenceEqual(User.objects.with_perm('auth.test'), []) + self.assertSequenceEqual(User.objects.with_perm("auth.test"), []) def test_nonexistent_permission(self): - self.assertSequenceEqual(User.objects.with_perm('auth.perm'), [self.superuser]) + 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', + "auth.test", + backend="invalid.backend.CustomModelBackend", ) - @override_settings(AUTHENTICATION_BACKENDS=['auth_tests.test_models.CustomModelBackend']) + @override_settings( + AUTHENTICATION_BACKENDS=["auth_tests.test_models.CustomModelBackend"] + ) def test_custom_backend(self): - for perm in ('auth.test', self.permission): + 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']) + @override_settings( + AUTHENTICATION_BACKENDS=["auth_tests.test_models.CustomModelBackend"] + ) def test_custom_backend_pass_obj(self): - for perm in ('auth.test', self.permission): + 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', - ]) + @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.' + "You have multiple authentication backends configured and " + "therefore must provide the `backend` argument." ) with self.assertRaisesMessage(ValueError, msg): - User.objects.with_perm('auth.test') + User.objects.with_perm("auth.test") - backend = 'auth_tests.test_models.CustomModelBackend' + backend = "auth_tests.test_models.CustomModelBackend" self.assertCountEqual( - User.objects.with_perm('auth.test', backend=backend), + User.objects.with_perm("auth.test", backend=backend), [self.user_charlie, self.user_charlie_b], ) @@ -435,7 +464,7 @@ class IsActiveTestCase(TestCase): """ def test_builtin_user_isactive(self): - user = User.objects.create(username='foo', email='foo@bar.com') + 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 @@ -444,13 +473,13 @@ class IsActiveTestCase(TestCase): # the is_active flag is saved self.assertFalse(user_fetched.is_active) - @override_settings(AUTH_USER_MODEL='auth_tests.IsActiveTestUser1') + @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') + user = UserModel(username="foo") self.assertIs(user.is_active, True) # you can set the attribute - but it will not save user.is_active = False @@ -465,6 +494,7 @@ class TestCreateSuperUserSignals(TestCase): """ Simple test case for ticket #20541 """ + def post_save_listener(self, *args, **kwargs): self.signals_count += 1 @@ -492,8 +522,8 @@ class AnonymousUserTests(SimpleTestCase): def test_properties(self): self.assertIsNone(self.user.pk) - self.assertEqual(self.user.username, '') - self.assertEqual(self.user.get_username(), '') + 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) @@ -505,19 +535,19 @@ class AnonymousUserTests(SimpleTestCase): self.assertEqual(self.user.get_group_permissions(), set()) def test_str(self): - self.assertEqual(str(self.user), 'AnonymousUser') + 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')) + 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?' + "Cannot cast AnonymousUser to int. Are you trying to use it in " + "place of User?" ) with self.assertRaisesMessage(TypeError, msg): int(self.user) @@ -532,20 +562,22 @@ class AnonymousUserTests(SimpleTestCase): def test_set_password(self): with self.assertRaisesMessage(NotImplementedError, self.no_repr_msg): - self.user.set_password('password') + self.user.set_password("password") def test_check_password(self): with self.assertRaisesMessage(NotImplementedError, self.no_repr_msg): - self.user.check_password('password') + self.user.check_password("password") class GroupTests(SimpleTestCase): def test_str(self): - g = Group(name='Users') - self.assertEqual(str(g), 'Users') + 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') + p = Permission.objects.get(codename="view_customemailfield") + self.assertEqual( + str(p), "auth_tests | custom email field | Can view custom email field" + ) diff --git a/tests/auth_tests/test_remote_user.py b/tests/auth_tests/test_remote_user.py index 3756f557a2..bd974cb1d5 100644 --- a/tests/auth_tests/test_remote_user.py +++ b/tests/auth_tests/test_remote_user.py @@ -10,22 +10,22 @@ from django.test import Client, TestCase, modify_settings, override_settings from django.utils import timezone -@override_settings(ROOT_URLCONF='auth_tests.urls') +@override_settings(ROOT_URLCONF="auth_tests.urls") class RemoteUserTest(TestCase): - middleware = 'django.contrib.auth.middleware.RemoteUserMiddleware' - backend = 'django.contrib.auth.backends.RemoteUserBackend' - header = 'REMOTE_USER' - email_header = 'REMOTE_EMAIL' + middleware = "django.contrib.auth.middleware.RemoteUserMiddleware" + backend = "django.contrib.auth.backends.RemoteUserBackend" + header = "REMOTE_USER" + email_header = "REMOTE_EMAIL" # Usernames to be passed in REMOTE_USER for the test_known_user test case. - known_user = 'knownuser' - known_user2 = 'knownuser2' + known_user = "knownuser" + known_user2 = "knownuser2" def setUp(self): self.patched_settings = modify_settings( - AUTHENTICATION_BACKENDS={'append': self.backend}, - MIDDLEWARE={'append': self.middleware}, + AUTHENTICATION_BACKENDS={"append": self.backend}, + MIDDLEWARE={"append": self.middleware}, ) self.patched_settings.enable() @@ -36,16 +36,16 @@ class RemoteUserTest(TestCase): """Users are not created when remote user is not specified.""" num_users = User.objects.count() - response = self.client.get('/remote_user/') - self.assertTrue(response.context['user'].is_anonymous) + response = self.client.get("/remote_user/") + self.assertTrue(response.context["user"].is_anonymous) self.assertEqual(User.objects.count(), num_users) - response = self.client.get('/remote_user/', **{self.header: None}) - self.assertTrue(response.context['user'].is_anonymous) + response = self.client.get("/remote_user/", **{self.header: None}) + self.assertTrue(response.context["user"].is_anonymous) self.assertEqual(User.objects.count(), num_users) - response = self.client.get('/remote_user/', **{self.header: ''}) - self.assertTrue(response.context['user'].is_anonymous) + response = self.client.get("/remote_user/", **{self.header: ""}) + self.assertTrue(response.context["user"].is_anonymous) self.assertEqual(User.objects.count(), num_users) def test_csrf_validation_passes_after_process_request_login(self): @@ -58,14 +58,14 @@ class RemoteUserTest(TestCase): csrf_secret = _get_new_csrf_string() csrf_token = _mask_cipher_secret(csrf_secret) csrf_token_form = _mask_cipher_secret(csrf_secret) - headers = {self.header: 'fakeuser'} - data = {'csrfmiddlewaretoken': csrf_token_form} + headers = {self.header: "fakeuser"} + data = {"csrfmiddlewaretoken": csrf_token_form} # Verify that CSRF is configured for the view csrf_client.cookies.load({settings.CSRF_COOKIE_NAME: csrf_token}) - response = csrf_client.post('/remote_user/', **headers) + response = csrf_client.post("/remote_user/", **headers) self.assertEqual(response.status_code, 403) - self.assertIn(b'CSRF verification failed.', response.content) + self.assertIn(b"CSRF verification failed.", response.content) # This request will call django.contrib.auth.login() which will call # django.middleware.csrf.rotate_token() thus changing the value of @@ -74,7 +74,7 @@ class RemoteUserTest(TestCase): # by rotate_token(). Csrf validation should still pass when the view is # later processed by CsrfViewMiddleware.process_view() csrf_client.cookies.load({settings.CSRF_COOKIE_NAME: csrf_token}) - response = csrf_client.post('/remote_user/', data, **headers) + response = csrf_client.post("/remote_user/", data, **headers) self.assertEqual(response.status_code, 200) def test_unknown_user(self): @@ -83,31 +83,29 @@ class RemoteUserTest(TestCase): as a User. """ num_users = User.objects.count() - response = self.client.get('/remote_user/', **{self.header: 'newuser'}) - self.assertEqual(response.context['user'].username, 'newuser') + response = self.client.get("/remote_user/", **{self.header: "newuser"}) + self.assertEqual(response.context["user"].username, "newuser") self.assertEqual(User.objects.count(), num_users + 1) - User.objects.get(username='newuser') + User.objects.get(username="newuser") # Another request with same user should not create any new users. - response = self.client.get('/remote_user/', **{self.header: 'newuser'}) + response = self.client.get("/remote_user/", **{self.header: "newuser"}) self.assertEqual(User.objects.count(), num_users + 1) def test_known_user(self): """ Tests the case where the username passed in the header is a valid User. """ - User.objects.create(username='knownuser') - User.objects.create(username='knownuser2') + User.objects.create(username="knownuser") + User.objects.create(username="knownuser2") num_users = User.objects.count() - response = self.client.get('/remote_user/', - **{self.header: self.known_user}) - self.assertEqual(response.context['user'].username, 'knownuser') + response = self.client.get("/remote_user/", **{self.header: self.known_user}) + self.assertEqual(response.context["user"].username, "knownuser") self.assertEqual(User.objects.count(), num_users) # A different user passed in the headers causes the new user # to be logged in. - response = self.client.get('/remote_user/', - **{self.header: self.known_user2}) - self.assertEqual(response.context['user'].username, 'knownuser2') + response = self.client.get("/remote_user/", **{self.header: self.known_user2}) + self.assertEqual(response.context["user"].username, "knownuser2") self.assertEqual(User.objects.count(), num_users) def test_last_login(self): @@ -115,7 +113,7 @@ class RemoteUserTest(TestCase): A user's last_login is set the first time they make a request but not updated in subsequent requests with the same session. """ - user = User.objects.create(username='knownuser') + user = User.objects.create(username="knownuser") # Set last_login to something so we can determine if it changes. default_login = datetime(2000, 1, 1) if settings.USE_TZ: @@ -123,64 +121,60 @@ class RemoteUserTest(TestCase): user.last_login = default_login user.save() - response = self.client.get('/remote_user/', - **{self.header: self.known_user}) - self.assertNotEqual(default_login, response.context['user'].last_login) + response = self.client.get("/remote_user/", **{self.header: self.known_user}) + self.assertNotEqual(default_login, response.context["user"].last_login) - user = User.objects.get(username='knownuser') + user = User.objects.get(username="knownuser") user.last_login = default_login user.save() - response = self.client.get('/remote_user/', - **{self.header: self.known_user}) - self.assertEqual(default_login, response.context['user'].last_login) + response = self.client.get("/remote_user/", **{self.header: self.known_user}) + self.assertEqual(default_login, response.context["user"].last_login) def test_header_disappears(self): """ A logged in user is logged out automatically when the REMOTE_USER header disappears during the same browser session. """ - User.objects.create(username='knownuser') + User.objects.create(username="knownuser") # Known user authenticates - response = self.client.get('/remote_user/', - **{self.header: self.known_user}) - self.assertEqual(response.context['user'].username, 'knownuser') + response = self.client.get("/remote_user/", **{self.header: self.known_user}) + self.assertEqual(response.context["user"].username, "knownuser") # During the session, the REMOTE_USER header disappears. Should trigger logout. - response = self.client.get('/remote_user/') - self.assertTrue(response.context['user'].is_anonymous) + response = self.client.get("/remote_user/") + self.assertTrue(response.context["user"].is_anonymous) # verify the remoteuser middleware will not remove a user # authenticated via another backend - User.objects.create_user(username='modeluser', password='foo') - self.client.login(username='modeluser', password='foo') - authenticate(username='modeluser', password='foo') - response = self.client.get('/remote_user/') - self.assertEqual(response.context['user'].username, 'modeluser') + User.objects.create_user(username="modeluser", password="foo") + self.client.login(username="modeluser", password="foo") + authenticate(username="modeluser", password="foo") + response = self.client.get("/remote_user/") + self.assertEqual(response.context["user"].username, "modeluser") def test_user_switch_forces_new_login(self): """ If the username in the header changes between requests that the original user is logged out """ - User.objects.create(username='knownuser') + User.objects.create(username="knownuser") # Known user authenticates - response = self.client.get('/remote_user/', - **{self.header: self.known_user}) - self.assertEqual(response.context['user'].username, 'knownuser') + response = self.client.get("/remote_user/", **{self.header: self.known_user}) + self.assertEqual(response.context["user"].username, "knownuser") # During the session, the REMOTE_USER changes to a different user. - response = self.client.get('/remote_user/', - **{self.header: "newnewuser"}) + response = self.client.get("/remote_user/", **{self.header: "newnewuser"}) # The current user is not the prior remote_user. # In backends that create a new user, username is "newnewuser" # In backends that do not create new users, it is '' (anonymous user) - self.assertNotEqual(response.context['user'].username, 'knownuser') + self.assertNotEqual(response.context["user"].username, "knownuser") def test_inactive_user(self): - User.objects.create(username='knownuser', is_active=False) - response = self.client.get('/remote_user/', **{self.header: 'knownuser'}) - self.assertTrue(response.context['user'].is_anonymous) + User.objects.create(username="knownuser", is_active=False) + response = self.client.get("/remote_user/", **{self.header: "knownuser"}) + self.assertTrue(response.context["user"].is_anonymous) class RemoteUserNoCreateBackend(RemoteUserBackend): """Backend that doesn't create unknown users.""" + create_unknown_user = False @@ -190,23 +184,24 @@ class RemoteUserNoCreateTest(RemoteUserTest): class that doesn't create unknown users. """ - backend = 'auth_tests.test_remote_user.RemoteUserNoCreateBackend' + backend = "auth_tests.test_remote_user.RemoteUserNoCreateBackend" def test_unknown_user(self): num_users = User.objects.count() - response = self.client.get('/remote_user/', **{self.header: 'newuser'}) - self.assertTrue(response.context['user'].is_anonymous) + response = self.client.get("/remote_user/", **{self.header: "newuser"}) + self.assertTrue(response.context["user"].is_anonymous) self.assertEqual(User.objects.count(), num_users) class AllowAllUsersRemoteUserBackendTest(RemoteUserTest): """Backend that allows inactive users.""" - backend = 'django.contrib.auth.backends.AllowAllUsersRemoteUserBackend' + + backend = "django.contrib.auth.backends.AllowAllUsersRemoteUserBackend" def test_inactive_user(self): - user = User.objects.create(username='knownuser', is_active=False) - response = self.client.get('/remote_user/', **{self.header: self.known_user}) - self.assertEqual(response.context['user'].username, user.username) + user = User.objects.create(username="knownuser", is_active=False) + response = self.client.get("/remote_user/", **{self.header: self.known_user}) + self.assertEqual(response.context["user"].username, user.username) class CustomRemoteUserBackend(RemoteUserBackend): @@ -218,13 +213,13 @@ class CustomRemoteUserBackend(RemoteUserBackend): """ Grabs username before the @ character. """ - return username.split('@')[0] + return username.split("@")[0] def configure_user(self, request, user): """ Sets user's email address using the email specified in an HTTP header. """ - user.email = request.META.get(RemoteUserTest.email_header, '') + user.email = request.META.get(RemoteUserTest.email_header, "") user.save() return user @@ -235,11 +230,11 @@ class RemoteUserCustomTest(RemoteUserTest): and configure_user methods. """ - backend = 'auth_tests.test_remote_user.CustomRemoteUserBackend' + backend = "auth_tests.test_remote_user.CustomRemoteUserBackend" # REMOTE_USER strings with email addresses for the custom backend to # clean. - known_user = 'knownuser@example.com' - known_user2 = 'knownuser2@example.com' + known_user = "knownuser@example.com" + known_user2 = "knownuser2@example.com" def test_known_user(self): """ @@ -247,8 +242,8 @@ class RemoteUserCustomTest(RemoteUserTest): should not have been configured with an email address. """ super().test_known_user() - self.assertEqual(User.objects.get(username='knownuser').email, '') - self.assertEqual(User.objects.get(username='knownuser2').email, '') + self.assertEqual(User.objects.get(username="knownuser").email, "") + self.assertEqual(User.objects.get(username="knownuser2").email, "") def test_unknown_user(self): """ @@ -256,22 +251,26 @@ class RemoteUserCustomTest(RemoteUserTest): provided in the request header. """ num_users = User.objects.count() - response = self.client.get('/remote_user/', **{ - self.header: 'newuser', - self.email_header: 'user@example.com', - }) - self.assertEqual(response.context['user'].username, 'newuser') - self.assertEqual(response.context['user'].email, 'user@example.com') + response = self.client.get( + "/remote_user/", + **{ + self.header: "newuser", + self.email_header: "user@example.com", + }, + ) + self.assertEqual(response.context["user"].username, "newuser") + self.assertEqual(response.context["user"].email, "user@example.com") self.assertEqual(User.objects.count(), num_users + 1) - newuser = User.objects.get(username='newuser') - self.assertEqual(newuser.email, 'user@example.com') + newuser = User.objects.get(username="newuser") + self.assertEqual(newuser.email, "user@example.com") class CustomHeaderMiddleware(RemoteUserMiddleware): """ Middleware that overrides custom HTTP auth user header. """ - header = 'HTTP_AUTHUSER' + + header = "HTTP_AUTHUSER" class CustomHeaderRemoteUserTest(RemoteUserTest): @@ -279,10 +278,9 @@ class CustomHeaderRemoteUserTest(RemoteUserTest): Tests a custom RemoteUserMiddleware subclass with custom HTTP auth user header. """ - middleware = ( - 'auth_tests.test_remote_user.CustomHeaderMiddleware' - ) - header = 'HTTP_AUTHUSER' + + middleware = "auth_tests.test_remote_user.CustomHeaderMiddleware" + header = "HTTP_AUTHUSER" class PersistentRemoteUserTest(RemoteUserTest): @@ -290,7 +288,8 @@ class PersistentRemoteUserTest(RemoteUserTest): PersistentRemoteUserMiddleware keeps the user logged in even if the subsequent calls do not contain the header value. """ - middleware = 'django.contrib.auth.middleware.PersistentRemoteUserMiddleware' + + middleware = "django.contrib.auth.middleware.PersistentRemoteUserMiddleware" require_header = False def test_header_disappears(self): @@ -298,11 +297,11 @@ class PersistentRemoteUserTest(RemoteUserTest): A logged in user is kept logged in even if the REMOTE_USER header disappears during the same browser session. """ - User.objects.create(username='knownuser') + User.objects.create(username="knownuser") # Known user authenticates - response = self.client.get('/remote_user/', **{self.header: self.known_user}) - self.assertEqual(response.context['user'].username, 'knownuser') + response = self.client.get("/remote_user/", **{self.header: self.known_user}) + self.assertEqual(response.context["user"].username, "knownuser") # Should stay logged in if the REMOTE_USER header disappears. - response = self.client.get('/remote_user/') - self.assertFalse(response.context['user'].is_anonymous) - self.assertEqual(response.context['user'].username, 'knownuser') + response = self.client.get("/remote_user/") + self.assertFalse(response.context["user"].is_anonymous) + self.assertEqual(response.context["user"].username, "knownuser") diff --git a/tests/auth_tests/test_signals.py b/tests/auth_tests/test_signals.py index 93b6c82366..a573fcb9dc 100644 --- a/tests/auth_tests/test_signals.py +++ b/tests/auth_tests/test_signals.py @@ -8,13 +8,12 @@ from django.test.client import RequestFactory from .models import MinimalUser, UserWithDisabledLastLoginField -@override_settings(ROOT_URLCONF='auth_tests.urls') +@override_settings(ROOT_URLCONF="auth_tests.urls") class SignalTestCase(TestCase): - @classmethod def setUpTestData(cls): - cls.u1 = User.objects.create_user(username='testclient', password='password') - cls.u3 = User.objects.create_user(username='staff', password='password') + cls.u1 = User.objects.create_user(username="testclient", password="password") + cls.u3 = User.objects.create_user(username="staff", password="password") def listener_login(self, user, **kwargs): self.logged_in.append(user) @@ -42,18 +41,18 @@ class SignalTestCase(TestCase): def test_login(self): # Only a successful login will trigger the success signal. - self.client.login(username='testclient', password='bad') + self.client.login(username="testclient", password="bad") self.assertEqual(len(self.logged_in), 0) self.assertEqual(len(self.login_failed), 1) - self.assertEqual(self.login_failed[0]['credentials']['username'], 'testclient') + self.assertEqual(self.login_failed[0]["credentials"]["username"], "testclient") # verify the password is cleansed - self.assertIn('***', self.login_failed[0]['credentials']['password']) - self.assertIn('request', self.login_failed[0]) + self.assertIn("***", self.login_failed[0]["credentials"]["password"]) + self.assertIn("request", self.login_failed[0]) # Like this: - self.client.login(username='testclient', password='password') + self.client.login(username="testclient", password="password") self.assertEqual(len(self.logged_in), 1) - self.assertEqual(self.logged_in[0].username, 'testclient') + self.assertEqual(self.logged_in[0].username, "testclient") # Ensure there were no more failures. self.assertEqual(len(self.login_failed), 1) @@ -61,15 +60,15 @@ class SignalTestCase(TestCase): def test_logout_anonymous(self): # The log_out function will still trigger the signal for anonymous # users. - self.client.get('/logout/next_page/') + self.client.get("/logout/next_page/") self.assertEqual(len(self.logged_out), 1) self.assertIsNone(self.logged_out[0]) def test_logout(self): - self.client.login(username='testclient', password='password') - self.client.get('/logout/next_page/') + self.client.login(username="testclient", password="password") + self.client.get("/logout/next_page/") self.assertEqual(len(self.logged_out), 1) - self.assertEqual(self.logged_out[0].username, 'testclient') + self.assertEqual(self.logged_out[0].username, "testclient") def test_update_last_login(self): """Only `last_login` is updated in `update_last_login`""" @@ -77,15 +76,15 @@ class SignalTestCase(TestCase): old_last_login = user.last_login user.username = "This username shouldn't get saved" - request = RequestFactory().get('/login') + request = RequestFactory().get("/login") signals.user_logged_in.send(sender=user.__class__, request=request, user=user) user = User.objects.get(pk=user.pk) - self.assertEqual(user.username, 'staff') + self.assertEqual(user.username, "staff") self.assertNotEqual(user.last_login, old_last_login) def test_failed_login_without_request(self): - authenticate(username='testclient', password='bad') - self.assertIsNone(self.login_failed[0]['request']) + authenticate(username="testclient", password="bad") + self.assertIsNone(self.login_failed[0]["request"]) def test_login_with_custom_user_without_last_login_field(self): """ @@ -96,19 +95,21 @@ class SignalTestCase(TestCase): try: signals.user_logged_in.receivers = [] with self.assertRaises(FieldDoesNotExist): - MinimalUser._meta.get_field('last_login') - with self.settings(AUTH_USER_MODEL='auth_tests.MinimalUser'): - apps.get_app_config('auth').ready() + MinimalUser._meta.get_field("last_login") + with self.settings(AUTH_USER_MODEL="auth_tests.MinimalUser"): + apps.get_app_config("auth").ready() self.assertEqual(signals.user_logged_in.receivers, []) # last_login is a property whose value is None. self.assertIsNone(UserWithDisabledLastLoginField().last_login) - with self.settings(AUTH_USER_MODEL='auth_tests.UserWithDisabledLastLoginField'): - apps.get_app_config('auth').ready() + with self.settings( + AUTH_USER_MODEL="auth_tests.UserWithDisabledLastLoginField" + ): + apps.get_app_config("auth").ready() self.assertEqual(signals.user_logged_in.receivers, []) - with self.settings(AUTH_USER_MODEL='auth.User'): - apps.get_app_config('auth').ready() + with self.settings(AUTH_USER_MODEL="auth.User"): + apps.get_app_config("auth").ready() self.assertEqual(len(signals.user_logged_in.receivers), 1) finally: signals.user_logged_in.receivers = last_login_receivers diff --git a/tests/auth_tests/test_templates.py b/tests/auth_tests/test_templates.py index 02f39a9cbf..ceecfa3325 100644 --- a/tests/auth_tests/test_templates.py +++ b/tests/auth_tests/test_templates.py @@ -4,8 +4,11 @@ from django.contrib.auth import authenticate from django.contrib.auth.models import User from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.contrib.auth.views import ( - PasswordChangeDoneView, PasswordChangeView, PasswordResetCompleteView, - PasswordResetDoneView, PasswordResetView, + PasswordChangeDoneView, + PasswordChangeView, + PasswordResetCompleteView, + PasswordResetDoneView, + PasswordResetView, ) from django.test import RequestFactory, TestCase, override_settings from django.urls import reverse @@ -15,35 +18,43 @@ from .client import PasswordResetConfirmClient from .models import CustomUser -@override_settings(ROOT_URLCONF='auth_tests.urls') +@override_settings(ROOT_URLCONF="auth_tests.urls") class AuthTemplateTests(TestCase): request_factory = RequestFactory() @classmethod def setUpTestData(cls): - user = User.objects.create_user('jsmith', 'jsmith@example.com', 'pass') - user = authenticate(username=user.username, password='pass') - request = cls.request_factory.get('/somepath/') + user = User.objects.create_user("jsmith", "jsmith@example.com", "pass") + user = authenticate(username=user.username, password="pass") + request = cls.request_factory.get("/somepath/") request.user = user cls.user, cls.request = user, request def test_password_reset_view(self): - response = PasswordResetView.as_view(success_url='dummy/')(self.request) - self.assertContains(response, '<title>Password reset | Django site admin</title>') - self.assertContains(response, '<h1>Password reset</h1>') + response = PasswordResetView.as_view(success_url="dummy/")(self.request) + self.assertContains( + response, "<title>Password reset | Django site admin</title>" + ) + self.assertContains(response, "<h1>Password reset</h1>") def test_password_reset_done_view(self): response = PasswordResetDoneView.as_view()(self.request) - self.assertContains(response, '<title>Password reset sent | Django site admin</title>') - self.assertContains(response, '<h1>Password reset sent</h1>') + self.assertContains( + response, "<title>Password reset sent | Django site admin</title>" + ) + self.assertContains(response, "<h1>Password reset sent</h1>") def test_password_reset_confirm_view_invalid_token(self): # PasswordResetConfirmView invalid token client = PasswordResetConfirmClient() - url = reverse('password_reset_confirm', kwargs={'uidb64': 'Bad', 'token': 'Bad-Token'}) + url = reverse( + "password_reset_confirm", kwargs={"uidb64": "Bad", "token": "Bad-Token"} + ) response = client.get(url) - self.assertContains(response, '<title>Password reset unsuccessful | Django site admin</title>') - self.assertContains(response, '<h1>Password reset unsuccessful</h1>') + self.assertContains( + response, "<title>Password reset unsuccessful | Django site admin</title>" + ) + self.assertContains(response, "<h1>Password reset unsuccessful</h1>") def test_password_reset_confirm_view_valid_token(self): # PasswordResetConfirmView valid token @@ -51,10 +62,14 @@ class AuthTemplateTests(TestCase): default_token_generator = PasswordResetTokenGenerator() token = default_token_generator.make_token(self.user) uidb64 = urlsafe_base64_encode(str(self.user.pk).encode()) - url = reverse('password_reset_confirm', kwargs={'uidb64': uidb64, 'token': token}) + url = reverse( + "password_reset_confirm", kwargs={"uidb64": uidb64, "token": token} + ) response = client.get(url) - self.assertContains(response, '<title>Enter new password | Django site admin</title>') - self.assertContains(response, '<h1>Enter new password</h1>') + self.assertContains( + response, "<title>Enter new password | Django site admin</title>" + ) + self.assertContains(response, "<h1>Enter new password</h1>") # The username is added to the password reset confirmation form to help # browser's password managers. self.assertContains( @@ -62,24 +77,26 @@ class AuthTemplateTests(TestCase): '<input class="hidden" autocomplete="username" value="jsmith">', ) - @override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') + @override_settings(AUTH_USER_MODEL="auth_tests.CustomUser") def test_password_reset_confirm_view_custom_username_hint(self): custom_user = CustomUser.custom_objects.create_user( - email='joe@example.com', + email="joe@example.com", date_of_birth=date(1986, 11, 11), - first_name='Joe', + first_name="Joe", ) client = PasswordResetConfirmClient() default_token_generator = PasswordResetTokenGenerator() token = default_token_generator.make_token(custom_user) uidb64 = urlsafe_base64_encode(str(custom_user.pk).encode()) - url = reverse('password_reset_confirm', kwargs={'uidb64': uidb64, 'token': token}) + url = reverse( + "password_reset_confirm", kwargs={"uidb64": uidb64, "token": token} + ) response = client.get(url) self.assertContains( response, - '<title>Enter new password | Django site admin</title>', + "<title>Enter new password | Django site admin</title>", ) - self.assertContains(response, '<h1>Enter new password</h1>') + self.assertContains(response, "<h1>Enter new password</h1>") # The username field is added to the password reset confirmation form # to help browser's password managers. self.assertContains( @@ -89,15 +106,21 @@ class AuthTemplateTests(TestCase): def test_password_reset_complete_view(self): response = PasswordResetCompleteView.as_view()(self.request) - self.assertContains(response, '<title>Password reset complete | Django site admin</title>') - self.assertContains(response, '<h1>Password reset complete</h1>') + self.assertContains( + response, "<title>Password reset complete | Django site admin</title>" + ) + self.assertContains(response, "<h1>Password reset complete</h1>") def test_password_reset_change_view(self): - response = PasswordChangeView.as_view(success_url='dummy/')(self.request) - self.assertContains(response, '<title>Password change | Django site admin</title>') - self.assertContains(response, '<h1>Password change</h1>') + response = PasswordChangeView.as_view(success_url="dummy/")(self.request) + self.assertContains( + response, "<title>Password change | Django site admin</title>" + ) + self.assertContains(response, "<h1>Password change</h1>") def test_password_change_done_view(self): response = PasswordChangeDoneView.as_view()(self.request) - self.assertContains(response, '<title>Password change successful | Django site admin</title>') - self.assertContains(response, '<h1>Password change successful</h1>') + self.assertContains( + response, "<title>Password change successful | Django site admin</title>" + ) + self.assertContains(response, "<h1>Password change successful</h1>") diff --git a/tests/auth_tests/test_tokens.py b/tests/auth_tests/test_tokens.py index 2f3f52aac6..fa82e642c5 100644 --- a/tests/auth_tests/test_tokens.py +++ b/tests/auth_tests/test_tokens.py @@ -20,9 +20,8 @@ class MockedPasswordResetTokenGenerator(PasswordResetTokenGenerator): class TokenGeneratorTest(TestCase): - def test_make_token(self): - user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') + user = User.objects.create_user("tokentestuser", "test2@example.com", "testpw") p0 = PasswordResetTokenGenerator() tk1 = p0.make_token(user) self.assertIs(p0.check_token(user, tk1), True) @@ -32,8 +31,8 @@ class TokenGeneratorTest(TestCase): The token generated for a user created in the same request will work correctly. """ - user = User.objects.create_user('comebackkid', 'test3@example.com', 'testpw') - user_reload = User.objects.get(username='comebackkid') + user = User.objects.create_user("comebackkid", "test3@example.com", "testpw") + user_reload = User.objects.get(username="comebackkid") p0 = MockedPasswordResetTokenGenerator(datetime.now()) tk1 = p0.make_token(user) tk2 = p0.make_token(user_reload) @@ -43,20 +42,20 @@ class TokenGeneratorTest(TestCase): """Updating the user email address invalidates the token.""" tests = [ (CustomEmailField, None), - (CustomEmailField, 'test4@example.com'), - (User, 'test4@example.com'), + (CustomEmailField, "test4@example.com"), + (User, "test4@example.com"), ] for model, email in tests: with self.subTest(model=model.__qualname__, email=email): user = model.objects.create_user( - 'changeemailuser', + "changeemailuser", email=email, - password='testpw', + password="testpw", ) p0 = PasswordResetTokenGenerator() tk1 = p0.make_token(user) self.assertIs(p0.check_token(user, tk1), True) - setattr(user, user.get_email_field_name(), 'test4new@example.com') + setattr(user, user.get_email_field_name(), "test4new@example.com") user.save() self.assertIs(p0.check_token(user, tk1), False) @@ -64,7 +63,7 @@ class TokenGeneratorTest(TestCase): """The token is valid after n seconds, but no greater.""" # Uses a mocked version of PasswordResetTokenGenerator so we can change # the value of 'now'. - user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') + user = User.objects.create_user("tokentestuser", "test2@example.com", "testpw") now = datetime.now() p0 = MockedPasswordResetTokenGenerator(now) tk1 = p0.make_token(user) @@ -87,7 +86,7 @@ class TokenGeneratorTest(TestCase): self.assertIs(p4.check_token(user, tk1), False) def test_check_token_with_nonexistent_token_and_user(self): - user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') + user = User.objects.create_user("tokentestuser", "test2@example.com", "testpw") p0 = PasswordResetTokenGenerator() tk1 = p0.make_token(user) self.assertIs(p0.check_token(None, tk1), False) @@ -98,8 +97,8 @@ class TokenGeneratorTest(TestCase): A valid token can be created with a secret other than SECRET_KEY by using the PasswordResetTokenGenerator.secret attribute. """ - user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') - new_secret = 'abcdefghijkl' + user = User.objects.create_user("tokentestuser", "test2@example.com", "testpw") + new_secret = "abcdefghijkl" # Create and check a token with a different secret. p0 = PasswordResetTokenGenerator() p0.secret = new_secret @@ -116,9 +115,9 @@ class TokenGeneratorTest(TestCase): def test_token_with_different_secret_subclass(self): class CustomPasswordResetTokenGenerator(PasswordResetTokenGenerator): - secret = 'test-secret' + secret = "test-secret" - user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') + user = User.objects.create_user("tokentestuser", "test2@example.com", "testpw") custom_password_generator = CustomPasswordResetTokenGenerator() tk_custom = custom_password_generator.make_token(user) self.assertIs(custom_password_generator.check_token(user, tk_custom), True) @@ -134,44 +133,44 @@ class TokenGeneratorTest(TestCase): self.assertIs(custom_password_generator.check_token(user, tk_default), False) self.assertIs(default_password_generator.check_token(user, tk_custom), False) - @override_settings(SECRET_KEY='') + @override_settings(SECRET_KEY="") def test_secret_lazy_validation(self): default_token_generator = PasswordResetTokenGenerator() - msg = 'The SECRET_KEY setting must not be empty.' + msg = "The SECRET_KEY setting must not be empty." with self.assertRaisesMessage(ImproperlyConfigured, msg): default_token_generator.secret def test_check_token_secret_fallbacks(self): - user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') + user = User.objects.create_user("tokentestuser", "test2@example.com", "testpw") p1 = PasswordResetTokenGenerator() - p1.secret = 'secret' + p1.secret = "secret" tk = p1.make_token(user) p2 = PasswordResetTokenGenerator() - p2.secret = 'newsecret' - p2.secret_fallbacks = ['secret'] + p2.secret = "newsecret" + p2.secret_fallbacks = ["secret"] self.assertIs(p1.check_token(user, tk), True) self.assertIs(p2.check_token(user, tk), True) @override_settings( - SECRET_KEY='secret', - SECRET_KEY_FALLBACKS=['oldsecret'], + SECRET_KEY="secret", + SECRET_KEY_FALLBACKS=["oldsecret"], ) def test_check_token_secret_key_fallbacks(self): - user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') + user = User.objects.create_user("tokentestuser", "test2@example.com", "testpw") p1 = PasswordResetTokenGenerator() - p1.secret = 'oldsecret' + p1.secret = "oldsecret" tk = p1.make_token(user) p2 = PasswordResetTokenGenerator() self.assertIs(p2.check_token(user, tk), True) @override_settings( - SECRET_KEY='secret', - SECRET_KEY_FALLBACKS=['oldsecret'], + SECRET_KEY="secret", + SECRET_KEY_FALLBACKS=["oldsecret"], ) def test_check_token_secret_key_fallbacks_override(self): - user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') + user = User.objects.create_user("tokentestuser", "test2@example.com", "testpw") p1 = PasswordResetTokenGenerator() - p1.secret = 'oldsecret' + p1.secret = "oldsecret" tk = p1.make_token(user) p2 = PasswordResetTokenGenerator() p2.secret_fallbacks = [] diff --git a/tests/auth_tests/test_validators.py b/tests/auth_tests/test_validators.py index f4aaf33052..727662c144 100644 --- a/tests/auth_tests/test_validators.py +++ b/tests/auth_tests/test_validators.py @@ -3,10 +3,15 @@ import os from django.contrib.auth import validators from django.contrib.auth.models import User from django.contrib.auth.password_validation import ( - CommonPasswordValidator, MinimumLengthValidator, NumericPasswordValidator, - UserAttributeSimilarityValidator, get_default_password_validators, - get_password_validators, password_changed, - password_validators_help_text_html, password_validators_help_texts, + CommonPasswordValidator, + MinimumLengthValidator, + NumericPasswordValidator, + UserAttributeSimilarityValidator, + get_default_password_validators, + get_password_validators, + password_changed, + password_validators_help_text_html, + password_validators_help_texts, validate_password, ) from django.core.exceptions import ValidationError @@ -16,46 +21,57 @@ from django.test.utils import isolate_apps from django.utils.html import conditional_escape -@override_settings(AUTH_PASSWORD_VALIDATORS=[ - {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, - {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': { - 'min_length': 12, - }}, -]) +@override_settings( + AUTH_PASSWORD_VALIDATORS=[ + {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + "OPTIONS": { + "min_length": 12, + }, + }, + ] +) class PasswordValidationTest(SimpleTestCase): def test_get_default_password_validators(self): validators = get_default_password_validators() self.assertEqual(len(validators), 2) - self.assertEqual(validators[0].__class__.__name__, 'CommonPasswordValidator') - self.assertEqual(validators[1].__class__.__name__, 'MinimumLengthValidator') + self.assertEqual(validators[0].__class__.__name__, "CommonPasswordValidator") + self.assertEqual(validators[1].__class__.__name__, "MinimumLengthValidator") self.assertEqual(validators[1].min_length, 12) def test_get_password_validators_custom(self): - validator_config = [{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}] + validator_config = [ + {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"} + ] validators = get_password_validators(validator_config) self.assertEqual(len(validators), 1) - self.assertEqual(validators[0].__class__.__name__, 'CommonPasswordValidator') + self.assertEqual(validators[0].__class__.__name__, "CommonPasswordValidator") self.assertEqual(get_password_validators([]), []) def test_validate_password(self): - self.assertIsNone(validate_password('sufficiently-long')) - msg_too_short = 'This password is too short. It must contain at least 12 characters.' + self.assertIsNone(validate_password("sufficiently-long")) + msg_too_short = ( + "This password is too short. It must contain at least 12 characters." + ) with self.assertRaises(ValidationError) as cm: - validate_password('django4242') + validate_password("django4242") self.assertEqual(cm.exception.messages, [msg_too_short]) - self.assertEqual(cm.exception.error_list[0].code, 'password_too_short') + self.assertEqual(cm.exception.error_list[0].code, "password_too_short") with self.assertRaises(ValidationError) as cm: - validate_password('password') - self.assertEqual(cm.exception.messages, ['This password is too common.', msg_too_short]) - self.assertEqual(cm.exception.error_list[0].code, 'password_too_common') + validate_password("password") + self.assertEqual( + cm.exception.messages, ["This password is too common.", msg_too_short] + ) + self.assertEqual(cm.exception.error_list[0].code, "password_too_common") - self.assertIsNone(validate_password('password', password_validators=[])) + self.assertIsNone(validate_password("password", password_validators=[])) def test_password_changed(self): - self.assertIsNone(password_changed('password')) + self.assertIsNone(password_changed("password")) def test_password_changed_with_custom_validator(self): class Validator: @@ -65,139 +81,151 @@ class PasswordValidationTest(SimpleTestCase): user = object() validator = Validator() - password_changed('password', user=user, password_validators=(validator,)) + password_changed("password", user=user, password_validators=(validator,)) self.assertIs(validator.user, user) - self.assertEqual(validator.password, 'password') + self.assertEqual(validator.password, "password") def test_password_validators_help_texts(self): help_texts = password_validators_help_texts() self.assertEqual(len(help_texts), 2) - self.assertIn('12 characters', help_texts[1]) + self.assertIn("12 characters", help_texts[1]) self.assertEqual(password_validators_help_texts(password_validators=[]), []) def test_password_validators_help_text_html(self): help_text = password_validators_help_text_html() - self.assertEqual(help_text.count('<li>'), 2) - self.assertIn('12 characters', help_text) + self.assertEqual(help_text.count("<li>"), 2) + self.assertIn("12 characters", help_text) def test_password_validators_help_text_html_escaping(self): class AmpersandValidator: def get_help_text(self): - return 'Must contain &' + return "Must contain &" + help_text = password_validators_help_text_html([AmpersandValidator()]) - self.assertEqual(help_text, '<ul><li>Must contain &</li></ul>') + self.assertEqual(help_text, "<ul><li>Must contain &</li></ul>") # help_text is marked safe and therefore unchanged by conditional_escape(). self.assertEqual(help_text, conditional_escape(help_text)) @override_settings(AUTH_PASSWORD_VALIDATORS=[]) def test_empty_password_validator_help_text_html(self): - self.assertEqual(password_validators_help_text_html(), '') + self.assertEqual(password_validators_help_text_html(), "") class MinimumLengthValidatorTest(SimpleTestCase): def test_validate(self): - expected_error = "This password is too short. It must contain at least %d characters." - self.assertIsNone(MinimumLengthValidator().validate('12345678')) - self.assertIsNone(MinimumLengthValidator(min_length=3).validate('123')) + expected_error = ( + "This password is too short. It must contain at least %d characters." + ) + self.assertIsNone(MinimumLengthValidator().validate("12345678")) + self.assertIsNone(MinimumLengthValidator(min_length=3).validate("123")) with self.assertRaises(ValidationError) as cm: - MinimumLengthValidator().validate('1234567') + MinimumLengthValidator().validate("1234567") self.assertEqual(cm.exception.messages, [expected_error % 8]) - self.assertEqual(cm.exception.error_list[0].code, 'password_too_short') + self.assertEqual(cm.exception.error_list[0].code, "password_too_short") with self.assertRaises(ValidationError) as cm: - MinimumLengthValidator(min_length=3).validate('12') + MinimumLengthValidator(min_length=3).validate("12") self.assertEqual(cm.exception.messages, [expected_error % 3]) def test_help_text(self): self.assertEqual( MinimumLengthValidator().get_help_text(), - "Your password must contain at least 8 characters." + "Your password must contain at least 8 characters.", ) class UserAttributeSimilarityValidatorTest(TestCase): def test_validate(self): user = User.objects.create_user( - username='testclient', password='password', email='testclient@example.com', - first_name='Test', last_name='Client', + username="testclient", + password="password", + email="testclient@example.com", + first_name="Test", + last_name="Client", ) expected_error = "The password is too similar to the %s." - self.assertIsNone(UserAttributeSimilarityValidator().validate('testclient')) + self.assertIsNone(UserAttributeSimilarityValidator().validate("testclient")) with self.assertRaises(ValidationError) as cm: - UserAttributeSimilarityValidator().validate('testclient', user=user), + UserAttributeSimilarityValidator().validate("testclient", user=user), self.assertEqual(cm.exception.messages, [expected_error % "username"]) - self.assertEqual(cm.exception.error_list[0].code, 'password_too_similar') + self.assertEqual(cm.exception.error_list[0].code, "password_too_similar") with self.assertRaises(ValidationError) as cm: - UserAttributeSimilarityValidator().validate('example.com', user=user), + UserAttributeSimilarityValidator().validate("example.com", user=user), self.assertEqual(cm.exception.messages, [expected_error % "email address"]) with self.assertRaises(ValidationError) as cm: UserAttributeSimilarityValidator( - user_attributes=['first_name'], + user_attributes=["first_name"], max_similarity=0.3, - ).validate('testclient', user=user) + ).validate("testclient", user=user) self.assertEqual(cm.exception.messages, [expected_error % "first name"]) # max_similarity=1 doesn't allow passwords that are identical to the # attribute's value. with self.assertRaises(ValidationError) as cm: UserAttributeSimilarityValidator( - user_attributes=['first_name'], + user_attributes=["first_name"], max_similarity=1, ).validate(user.first_name, user=user) self.assertEqual(cm.exception.messages, [expected_error % "first name"]) # Very low max_similarity is rejected. - msg = 'max_similarity must be at least 0.1' + msg = "max_similarity must be at least 0.1" with self.assertRaisesMessage(ValueError, msg): UserAttributeSimilarityValidator(max_similarity=0.09) # Passes validation. self.assertIsNone( - UserAttributeSimilarityValidator(user_attributes=['first_name']).validate('testclient', user=user) + UserAttributeSimilarityValidator(user_attributes=["first_name"]).validate( + "testclient", user=user + ) ) - @isolate_apps('auth_tests') + @isolate_apps("auth_tests") def test_validate_property(self): class TestUser(models.Model): pass @property def username(self): - return 'foobar' + return "foobar" with self.assertRaises(ValidationError) as cm: - UserAttributeSimilarityValidator().validate('foobar', user=TestUser()), - self.assertEqual(cm.exception.messages, ['The password is too similar to the username.']) + UserAttributeSimilarityValidator().validate("foobar", user=TestUser()), + self.assertEqual( + cm.exception.messages, ["The password is too similar to the username."] + ) def test_help_text(self): self.assertEqual( UserAttributeSimilarityValidator().get_help_text(), - 'Your password can’t be too similar to your other personal information.' + "Your password can’t be too similar to your other personal information.", ) class CommonPasswordValidatorTest(SimpleTestCase): def test_validate(self): expected_error = "This password is too common." - self.assertIsNone(CommonPasswordValidator().validate('a-safe-password')) + self.assertIsNone(CommonPasswordValidator().validate("a-safe-password")) with self.assertRaises(ValidationError) as cm: - CommonPasswordValidator().validate('godzilla') + CommonPasswordValidator().validate("godzilla") self.assertEqual(cm.exception.messages, [expected_error]) def test_validate_custom_list(self): - path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'common-passwords-custom.txt') + path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "common-passwords-custom.txt" + ) validator = CommonPasswordValidator(password_list_path=path) expected_error = "This password is too common." - self.assertIsNone(validator.validate('a-safe-password')) + self.assertIsNone(validator.validate("a-safe-password")) with self.assertRaises(ValidationError) as cm: - validator.validate('from-my-custom-list') + validator.validate("from-my-custom-list") self.assertEqual(cm.exception.messages, [expected_error]) - self.assertEqual(cm.exception.error_list[0].code, 'password_too_common') + self.assertEqual(cm.exception.error_list[0].code, "password_too_common") def test_validate_django_supplied_file(self): validator = CommonPasswordValidator() @@ -207,34 +235,37 @@ class CommonPasswordValidatorTest(SimpleTestCase): def test_help_text(self): self.assertEqual( CommonPasswordValidator().get_help_text(), - 'Your password can’t be a commonly used password.' + "Your password can’t be a commonly used password.", ) class NumericPasswordValidatorTest(SimpleTestCase): def test_validate(self): expected_error = "This password is entirely numeric." - self.assertIsNone(NumericPasswordValidator().validate('a-safe-password')) + self.assertIsNone(NumericPasswordValidator().validate("a-safe-password")) with self.assertRaises(ValidationError) as cm: - NumericPasswordValidator().validate('42424242') + NumericPasswordValidator().validate("42424242") self.assertEqual(cm.exception.messages, [expected_error]) - self.assertEqual(cm.exception.error_list[0].code, 'password_entirely_numeric') + self.assertEqual(cm.exception.error_list[0].code, "password_entirely_numeric") def test_help_text(self): self.assertEqual( NumericPasswordValidator().get_help_text(), - 'Your password can’t be entirely numeric.' + "Your password can’t be entirely numeric.", ) class UsernameValidatorsTests(SimpleTestCase): def test_unicode_validator(self): - valid_usernames = ['joe', 'René', 'ᴮᴵᴳᴮᴵᴿᴰ', 'أحمد'] + valid_usernames = ["joe", "René", "ᴮᴵᴳᴮᴵᴿᴰ", "أحمد"] invalid_usernames = [ - "o'connell", "عبد ال", - "zerowidth\u200Bspace", "nonbreaking\u00A0space", - "en\u2013dash", 'trailingnewline\u000A', + "o'connell", + "عبد ال", + "zerowidth\u200Bspace", + "nonbreaking\u00A0space", + "en\u2013dash", + "trailingnewline\u000A", ] v = validators.UnicodeUsernameValidator() for valid in valid_usernames: @@ -246,8 +277,14 @@ class UsernameValidatorsTests(SimpleTestCase): v(invalid) def test_ascii_validator(self): - valid_usernames = ['glenn', 'GLEnN', 'jean-marc'] - invalid_usernames = ["o'connell", 'Éric', 'jean marc', "أحمد", 'trailingnewline\n'] + valid_usernames = ["glenn", "GLEnN", "jean-marc"] + invalid_usernames = [ + "o'connell", + "Éric", + "jean marc", + "أحمد", + "trailingnewline\n", + ] v = validators.ASCIIUsernameValidator() for valid in valid_usernames: with self.subTest(valid=valid): diff --git a/tests/auth_tests/test_views.py b/tests/auth_tests/test_views.py index a572e2610f..5ba05e8a00 100644 --- a/tests/auth_tests/test_views.py +++ b/tests/auth_tests/test_views.py @@ -8,15 +8,17 @@ from urllib.parse import quote, urljoin from django.apps import apps from django.conf import settings from django.contrib.admin.models import LogEntry -from django.contrib.auth import ( - BACKEND_SESSION_KEY, REDIRECT_FIELD_NAME, SESSION_KEY, -) +from django.contrib.auth import BACKEND_SESSION_KEY, REDIRECT_FIELD_NAME, SESSION_KEY from django.contrib.auth.forms import ( - AuthenticationForm, PasswordChangeForm, SetPasswordForm, + AuthenticationForm, + PasswordChangeForm, + SetPasswordForm, ) from django.contrib.auth.models import Permission, User from django.contrib.auth.views import ( - INTERNAL_RESET_SESSION_TOKEN, LoginView, logout_then_login, + INTERNAL_RESET_SESSION_TOKEN, + LoginView, + logout_then_login, redirect_to_login, ) from django.contrib.contenttypes.models import ContentType @@ -38,10 +40,10 @@ from .settings import AUTH_TEMPLATES @override_settings( - LANGUAGES=[('en', 'English')], - LANGUAGE_CODE='en', + LANGUAGES=[("en", "English")], + LANGUAGE_CODE="en", TEMPLATES=AUTH_TEMPLATES, - ROOT_URLCONF='auth_tests.urls', + ROOT_URLCONF="auth_tests.urls", ) class AuthViewsTestCase(TestCase): """ @@ -50,71 +52,86 @@ class AuthViewsTestCase(TestCase): @classmethod def setUpTestData(cls): - cls.u1 = User.objects.create_user(username='testclient', password='password', email='testclient@example.com') - cls.u3 = User.objects.create_user(username='staff', password='password', email='staffmember@example.com') - - def login(self, username='testclient', password='password', url='/login/'): - response = self.client.post(url, { - 'username': username, - 'password': password, - }) + cls.u1 = User.objects.create_user( + username="testclient", password="password", email="testclient@example.com" + ) + cls.u3 = User.objects.create_user( + username="staff", password="password", email="staffmember@example.com" + ) + + def login(self, username="testclient", password="password", url="/login/"): + response = self.client.post( + url, + { + "username": username, + "password": password, + }, + ) self.assertIn(SESSION_KEY, self.client.session) return response def logout(self): - response = self.client.get('/admin/logout/') + response = self.client.get("/admin/logout/") self.assertEqual(response.status_code, 200) self.assertNotIn(SESSION_KEY, self.client.session) def assertFormError(self, response, error): """Assert that error is found in response.context['form'] errors""" - form_errors = list(itertools.chain(*response.context['form'].errors.values())) + form_errors = list(itertools.chain(*response.context["form"].errors.values())) self.assertIn(str(error), form_errors) -@override_settings(ROOT_URLCONF='django.contrib.auth.urls') +@override_settings(ROOT_URLCONF="django.contrib.auth.urls") class AuthViewNamedURLTests(AuthViewsTestCase): - def test_named_urls(self): "Named URLs should be reversible" expected_named_urls = [ - ('login', [], {}), - ('logout', [], {}), - ('password_change', [], {}), - ('password_change_done', [], {}), - ('password_reset', [], {}), - ('password_reset_done', [], {}), - ('password_reset_confirm', [], { - 'uidb64': 'aaaaaaa', - 'token': '1111-aaaaa', - }), - ('password_reset_complete', [], {}), + ("login", [], {}), + ("logout", [], {}), + ("password_change", [], {}), + ("password_change_done", [], {}), + ("password_reset", [], {}), + ("password_reset_done", [], {}), + ( + "password_reset_confirm", + [], + { + "uidb64": "aaaaaaa", + "token": "1111-aaaaa", + }, + ), + ("password_reset_complete", [], {}), ] for name, args, kwargs in expected_named_urls: with self.subTest(name=name): try: reverse(name, args=args, kwargs=kwargs) except NoReverseMatch: - self.fail("Reversal of url named '%s' failed with NoReverseMatch" % name) + self.fail( + "Reversal of url named '%s' failed with NoReverseMatch" % name + ) class PasswordResetTest(AuthViewsTestCase): - def setUp(self): self.client = PasswordResetConfirmClient() def test_email_not_found(self): """If the provided email is not registered, don't raise any error but also don't send any email.""" - response = self.client.get('/password_reset/') + response = self.client.get("/password_reset/") self.assertEqual(response.status_code, 200) - response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'}) + response = self.client.post( + "/password_reset/", {"email": "not_a_real_email@email.com"} + ) self.assertEqual(response.status_code, 302) self.assertEqual(len(mail.outbox), 0) def test_email_found(self): "Email is sent if a valid email address is provided for password reset" - response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'}) + response = self.client.post( + "/password_reset/", {"email": "staffmember@example.com"} + ) self.assertEqual(response.status_code, 302) self.assertEqual(len(mail.outbox), 1) self.assertIn("http://", mail.outbox[0].body) @@ -128,33 +145,37 @@ class PasswordResetTest(AuthViewsTestCase): extra_email_context should be available in the email template context. """ response = self.client.post( - '/password_reset_extra_email_context/', - {'email': 'staffmember@example.com'}, + "/password_reset_extra_email_context/", + {"email": "staffmember@example.com"}, ) self.assertEqual(response.status_code, 302) self.assertEqual(len(mail.outbox), 1) self.assertIn('Email email context: "Hello!"', mail.outbox[0].body) - self.assertIn('http://custom.example.com/reset/', mail.outbox[0].body) + self.assertIn("http://custom.example.com/reset/", mail.outbox[0].body) def test_html_mail_template(self): """ A multipart email with text/plain and text/html is sent if the html_email_template parameter is passed to the view """ - response = self.client.post('/password_reset/html_email_template/', {'email': 'staffmember@example.com'}) + response = self.client.post( + "/password_reset/html_email_template/", {"email": "staffmember@example.com"} + ) self.assertEqual(response.status_code, 302) self.assertEqual(len(mail.outbox), 1) message = mail.outbox[0].message() self.assertEqual(len(message.get_payload()), 2) self.assertTrue(message.is_multipart()) - self.assertEqual(message.get_payload(0).get_content_type(), 'text/plain') - self.assertEqual(message.get_payload(1).get_content_type(), 'text/html') - self.assertNotIn('<html>', message.get_payload(0).get_payload()) - self.assertIn('<html>', message.get_payload(1).get_payload()) + self.assertEqual(message.get_payload(0).get_content_type(), "text/plain") + self.assertEqual(message.get_payload(1).get_content_type(), "text/html") + self.assertNotIn("<html>", message.get_payload(0).get_payload()) + self.assertIn("<html>", message.get_payload(1).get_payload()) def test_email_found_custom_from(self): "Email is sent if a valid email address is provided for password reset when a custom from_email is provided." - response = self.client.post('/password_reset_from_email/', {'email': 'staffmember@example.com'}) + response = self.client.post( + "/password_reset_from_email/", {"email": "staffmember@example.com"} + ) self.assertEqual(response.status_code, 302) self.assertEqual(len(mail.outbox), 1) self.assertEqual("staffmember@example.com", mail.outbox[0].from_email) @@ -170,11 +191,11 @@ class PasswordResetTest(AuthViewsTestCase): # produce a meaningful reset URL, we need to be certain that the # HTTP_HOST header isn't poisoned. This is done as a check when get_host() # is invoked, but we check here as a practical consequence. - with self.assertLogs('django.security.DisallowedHost', 'ERROR'): + with self.assertLogs("django.security.DisallowedHost", "ERROR"): response = self.client.post( - '/password_reset/', - {'email': 'staffmember@example.com'}, - HTTP_HOST='www.example:dr.frankenstein@evil.tld' + "/password_reset/", + {"email": "staffmember@example.com"}, + HTTP_HOST="www.example:dr.frankenstein@evil.tld", ) self.assertEqual(response.status_code, 400) self.assertEqual(len(mail.outbox), 0) @@ -183,18 +204,18 @@ class PasswordResetTest(AuthViewsTestCase): @override_settings(DEBUG_PROPAGATE_EXCEPTIONS=True) def test_poisoned_http_host_admin_site(self): "Poisoned HTTP_HOST headers can't be used for reset emails on admin views" - with self.assertLogs('django.security.DisallowedHost', 'ERROR'): + with self.assertLogs("django.security.DisallowedHost", "ERROR"): response = self.client.post( - '/admin_password_reset/', - {'email': 'staffmember@example.com'}, - HTTP_HOST='www.example:dr.frankenstein@evil.tld' + "/admin_password_reset/", + {"email": "staffmember@example.com"}, + HTTP_HOST="www.example:dr.frankenstein@evil.tld", ) self.assertEqual(response.status_code, 400) self.assertEqual(len(mail.outbox), 0) def _test_confirm_start(self): # Start by creating the email - self.client.post('/password_reset/', {'email': 'staffmember@example.com'}) + self.client.post("/password_reset/", {"email": "staffmember@example.com"}) self.assertEqual(len(mail.outbox), 1) return self._read_signup_email(mail.outbox[0]) @@ -220,12 +241,12 @@ class PasswordResetTest(AuthViewsTestCase): def test_confirm_invalid_user(self): # A nonexistent user returns a 200 response, not a 404. - response = self.client.get('/reset/123456/1-1/') + response = self.client.get("/reset/123456/1-1/") self.assertContains(response, "The password reset link was invalid") def test_confirm_overflow_user(self): # A base36 user id that overflows int returns a 200 response. - response = self.client.get('/reset/zzzzzzzzzzzzz/1-1/') + response = self.client.get("/reset/zzzzzzzzzzzzz/1-1/") self.assertContains(response, "The password reset link was invalid") def test_confirm_invalid_post(self): @@ -233,36 +254,44 @@ class PasswordResetTest(AuthViewsTestCase): url, path = self._test_confirm_start() path = path[:-5] + ("0" * 4) + path[-1] - self.client.post(path, { - 'new_password1': 'anewpassword', - 'new_password2': ' anewpassword', - }) + self.client.post( + path, + { + "new_password1": "anewpassword", + "new_password2": " anewpassword", + }, + ) # Check the password has not been changed - u = User.objects.get(email='staffmember@example.com') + u = User.objects.get(email="staffmember@example.com") self.assertTrue(not u.check_password("anewpassword")) def test_confirm_invalid_hash(self): """A POST with an invalid token is rejected.""" - u = User.objects.get(email='staffmember@example.com') + u = User.objects.get(email="staffmember@example.com") original_password = u.password url, path = self._test_confirm_start() - path_parts = path.split('-') - path_parts[-1] = ("0") * 20 + '/' - path = '-'.join(path_parts) - - response = self.client.post(path, { - 'new_password1': 'anewpassword', - 'new_password2': 'anewpassword', - }) - self.assertIs(response.context['validlink'], False) + path_parts = path.split("-") + path_parts[-1] = ("0") * 20 + "/" + path = "-".join(path_parts) + + response = self.client.post( + path, + { + "new_password1": "anewpassword", + "new_password2": "anewpassword", + }, + ) + self.assertIs(response.context["validlink"], False) u.refresh_from_db() self.assertEqual(original_password, u.password) # password hasn't changed def test_confirm_complete(self): url, path = self._test_confirm_start() - response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'}) + response = self.client.post( + path, {"new_password1": "anewpassword", "new_password2": "anewpassword"} + ) # Check the password has been changed - u = User.objects.get(email='staffmember@example.com') + u = User.objects.get(email="staffmember@example.com") self.assertTrue(u.check_password("anewpassword")) # The reset token is deleted from the session. self.assertNotIn(INTERNAL_RESET_SESSION_TOKEN, self.client.session) @@ -273,77 +302,106 @@ class PasswordResetTest(AuthViewsTestCase): def test_confirm_different_passwords(self): url, path = self._test_confirm_start() - response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'x'}) - self.assertFormError(response, SetPasswordForm.error_messages['password_mismatch']) + response = self.client.post( + path, {"new_password1": "anewpassword", "new_password2": "x"} + ) + self.assertFormError( + response, SetPasswordForm.error_messages["password_mismatch"] + ) def test_reset_redirect_default(self): - response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'}) - self.assertRedirects(response, '/password_reset/done/', fetch_redirect_response=False) + response = self.client.post( + "/password_reset/", {"email": "staffmember@example.com"} + ) + self.assertRedirects( + response, "/password_reset/done/", fetch_redirect_response=False + ) def test_reset_custom_redirect(self): - response = self.client.post('/password_reset/custom_redirect/', {'email': 'staffmember@example.com'}) - self.assertRedirects(response, '/custom/', fetch_redirect_response=False) + response = self.client.post( + "/password_reset/custom_redirect/", {"email": "staffmember@example.com"} + ) + self.assertRedirects(response, "/custom/", fetch_redirect_response=False) def test_reset_custom_redirect_named(self): - response = self.client.post('/password_reset/custom_redirect/named/', {'email': 'staffmember@example.com'}) - self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False) + response = self.client.post( + "/password_reset/custom_redirect/named/", + {"email": "staffmember@example.com"}, + ) + self.assertRedirects( + response, "/password_reset/", fetch_redirect_response=False + ) def test_confirm_redirect_default(self): url, path = self._test_confirm_start() - response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'}) - self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False) + response = self.client.post( + path, {"new_password1": "anewpassword", "new_password2": "anewpassword"} + ) + self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False) def test_confirm_redirect_custom(self): url, path = self._test_confirm_start() - path = path.replace('/reset/', '/reset/custom/') - response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'}) - self.assertRedirects(response, '/custom/', fetch_redirect_response=False) + path = path.replace("/reset/", "/reset/custom/") + response = self.client.post( + path, {"new_password1": "anewpassword", "new_password2": "anewpassword"} + ) + self.assertRedirects(response, "/custom/", fetch_redirect_response=False) def test_confirm_redirect_custom_named(self): url, path = self._test_confirm_start() - path = path.replace('/reset/', '/reset/custom/named/') - response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'}) - self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False) + path = path.replace("/reset/", "/reset/custom/named/") + response = self.client.post( + path, {"new_password1": "anewpassword", "new_password2": "anewpassword"} + ) + self.assertRedirects( + response, "/password_reset/", fetch_redirect_response=False + ) def test_confirm_custom_reset_url_token(self): url, path = self._test_confirm_start() - path = path.replace('/reset/', '/reset/custom/token/') - self.client.reset_url_token = 'set-passwordcustom' + path = path.replace("/reset/", "/reset/custom/token/") + self.client.reset_url_token = "set-passwordcustom" response = self.client.post( path, - {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'}, + {"new_password1": "anewpassword", "new_password2": "anewpassword"}, ) - self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False) + self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False) def test_confirm_login_post_reset(self): url, path = self._test_confirm_start() - path = path.replace('/reset/', '/reset/post_reset_login/') - response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'}) - self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False) + path = path.replace("/reset/", "/reset/post_reset_login/") + response = self.client.post( + path, {"new_password1": "anewpassword", "new_password2": "anewpassword"} + ) + self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False) self.assertIn(SESSION_KEY, self.client.session) @override_settings( AUTHENTICATION_BACKENDS=[ - 'django.contrib.auth.backends.ModelBackend', - 'django.contrib.auth.backends.AllowAllUsersModelBackend', + "django.contrib.auth.backends.ModelBackend", + "django.contrib.auth.backends.AllowAllUsersModelBackend", ] ) def test_confirm_login_post_reset_custom_backend(self): # This backend is specified in the URL pattern. - backend = 'django.contrib.auth.backends.AllowAllUsersModelBackend' + backend = "django.contrib.auth.backends.AllowAllUsersModelBackend" url, path = self._test_confirm_start() - path = path.replace('/reset/', '/reset/post_reset_login_custom_backend/') - response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'}) - self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False) + path = path.replace("/reset/", "/reset/post_reset_login_custom_backend/") + response = self.client.post( + path, {"new_password1": "anewpassword", "new_password2": "anewpassword"} + ) + self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False) self.assertIn(SESSION_KEY, self.client.session) self.assertEqual(self.client.session[BACKEND_SESSION_KEY], backend) def test_confirm_login_post_reset_already_logged_in(self): url, path = self._test_confirm_start() - path = path.replace('/reset/', '/reset/post_reset_login/') + path = path.replace("/reset/", "/reset/post_reset_login/") self.login() - response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'}) - self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False) + response = self.client.post( + path, {"new_password1": "anewpassword", "new_password2": "anewpassword"} + ) + self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False) self.assertIn(SESSION_KEY, self.client.session) def test_confirm_display_user_from_form(self): @@ -353,11 +411,11 @@ class PasswordResetTest(AuthViewsTestCase): # SetPasswordForm``, even on GET requests (#16919). For this test, # {{ form.user }}`` is rendered in the template # registration/password_reset_confirm.html. - username = User.objects.get(email='staffmember@example.com').username + username = User.objects.get(email="staffmember@example.com").username self.assertContains(response, "Hello, %s." % username) # However, the view should NOT pass any user object on a form if the # password reset link was invalid. - response = self.client.get('/reset/zzzzzzzzzzzzz/1-1/') + response = self.client.get("/reset/zzzzzzzzzzzzz/1-1/") self.assertContains(response, "Hello, .") def test_confirm_link_redirects_to_set_password_page(self): @@ -366,44 +424,46 @@ class PasswordResetTest(AuthViewsTestCase): # automatically fetches the redirect page. client = Client() response = client.get(path) - token = response.resolver_match.kwargs['token'] - uuidb64 = response.resolver_match.kwargs['uidb64'] - self.assertRedirects(response, '/reset/%s/set-password/' % uuidb64) - self.assertEqual(client.session['_password_reset_token'], token) + token = response.resolver_match.kwargs["token"] + uuidb64 = response.resolver_match.kwargs["uidb64"] + self.assertRedirects(response, "/reset/%s/set-password/" % uuidb64) + self.assertEqual(client.session["_password_reset_token"], token) def test_confirm_custom_reset_url_token_link_redirects_to_set_password_page(self): url, path = self._test_confirm_start() - path = path.replace('/reset/', '/reset/custom/token/') + path = path.replace("/reset/", "/reset/custom/token/") client = Client() response = client.get(path) - token = response.resolver_match.kwargs['token'] - uuidb64 = response.resolver_match.kwargs['uidb64'] - self.assertRedirects(response, '/reset/custom/token/%s/set-passwordcustom/' % uuidb64) - self.assertEqual(client.session['_password_reset_token'], token) + token = response.resolver_match.kwargs["token"] + uuidb64 = response.resolver_match.kwargs["uidb64"] + self.assertRedirects( + response, "/reset/custom/token/%s/set-passwordcustom/" % uuidb64 + ) + self.assertEqual(client.session["_password_reset_token"], token) def test_invalid_link_if_going_directly_to_the_final_reset_password_url(self): url, path = self._test_confirm_start() - _, uuidb64, _ = path.strip('/').split('/') - response = Client().get('/reset/%s/set-password/' % uuidb64) - self.assertContains(response, 'The password reset link was invalid') + _, uuidb64, _ = path.strip("/").split("/") + response = Client().get("/reset/%s/set-password/" % uuidb64) + self.assertContains(response, "The password reset link was invalid") def test_missing_kwargs(self): msg = "The URL path must contain 'uidb64' and 'token' parameters." with self.assertRaisesMessage(ImproperlyConfigured, msg): - self.client.get('/reset/missing_parameters/') + self.client.get("/reset/missing_parameters/") -@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser') +@override_settings(AUTH_USER_MODEL="auth_tests.CustomUser") class CustomUserPasswordResetTest(AuthViewsTestCase): - user_email = 'staffmember@example.com' + user_email = "staffmember@example.com" @classmethod def setUpTestData(cls): cls.u1 = CustomUser.custom_objects.create( - email='staffmember@example.com', + email="staffmember@example.com", date_of_birth=datetime.date(1976, 11, 8), ) - cls.u1.set_password('password') + cls.u1.set_password("password") cls.u1.save() def setUp(self): @@ -411,7 +471,7 @@ class CustomUserPasswordResetTest(AuthViewsTestCase): def _test_confirm_start(self): # Start by creating the email - response = self.client.post('/password_reset/', {'email': self.user_email}) + response = self.client.post("/password_reset/", {"email": self.user_email}) self.assertEqual(response.status_code, 302) self.assertEqual(len(mail.outbox), 1) return self._read_signup_email(mail.outbox[0]) @@ -427,116 +487,159 @@ class CustomUserPasswordResetTest(AuthViewsTestCase): # redirect to a 'complete' page: self.assertContains(response, "Please enter your new password") # then submit a new password - response = self.client.post(path, { - 'new_password1': 'anewpassword', - 'new_password2': 'anewpassword', - }) - self.assertRedirects(response, '/reset/done/') + response = self.client.post( + path, + { + "new_password1": "anewpassword", + "new_password2": "anewpassword", + }, + ) + self.assertRedirects(response, "/reset/done/") -@override_settings(AUTH_USER_MODEL='auth_tests.UUIDUser') +@override_settings(AUTH_USER_MODEL="auth_tests.UUIDUser") class UUIDUserPasswordResetTest(CustomUserPasswordResetTest): - def _test_confirm_start(self): # instead of fixture UUIDUser.objects.create_user( email=self.user_email, - username='foo', - password='foo', + username="foo", + password="foo", ) return super()._test_confirm_start() def test_confirm_invalid_uuid(self): """A uidb64 that decodes to a non-UUID doesn't crash.""" _, path = self._test_confirm_start() - invalid_uidb64 = urlsafe_base64_encode(b'INVALID_UUID') - first, _uuidb64_, second = path.strip('/').split('/') - response = self.client.get('/' + '/'.join((first, invalid_uidb64, second)) + '/') - self.assertContains(response, 'The password reset link was invalid') + invalid_uidb64 = urlsafe_base64_encode(b"INVALID_UUID") + first, _uuidb64_, second = path.strip("/").split("/") + response = self.client.get( + "/" + "/".join((first, invalid_uidb64, second)) + "/" + ) + self.assertContains(response, "The password reset link was invalid") class ChangePasswordTest(AuthViewsTestCase): - def fail_login(self): - response = self.client.post('/login/', { - 'username': 'testclient', - 'password': 'password', - }) - self.assertFormError(response, AuthenticationForm.error_messages['invalid_login'] % { - 'username': User._meta.get_field('username').verbose_name - }) + response = self.client.post( + "/login/", + { + "username": "testclient", + "password": "password", + }, + ) + self.assertFormError( + response, + AuthenticationForm.error_messages["invalid_login"] + % {"username": User._meta.get_field("username").verbose_name}, + ) def logout(self): - self.client.get('/logout/') + self.client.get("/logout/") def test_password_change_fails_with_invalid_old_password(self): self.login() - response = self.client.post('/password_change/', { - 'old_password': 'donuts', - 'new_password1': 'password1', - 'new_password2': 'password1', - }) - self.assertFormError(response, PasswordChangeForm.error_messages['password_incorrect']) + response = self.client.post( + "/password_change/", + { + "old_password": "donuts", + "new_password1": "password1", + "new_password2": "password1", + }, + ) + self.assertFormError( + response, PasswordChangeForm.error_messages["password_incorrect"] + ) def test_password_change_fails_with_mismatched_passwords(self): self.login() - response = self.client.post('/password_change/', { - 'old_password': 'password', - 'new_password1': 'password1', - 'new_password2': 'donuts', - }) - self.assertFormError(response, SetPasswordForm.error_messages['password_mismatch']) + response = self.client.post( + "/password_change/", + { + "old_password": "password", + "new_password1": "password1", + "new_password2": "donuts", + }, + ) + self.assertFormError( + response, SetPasswordForm.error_messages["password_mismatch"] + ) def test_password_change_succeeds(self): self.login() - self.client.post('/password_change/', { - 'old_password': 'password', - 'new_password1': 'password1', - 'new_password2': 'password1', - }) + self.client.post( + "/password_change/", + { + "old_password": "password", + "new_password1": "password1", + "new_password2": "password1", + }, + ) self.fail_login() - self.login(password='password1') + self.login(password="password1") def test_password_change_done_succeeds(self): self.login() - response = self.client.post('/password_change/', { - 'old_password': 'password', - 'new_password1': 'password1', - 'new_password2': 'password1', - }) - self.assertRedirects(response, '/password_change/done/', fetch_redirect_response=False) - - @override_settings(LOGIN_URL='/login/') + response = self.client.post( + "/password_change/", + { + "old_password": "password", + "new_password1": "password1", + "new_password2": "password1", + }, + ) + self.assertRedirects( + response, "/password_change/done/", fetch_redirect_response=False + ) + + @override_settings(LOGIN_URL="/login/") def test_password_change_done_fails(self): - response = self.client.get('/password_change/done/') - self.assertRedirects(response, '/login/?next=/password_change/done/', fetch_redirect_response=False) + response = self.client.get("/password_change/done/") + self.assertRedirects( + response, + "/login/?next=/password_change/done/", + fetch_redirect_response=False, + ) def test_password_change_redirect_default(self): self.login() - response = self.client.post('/password_change/', { - 'old_password': 'password', - 'new_password1': 'password1', - 'new_password2': 'password1', - }) - self.assertRedirects(response, '/password_change/done/', fetch_redirect_response=False) + response = self.client.post( + "/password_change/", + { + "old_password": "password", + "new_password1": "password1", + "new_password2": "password1", + }, + ) + self.assertRedirects( + response, "/password_change/done/", fetch_redirect_response=False + ) def test_password_change_redirect_custom(self): self.login() - response = self.client.post('/password_change/custom/', { - 'old_password': 'password', - 'new_password1': 'password1', - 'new_password2': 'password1', - }) - self.assertRedirects(response, '/custom/', fetch_redirect_response=False) + response = self.client.post( + "/password_change/custom/", + { + "old_password": "password", + "new_password1": "password1", + "new_password2": "password1", + }, + ) + self.assertRedirects(response, "/custom/", fetch_redirect_response=False) def test_password_change_redirect_custom_named(self): self.login() - response = self.client.post('/password_change/custom/named/', { - 'old_password': 'password', - 'new_password1': 'password1', - 'new_password2': 'password1', - }) - self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False) + response = self.client.post( + "/password_change/custom/named/", + { + "old_password": "password", + "new_password1": "password1", + "new_password2": "password1", + }, + ) + self.assertRedirects( + response, "/password_reset/", fetch_redirect_response=False + ) class SessionAuthenticationTests(AuthViewsTestCase): @@ -547,94 +650,104 @@ class SessionAuthenticationTests(AuthViewsTestCase): """ self.login() original_session_key = self.client.session.session_key - response = self.client.post('/password_change/', { - 'old_password': 'password', - 'new_password1': 'password1', - 'new_password2': 'password1', - }) + response = self.client.post( + "/password_change/", + { + "old_password": "password", + "new_password1": "password1", + "new_password2": "password1", + }, + ) # if the hash isn't updated, retrieving the redirection page will fail. - self.assertRedirects(response, '/password_change/done/') + self.assertRedirects(response, "/password_change/done/") # The session key is rotated. self.assertNotEqual(original_session_key, self.client.session.session_key) class LoginTest(AuthViewsTestCase): - def test_current_site_in_context_after_login(self): - response = self.client.get(reverse('login')) + response = self.client.get(reverse("login")) self.assertEqual(response.status_code, 200) - if apps.is_installed('django.contrib.sites'): - Site = apps.get_model('sites.Site') + if apps.is_installed("django.contrib.sites"): + Site = apps.get_model("sites.Site") site = Site.objects.get_current() - self.assertEqual(response.context['site'], site) - self.assertEqual(response.context['site_name'], site.name) + self.assertEqual(response.context["site"], site) + self.assertEqual(response.context["site_name"], site.name) else: - self.assertIsInstance(response.context['site'], RequestSite) - self.assertIsInstance(response.context['form'], AuthenticationForm) + self.assertIsInstance(response.context["site"], RequestSite) + self.assertIsInstance(response.context["form"], AuthenticationForm) def test_security_check(self): - login_url = reverse('login') + login_url = reverse("login") # These URLs should not pass the security check. bad_urls = ( - 'http://example.com', - 'http:///example.com', - 'https://example.com', - 'ftp://example.com', - '///example.com', - '//example.com', + "http://example.com", + "http:///example.com", + "https://example.com", + "ftp://example.com", + "///example.com", + "//example.com", 'javascript:alert("XSS")', ) for bad_url in bad_urls: with self.subTest(bad_url=bad_url): - nasty_url = '%(url)s?%(next)s=%(bad_url)s' % { - 'url': login_url, - 'next': REDIRECT_FIELD_NAME, - 'bad_url': quote(bad_url), + nasty_url = "%(url)s?%(next)s=%(bad_url)s" % { + "url": login_url, + "next": REDIRECT_FIELD_NAME, + "bad_url": quote(bad_url), } - response = self.client.post(nasty_url, { - 'username': 'testclient', - 'password': 'password', - }) + response = self.client.post( + nasty_url, + { + "username": "testclient", + "password": "password", + }, + ) self.assertEqual(response.status_code, 302) - self.assertNotIn(bad_url, response.url, '%s should be blocked' % bad_url) + self.assertNotIn( + bad_url, response.url, "%s should be blocked" % bad_url + ) # These URLs should pass the security check. good_urls = ( - '/view/?param=http://example.com', - '/view/?param=https://example.com', - '/view?param=ftp://example.com', - 'view/?param=//example.com', - 'https://testserver/', - 'HTTPS://testserver/', - '//testserver/', - '/url%20with%20spaces/', + "/view/?param=http://example.com", + "/view/?param=https://example.com", + "/view?param=ftp://example.com", + "view/?param=//example.com", + "https://testserver/", + "HTTPS://testserver/", + "//testserver/", + "/url%20with%20spaces/", ) for good_url in good_urls: with self.subTest(good_url=good_url): - safe_url = '%(url)s?%(next)s=%(good_url)s' % { - 'url': login_url, - 'next': REDIRECT_FIELD_NAME, - 'good_url': quote(good_url), + safe_url = "%(url)s?%(next)s=%(good_url)s" % { + "url": login_url, + "next": REDIRECT_FIELD_NAME, + "good_url": quote(good_url), } - response = self.client.post(safe_url, { - 'username': 'testclient', - 'password': 'password', - }) + response = self.client.post( + safe_url, + { + "username": "testclient", + "password": "password", + }, + ) self.assertEqual(response.status_code, 302) - self.assertIn(good_url, response.url, '%s should be allowed' % good_url) + self.assertIn(good_url, response.url, "%s should be allowed" % good_url) def test_security_check_https(self): - login_url = reverse('login') - non_https_next_url = 'http://testserver/path' - not_secured_url = '%(url)s?%(next)s=%(next_url)s' % { - 'url': login_url, - 'next': REDIRECT_FIELD_NAME, - 'next_url': quote(non_https_next_url), + login_url = reverse("login") + non_https_next_url = "http://testserver/path" + not_secured_url = "%(url)s?%(next)s=%(next_url)s" % { + "url": login_url, + "next": REDIRECT_FIELD_NAME, + "next_url": quote(non_https_next_url), } post_data = { - 'username': 'testclient', - 'password': 'password', + "username": "testclient", + "password": "password", } response = self.client.post(not_secured_url, post_data, secure=True) self.assertEqual(response.status_code, 302) @@ -644,17 +757,23 @@ class LoginTest(AuthViewsTestCase): def test_login_form_contains_request(self): # The custom authentication form for this login requires a request to # initialize it. - response = self.client.post('/custom_request_auth_login/', { - 'username': 'testclient', - 'password': 'password', - }) + response = self.client.post( + "/custom_request_auth_login/", + { + "username": "testclient", + "password": "password", + }, + ) # The login was successful. - self.assertRedirects(response, settings.LOGIN_REDIRECT_URL, fetch_redirect_response=False) + self.assertRedirects( + response, settings.LOGIN_REDIRECT_URL, fetch_redirect_response=False + ) def test_login_csrf_rotate(self): """ Makes sure that a login rotates the currently-used CSRF token. """ + def get_response(request): return HttpResponse() @@ -672,12 +791,18 @@ class LoginTest(AuthViewsTestCase): req = HttpRequest() req.COOKIES[settings.CSRF_COOKIE_NAME] = token1 req.method = "POST" - req.POST = {'username': 'testclient', 'password': 'password', 'csrfmiddlewaretoken': token1} + req.POST = { + "username": "testclient", + "password": "password", + "csrfmiddlewaretoken": token1, + } # Use POST request to log in SessionMiddleware(get_response).process_request(req) CsrfViewMiddleware(get_response).process_view(req, LoginView.as_view(), (), {}) - req.META["SERVER_NAME"] = "testserver" # Required to have redirect work in login view + req.META[ + "SERVER_NAME" + ] = "testserver" # Required to have redirect work in login view req.META["SERVER_PORT"] = 80 resp = CsrfViewMiddleware(LoginView.as_view())(req) csrf_cookie = resp.cookies.get(settings.CSRF_COOKIE_NAME, None) @@ -695,7 +820,7 @@ class LoginTest(AuthViewsTestCase): self.login() original_session_key = self.client.session.session_key - self.login(username='staff') + self.login(username="staff") self.assertNotEqual(original_session_key, self.client.session.session_key) def test_session_key_flushed_on_login_after_password_change(self): @@ -709,11 +834,11 @@ class LoginTest(AuthViewsTestCase): self.login() self.assertEqual(original_session_key, self.client.session.session_key) - user = User.objects.get(username='testclient') - user.set_password('foobar') + user = User.objects.get(username="testclient") + user.set_password("foobar") user.save() - self.login(password='foobar') + self.login(password="foobar") self.assertNotEqual(original_session_key, self.client.session.session_key) def test_login_session_without_hash_session_key(self): @@ -721,7 +846,7 @@ class LoginTest(AuthViewsTestCase): Session without django.contrib.auth.HASH_SESSION_KEY should login without an exception. """ - user = User.objects.get(username='testclient') + user = User.objects.get(username="testclient") engine = import_module(settings.SESSION_ENGINE) session = engine.SessionStore() session[SESSION_KEY] = user.id @@ -733,106 +858,111 @@ class LoginTest(AuthViewsTestCase): self.assertNotEqual(original_session_key, self.client.session.session_key) def test_login_get_default_redirect_url(self): - response = self.login(url='/login/get_default_redirect_url/') - self.assertRedirects(response, '/custom/', fetch_redirect_response=False) + response = self.login(url="/login/get_default_redirect_url/") + self.assertRedirects(response, "/custom/", fetch_redirect_response=False) def test_login_next_page(self): - response = self.login(url='/login/next_page/') - self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False) + response = self.login(url="/login/next_page/") + self.assertRedirects(response, "/somewhere/", fetch_redirect_response=False) def test_login_named_next_page_named(self): - response = self.login(url='/login/next_page/named/') - self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False) + response = self.login(url="/login/next_page/named/") + self.assertRedirects( + response, "/password_reset/", fetch_redirect_response=False + ) - @override_settings(LOGIN_REDIRECT_URL='/custom/') + @override_settings(LOGIN_REDIRECT_URL="/custom/") def test_login_next_page_overrides_login_redirect_url_setting(self): - response = self.login(url='/login/next_page/') - self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False) + response = self.login(url="/login/next_page/") + self.assertRedirects(response, "/somewhere/", fetch_redirect_response=False) def test_login_redirect_url_overrides_next_page(self): - response = self.login(url='/login/next_page/?next=/test/') - self.assertRedirects(response, '/test/', fetch_redirect_response=False) + response = self.login(url="/login/next_page/?next=/test/") + self.assertRedirects(response, "/test/", fetch_redirect_response=False) def test_login_redirect_url_overrides_get_default_redirect_url(self): - response = self.login(url='/login/get_default_redirect_url/?next=/test/') - self.assertRedirects(response, '/test/', fetch_redirect_response=False) + response = self.login(url="/login/get_default_redirect_url/?next=/test/") + self.assertRedirects(response, "/test/", fetch_redirect_response=False) class LoginURLSettings(AuthViewsTestCase): """Tests for settings.LOGIN_URL.""" + def assertLoginURLEquals(self, url): - response = self.client.get('/login_required/') + response = self.client.get("/login_required/") self.assertRedirects(response, url, fetch_redirect_response=False) - @override_settings(LOGIN_URL='/login/') + @override_settings(LOGIN_URL="/login/") def test_standard_login_url(self): - self.assertLoginURLEquals('/login/?next=/login_required/') + self.assertLoginURLEquals("/login/?next=/login_required/") - @override_settings(LOGIN_URL='login') + @override_settings(LOGIN_URL="login") def test_named_login_url(self): - self.assertLoginURLEquals('/login/?next=/login_required/') + self.assertLoginURLEquals("/login/?next=/login_required/") - @override_settings(LOGIN_URL='http://remote.example.com/login') + @override_settings(LOGIN_URL="http://remote.example.com/login") def test_remote_login_url(self): - quoted_next = quote('http://testserver/login_required/') - expected = 'http://remote.example.com/login?next=%s' % quoted_next + quoted_next = quote("http://testserver/login_required/") + expected = "http://remote.example.com/login?next=%s" % quoted_next self.assertLoginURLEquals(expected) - @override_settings(LOGIN_URL='https:///login/') + @override_settings(LOGIN_URL="https:///login/") def test_https_login_url(self): - quoted_next = quote('http://testserver/login_required/') - expected = 'https:///login/?next=%s' % quoted_next + quoted_next = quote("http://testserver/login_required/") + expected = "https:///login/?next=%s" % quoted_next self.assertLoginURLEquals(expected) - @override_settings(LOGIN_URL='/login/?pretty=1') + @override_settings(LOGIN_URL="/login/?pretty=1") def test_login_url_with_querystring(self): - self.assertLoginURLEquals('/login/?pretty=1&next=/login_required/') + self.assertLoginURLEquals("/login/?pretty=1&next=/login_required/") - @override_settings(LOGIN_URL='http://remote.example.com/login/?next=/default/') + @override_settings(LOGIN_URL="http://remote.example.com/login/?next=/default/") def test_remote_login_url_with_next_querystring(self): - quoted_next = quote('http://testserver/login_required/') - expected = 'http://remote.example.com/login/?next=%s' % quoted_next + quoted_next = quote("http://testserver/login_required/") + expected = "http://remote.example.com/login/?next=%s" % quoted_next self.assertLoginURLEquals(expected) - @override_settings(LOGIN_URL=reverse_lazy('login')) + @override_settings(LOGIN_URL=reverse_lazy("login")) def test_lazy_login_url(self): - self.assertLoginURLEquals('/login/?next=/login_required/') + self.assertLoginURLEquals("/login/?next=/login_required/") class LoginRedirectUrlTest(AuthViewsTestCase): """Tests for settings.LOGIN_REDIRECT_URL.""" + def assertLoginRedirectURLEqual(self, url): response = self.login() self.assertRedirects(response, url, fetch_redirect_response=False) def test_default(self): - self.assertLoginRedirectURLEqual('/accounts/profile/') + self.assertLoginRedirectURLEqual("/accounts/profile/") - @override_settings(LOGIN_REDIRECT_URL='/custom/') + @override_settings(LOGIN_REDIRECT_URL="/custom/") def test_custom(self): - self.assertLoginRedirectURLEqual('/custom/') + self.assertLoginRedirectURLEqual("/custom/") - @override_settings(LOGIN_REDIRECT_URL='password_reset') + @override_settings(LOGIN_REDIRECT_URL="password_reset") def test_named(self): - self.assertLoginRedirectURLEqual('/password_reset/') + self.assertLoginRedirectURLEqual("/password_reset/") - @override_settings(LOGIN_REDIRECT_URL='http://remote.example.com/welcome/') + @override_settings(LOGIN_REDIRECT_URL="http://remote.example.com/welcome/") def test_remote(self): - self.assertLoginRedirectURLEqual('http://remote.example.com/welcome/') + self.assertLoginRedirectURLEqual("http://remote.example.com/welcome/") class RedirectToLoginTests(AuthViewsTestCase): """Tests for the redirect_to_login view""" - @override_settings(LOGIN_URL=reverse_lazy('login')) + + @override_settings(LOGIN_URL=reverse_lazy("login")) def test_redirect_to_login_with_lazy(self): - login_redirect_response = redirect_to_login(next='/else/where/') - expected = '/login/?next=/else/where/' + login_redirect_response = redirect_to_login(next="/else/where/") + expected = "/login/?next=/else/where/" self.assertEqual(expected, login_redirect_response.url) - @override_settings(LOGIN_URL=reverse_lazy('login')) + @override_settings(LOGIN_URL=reverse_lazy("login")) def test_redirect_to_login_with_lazy_and_unicode(self): - login_redirect_response = redirect_to_login(next='/else/where/झ/') - expected = '/login/?next=/else/where/%E0%A4%9D/' + login_redirect_response = redirect_to_login(next="/else/where/झ/") + expected = "/login/?next=/else/where/%E0%A4%9D/" self.assertEqual(expected, login_redirect_response.url) @@ -842,36 +972,36 @@ class LogoutThenLoginTests(AuthViewsTestCase): def confirm_logged_out(self): self.assertNotIn(SESSION_KEY, self.client.session) - @override_settings(LOGIN_URL='/login/') + @override_settings(LOGIN_URL="/login/") def test_default_logout_then_login(self): self.login() req = HttpRequest() - req.method = 'GET' + req.method = "GET" req.session = self.client.session response = logout_then_login(req) self.confirm_logged_out() - self.assertRedirects(response, '/login/', fetch_redirect_response=False) + self.assertRedirects(response, "/login/", fetch_redirect_response=False) def test_logout_then_login_with_custom_login(self): self.login() req = HttpRequest() - req.method = 'GET' + req.method = "GET" req.session = self.client.session - response = logout_then_login(req, login_url='/custom/') + response = logout_then_login(req, login_url="/custom/") self.confirm_logged_out() - self.assertRedirects(response, '/custom/', fetch_redirect_response=False) + self.assertRedirects(response, "/custom/", fetch_redirect_response=False) class LoginRedirectAuthenticatedUser(AuthViewsTestCase): - dont_redirect_url = '/login/redirect_authenticated_user_default/' - do_redirect_url = '/login/redirect_authenticated_user/' + dont_redirect_url = "/login/redirect_authenticated_user_default/" + do_redirect_url = "/login/redirect_authenticated_user/" def test_default(self): """Stay on the login page by default.""" self.login() response = self.client.get(self.dont_redirect_url) self.assertEqual(response.status_code, 200) - self.assertEqual(response.context['next'], '') + self.assertEqual(response.context["next"], "") def test_guest(self): """If not logged in, stay on the same page.""" @@ -882,21 +1012,23 @@ class LoginRedirectAuthenticatedUser(AuthViewsTestCase): """If logged in, go to default redirected URL.""" self.login() response = self.client.get(self.do_redirect_url) - self.assertRedirects(response, '/accounts/profile/', fetch_redirect_response=False) + self.assertRedirects( + response, "/accounts/profile/", fetch_redirect_response=False + ) - @override_settings(LOGIN_REDIRECT_URL='/custom/') + @override_settings(LOGIN_REDIRECT_URL="/custom/") def test_redirect_url(self): """If logged in, go to custom redirected URL.""" self.login() response = self.client.get(self.do_redirect_url) - self.assertRedirects(response, '/custom/', fetch_redirect_response=False) + self.assertRedirects(response, "/custom/", fetch_redirect_response=False) def test_redirect_param(self): """If next is specified as a GET parameter, go there.""" self.login() - url = self.do_redirect_url + '?next=/custom_next/' + url = self.do_redirect_url + "?next=/custom_next/" response = self.client.get(url) - self.assertRedirects(response, '/custom_next/', fetch_redirect_response=False) + self.assertRedirects(response, "/custom_next/", fetch_redirect_response=False) def test_redirect_loop(self): """ @@ -912,7 +1044,7 @@ class LoginRedirectAuthenticatedUser(AuthViewsTestCase): with self.assertRaisesMessage(ValueError, msg): self.client.get(self.do_redirect_url) - url = self.do_redirect_url + '?bla=2' + url = self.do_redirect_url + "?bla=2" with self.assertRaisesMessage(ValueError, msg): self.client.get(url) @@ -920,13 +1052,15 @@ class LoginRedirectAuthenticatedUser(AuthViewsTestCase): # Not logged in ... with self.settings(LOGIN_URL=self.do_redirect_url): # redirected to login. - response = self.client.get('/permission_required_redirect/', follow=True) + response = self.client.get("/permission_required_redirect/", follow=True) self.assertEqual(response.status_code, 200) # exception raised. - response = self.client.get('/permission_required_exception/', follow=True) + response = self.client.get("/permission_required_exception/", follow=True) self.assertEqual(response.status_code, 403) # redirected to login. - response = self.client.get('/login_and_permission_required_exception/', follow=True) + response = self.client.get( + "/login_and_permission_required_exception/", follow=True + ) self.assertEqual(response.status_code, 200) def test_permission_required_logged_in(self): @@ -934,191 +1068,219 @@ class LoginRedirectAuthenticatedUser(AuthViewsTestCase): # Already logged in... with self.settings(LOGIN_URL=self.do_redirect_url): # redirect loop encountered. - with self.assertRaisesMessage(RedirectCycleError, 'Redirect loop detected.'): - self.client.get('/permission_required_redirect/', follow=True) + with self.assertRaisesMessage( + RedirectCycleError, "Redirect loop detected." + ): + self.client.get("/permission_required_redirect/", follow=True) # exception raised. - response = self.client.get('/permission_required_exception/', follow=True) + response = self.client.get("/permission_required_exception/", follow=True) self.assertEqual(response.status_code, 403) # exception raised. - response = self.client.get('/login_and_permission_required_exception/', follow=True) + response = self.client.get( + "/login_and_permission_required_exception/", follow=True + ) self.assertEqual(response.status_code, 403) class LoginSuccessURLAllowedHostsTest(AuthViewsTestCase): def test_success_url_allowed_hosts_same_host(self): - response = self.client.post('/login/allowed_hosts/', { - 'username': 'testclient', - 'password': 'password', - 'next': 'https://testserver/home', - }) + response = self.client.post( + "/login/allowed_hosts/", + { + "username": "testclient", + "password": "password", + "next": "https://testserver/home", + }, + ) self.assertIn(SESSION_KEY, self.client.session) - self.assertRedirects(response, 'https://testserver/home', fetch_redirect_response=False) + self.assertRedirects( + response, "https://testserver/home", fetch_redirect_response=False + ) def test_success_url_allowed_hosts_safe_host(self): - response = self.client.post('/login/allowed_hosts/', { - 'username': 'testclient', - 'password': 'password', - 'next': 'https://otherserver/home', - }) + response = self.client.post( + "/login/allowed_hosts/", + { + "username": "testclient", + "password": "password", + "next": "https://otherserver/home", + }, + ) self.assertIn(SESSION_KEY, self.client.session) - self.assertRedirects(response, 'https://otherserver/home', fetch_redirect_response=False) + self.assertRedirects( + response, "https://otherserver/home", fetch_redirect_response=False + ) def test_success_url_allowed_hosts_unsafe_host(self): - response = self.client.post('/login/allowed_hosts/', { - 'username': 'testclient', - 'password': 'password', - 'next': 'https://evil/home', - }) + response = self.client.post( + "/login/allowed_hosts/", + { + "username": "testclient", + "password": "password", + "next": "https://evil/home", + }, + ) self.assertIn(SESSION_KEY, self.client.session) - self.assertRedirects(response, '/accounts/profile/', fetch_redirect_response=False) + self.assertRedirects( + response, "/accounts/profile/", fetch_redirect_response=False + ) class LogoutTest(AuthViewsTestCase): - def confirm_logged_out(self): self.assertNotIn(SESSION_KEY, self.client.session) def test_logout_default(self): "Logout without next_page option renders the default template" self.login() - response = self.client.get('/logout/') - self.assertContains(response, 'Logged out') + response = self.client.get("/logout/") + self.assertContains(response, "Logged out") self.confirm_logged_out() def test_logout_with_post(self): self.login() - response = self.client.post('/logout/') - self.assertContains(response, 'Logged out') + response = self.client.post("/logout/") + self.assertContains(response, "Logged out") self.confirm_logged_out() def test_14377(self): # Bug 14377 self.login() - response = self.client.get('/logout/') - self.assertIn('site', response.context) + response = self.client.get("/logout/") + self.assertIn("site", response.context) def test_logout_doesnt_cache(self): """ The logout() view should send "no-cache" headers for reasons described in #25490. """ - response = self.client.get('/logout/') - self.assertIn('no-store', response.headers['Cache-Control']) + response = self.client.get("/logout/") + self.assertIn("no-store", response.headers["Cache-Control"]) def test_logout_with_overridden_redirect_url(self): # Bug 11223 self.login() - response = self.client.get('/logout/next_page/') - self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False) + response = self.client.get("/logout/next_page/") + self.assertRedirects(response, "/somewhere/", fetch_redirect_response=False) - response = self.client.get('/logout/next_page/?next=/login/') - self.assertRedirects(response, '/login/', fetch_redirect_response=False) + response = self.client.get("/logout/next_page/?next=/login/") + self.assertRedirects(response, "/login/", fetch_redirect_response=False) self.confirm_logged_out() def test_logout_with_next_page_specified(self): "Logout with next_page option given redirects to specified resource" self.login() - response = self.client.get('/logout/next_page/') - self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False) + response = self.client.get("/logout/next_page/") + self.assertRedirects(response, "/somewhere/", fetch_redirect_response=False) self.confirm_logged_out() def test_logout_with_redirect_argument(self): "Logout with query string redirects to specified resource" self.login() - response = self.client.get('/logout/?next=/login/') - self.assertRedirects(response, '/login/', fetch_redirect_response=False) + response = self.client.get("/logout/?next=/login/") + self.assertRedirects(response, "/login/", fetch_redirect_response=False) self.confirm_logged_out() def test_logout_with_custom_redirect_argument(self): "Logout with custom query string redirects to specified resource" self.login() - response = self.client.get('/logout/custom_query/?follow=/somewhere/') - self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False) + response = self.client.get("/logout/custom_query/?follow=/somewhere/") + self.assertRedirects(response, "/somewhere/", fetch_redirect_response=False) self.confirm_logged_out() def test_logout_with_named_redirect(self): "Logout resolves names or URLs passed as next_page." self.login() - response = self.client.get('/logout/next_page/named/') - self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False) + response = self.client.get("/logout/next_page/named/") + self.assertRedirects( + response, "/password_reset/", fetch_redirect_response=False + ) self.confirm_logged_out() def test_success_url_allowed_hosts_same_host(self): self.login() - response = self.client.get('/logout/allowed_hosts/?next=https://testserver/') - self.assertRedirects(response, 'https://testserver/', fetch_redirect_response=False) + response = self.client.get("/logout/allowed_hosts/?next=https://testserver/") + self.assertRedirects( + response, "https://testserver/", fetch_redirect_response=False + ) self.confirm_logged_out() def test_success_url_allowed_hosts_safe_host(self): self.login() - response = self.client.get('/logout/allowed_hosts/?next=https://otherserver/') - self.assertRedirects(response, 'https://otherserver/', fetch_redirect_response=False) + response = self.client.get("/logout/allowed_hosts/?next=https://otherserver/") + self.assertRedirects( + response, "https://otherserver/", fetch_redirect_response=False + ) self.confirm_logged_out() def test_success_url_allowed_hosts_unsafe_host(self): self.login() - response = self.client.get('/logout/allowed_hosts/?next=https://evil/') - self.assertRedirects(response, '/logout/allowed_hosts/', fetch_redirect_response=False) + response = self.client.get("/logout/allowed_hosts/?next=https://evil/") + self.assertRedirects( + response, "/logout/allowed_hosts/", fetch_redirect_response=False + ) self.confirm_logged_out() def test_security_check(self): - logout_url = reverse('logout') + logout_url = reverse("logout") # These URLs should not pass the security check. bad_urls = ( - 'http://example.com', - 'http:///example.com', - 'https://example.com', - 'ftp://example.com', - '///example.com', - '//example.com', + "http://example.com", + "http:///example.com", + "https://example.com", + "ftp://example.com", + "///example.com", + "//example.com", 'javascript:alert("XSS")', ) for bad_url in bad_urls: with self.subTest(bad_url=bad_url): - nasty_url = '%(url)s?%(next)s=%(bad_url)s' % { - 'url': logout_url, - 'next': REDIRECT_FIELD_NAME, - 'bad_url': quote(bad_url), + nasty_url = "%(url)s?%(next)s=%(bad_url)s" % { + "url": logout_url, + "next": REDIRECT_FIELD_NAME, + "bad_url": quote(bad_url), } self.login() response = self.client.get(nasty_url) self.assertEqual(response.status_code, 302) - self.assertNotIn(bad_url, response.url, '%s should be blocked' % bad_url) + self.assertNotIn( + bad_url, response.url, "%s should be blocked" % bad_url + ) self.confirm_logged_out() # These URLs should pass the security check. good_urls = ( - '/view/?param=http://example.com', - '/view/?param=https://example.com', - '/view?param=ftp://example.com', - 'view/?param=//example.com', - 'https://testserver/', - 'HTTPS://testserver/', - '//testserver/', - '/url%20with%20spaces/', + "/view/?param=http://example.com", + "/view/?param=https://example.com", + "/view?param=ftp://example.com", + "view/?param=//example.com", + "https://testserver/", + "HTTPS://testserver/", + "//testserver/", + "/url%20with%20spaces/", ) for good_url in good_urls: with self.subTest(good_url=good_url): - safe_url = '%(url)s?%(next)s=%(good_url)s' % { - 'url': logout_url, - 'next': REDIRECT_FIELD_NAME, - 'good_url': quote(good_url), + safe_url = "%(url)s?%(next)s=%(good_url)s" % { + "url": logout_url, + "next": REDIRECT_FIELD_NAME, + "good_url": quote(good_url), } self.login() response = self.client.get(safe_url) self.assertEqual(response.status_code, 302) - self.assertIn(good_url, response.url, '%s should be allowed' % good_url) + self.assertIn(good_url, response.url, "%s should be allowed" % good_url) self.confirm_logged_out() def test_security_check_https(self): - logout_url = reverse('logout') - non_https_next_url = 'http://testserver/' - url = '%(url)s?%(next)s=%(next_url)s' % { - 'url': logout_url, - 'next': REDIRECT_FIELD_NAME, - 'next_url': quote(non_https_next_url), + logout_url = reverse("logout") + non_https_next_url = "http://testserver/" + url = "%(url)s?%(next)s=%(next_url)s" % { + "url": logout_url, + "next": REDIRECT_FIELD_NAME, + "next_url": quote(non_https_next_url), } self.login() response = self.client.get(url, secure=True) @@ -1128,22 +1290,22 @@ class LogoutTest(AuthViewsTestCase): def test_logout_preserve_language(self): """Language is preserved after logout.""" self.login() - self.client.post('/setlang/', {'language': 'pl'}) - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, 'pl') - self.client.get('/logout/') - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, 'pl') + self.client.post("/setlang/", {"language": "pl"}) + self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, "pl") + self.client.get("/logout/") + self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, "pl") - @override_settings(LOGOUT_REDIRECT_URL='/custom/') + @override_settings(LOGOUT_REDIRECT_URL="/custom/") def test_logout_redirect_url_setting(self): self.login() - response = self.client.get('/logout/') - self.assertRedirects(response, '/custom/', fetch_redirect_response=False) + response = self.client.get("/logout/") + self.assertRedirects(response, "/custom/", fetch_redirect_response=False) - @override_settings(LOGOUT_REDIRECT_URL='logout') + @override_settings(LOGOUT_REDIRECT_URL="logout") def test_logout_redirect_url_named_setting(self): self.login() - response = self.client.get('/logout/') - self.assertRedirects(response, '/logout/', fetch_redirect_response=False) + response = self.client.get("/logout/") + self.assertRedirects(response, "/logout/", fetch_redirect_response=False) def get_perm(Model, perm): @@ -1153,14 +1315,15 @@ def get_perm(Model, perm): # Redirect in test_user_change_password will fail if session auth hash # isn't updated after password change (#21649) -@override_settings(ROOT_URLCONF='auth_tests.urls_admin') +@override_settings(ROOT_URLCONF="auth_tests.urls_admin") class ChangelistTests(AuthViewsTestCase): - @classmethod def setUpTestData(cls): super().setUpTestData() # Make me a superuser before logging in. - User.objects.filter(username='testclient').update(is_staff=True, is_superuser=True) + User.objects.filter(username="testclient").update( + is_staff=True, is_superuser=True + ) def setUp(self): self.login() @@ -1169,126 +1332,145 @@ class ChangelistTests(AuthViewsTestCase): def get_user_data(self, user): return { - 'username': user.username, - 'password': user.password, - 'email': user.email, - 'is_active': user.is_active, - 'is_staff': user.is_staff, - 'is_superuser': user.is_superuser, - 'last_login_0': user.last_login.strftime('%Y-%m-%d'), - 'last_login_1': user.last_login.strftime('%H:%M:%S'), - 'initial-last_login_0': user.last_login.strftime('%Y-%m-%d'), - 'initial-last_login_1': user.last_login.strftime('%H:%M:%S'), - 'date_joined_0': user.date_joined.strftime('%Y-%m-%d'), - 'date_joined_1': user.date_joined.strftime('%H:%M:%S'), - 'initial-date_joined_0': user.date_joined.strftime('%Y-%m-%d'), - 'initial-date_joined_1': user.date_joined.strftime('%H:%M:%S'), - 'first_name': user.first_name, - 'last_name': user.last_name, + "username": user.username, + "password": user.password, + "email": user.email, + "is_active": user.is_active, + "is_staff": user.is_staff, + "is_superuser": user.is_superuser, + "last_login_0": user.last_login.strftime("%Y-%m-%d"), + "last_login_1": user.last_login.strftime("%H:%M:%S"), + "initial-last_login_0": user.last_login.strftime("%Y-%m-%d"), + "initial-last_login_1": user.last_login.strftime("%H:%M:%S"), + "date_joined_0": user.date_joined.strftime("%Y-%m-%d"), + "date_joined_1": user.date_joined.strftime("%H:%M:%S"), + "initial-date_joined_0": user.date_joined.strftime("%Y-%m-%d"), + "initial-date_joined_1": user.date_joined.strftime("%H:%M:%S"), + "first_name": user.first_name, + "last_name": user.last_name, } # #20078 - users shouldn't be allowed to guess password hashes via # repeated password__startswith queries. def test_changelist_disallows_password_lookups(self): # A lookup that tries to filter on password isn't OK - with self.assertLogs('django.security.DisallowedModelAdminLookup', 'ERROR'): - response = self.client.get(reverse('auth_test_admin:auth_user_changelist') + '?password__startswith=sha1$') + with self.assertLogs("django.security.DisallowedModelAdminLookup", "ERROR"): + response = self.client.get( + reverse("auth_test_admin:auth_user_changelist") + + "?password__startswith=sha1$" + ) self.assertEqual(response.status_code, 400) def test_user_change_email(self): data = self.get_user_data(self.admin) - data['email'] = 'new_' + data['email'] + data["email"] = "new_" + data["email"] response = self.client.post( - reverse('auth_test_admin:auth_user_change', args=(self.admin.pk,)), - data + reverse("auth_test_admin:auth_user_change", args=(self.admin.pk,)), data ) - self.assertRedirects(response, reverse('auth_test_admin:auth_user_changelist')) - row = LogEntry.objects.latest('id') - self.assertEqual(row.get_change_message(), 'Changed Email address.') + self.assertRedirects(response, reverse("auth_test_admin:auth_user_changelist")) + row = LogEntry.objects.latest("id") + self.assertEqual(row.get_change_message(), "Changed Email address.") def test_user_not_change(self): response = self.client.post( - reverse('auth_test_admin:auth_user_change', args=(self.admin.pk,)), - self.get_user_data(self.admin) + reverse("auth_test_admin:auth_user_change", args=(self.admin.pk,)), + self.get_user_data(self.admin), ) - self.assertRedirects(response, reverse('auth_test_admin:auth_user_changelist')) - row = LogEntry.objects.latest('id') - self.assertEqual(row.get_change_message(), 'No fields changed.') + self.assertRedirects(response, reverse("auth_test_admin:auth_user_changelist")) + row = LogEntry.objects.latest("id") + self.assertEqual(row.get_change_message(), "No fields changed.") def test_user_change_password(self): - user_change_url = reverse('auth_test_admin:auth_user_change', args=(self.admin.pk,)) - password_change_url = reverse('auth_test_admin:auth_user_password_change', args=(self.admin.pk,)) + user_change_url = reverse( + "auth_test_admin:auth_user_change", args=(self.admin.pk,) + ) + password_change_url = reverse( + "auth_test_admin:auth_user_password_change", args=(self.admin.pk,) + ) response = self.client.get(user_change_url) # Test the link inside password field help_text. rel_link = re.search( r'you can change the password using <a href="([^"]*)">this form</a>', - response.content.decode() + response.content.decode(), )[1] self.assertEqual(urljoin(user_change_url, rel_link), password_change_url) response = self.client.post( password_change_url, { - 'password1': 'password1', - 'password2': 'password1', - } + "password1": "password1", + "password2": "password1", + }, ) self.assertRedirects(response, user_change_url) - row = LogEntry.objects.latest('id') - self.assertEqual(row.get_change_message(), 'Changed password.') + row = LogEntry.objects.latest("id") + self.assertEqual(row.get_change_message(), "Changed password.") self.logout() - self.login(password='password1') + self.login(password="password1") def test_user_change_different_user_password(self): - u = User.objects.get(email='staffmember@example.com') + u = User.objects.get(email="staffmember@example.com") response = self.client.post( - reverse('auth_test_admin:auth_user_password_change', args=(u.pk,)), + reverse("auth_test_admin:auth_user_password_change", args=(u.pk,)), { - 'password1': 'password1', - 'password2': 'password1', - } + "password1": "password1", + "password2": "password1", + }, + ) + self.assertRedirects( + response, reverse("auth_test_admin:auth_user_change", args=(u.pk,)) ) - self.assertRedirects(response, reverse('auth_test_admin:auth_user_change', args=(u.pk,))) - row = LogEntry.objects.latest('id') + row = LogEntry.objects.latest("id") self.assertEqual(row.user_id, self.admin.pk) self.assertEqual(row.object_id, str(u.pk)) - self.assertEqual(row.get_change_message(), 'Changed password.') + self.assertEqual(row.get_change_message(), "Changed password.") def test_password_change_bad_url(self): - response = self.client.get(reverse('auth_test_admin:auth_user_password_change', args=('foobar',))) + response = self.client.get( + reverse("auth_test_admin:auth_user_password_change", args=("foobar",)) + ) self.assertEqual(response.status_code, 404) - @mock.patch('django.contrib.auth.admin.UserAdmin.has_change_permission') - def test_user_change_password_passes_user_to_has_change_permission(self, has_change_permission): - url = reverse('auth_test_admin:auth_user_password_change', args=(self.admin.pk,)) - self.client.post(url, {'password1': 'password1', 'password2': 'password1'}) + @mock.patch("django.contrib.auth.admin.UserAdmin.has_change_permission") + def test_user_change_password_passes_user_to_has_change_permission( + self, has_change_permission + ): + url = reverse( + "auth_test_admin:auth_user_password_change", args=(self.admin.pk,) + ) + self.client.post(url, {"password1": "password1", "password2": "password1"}) (_request, user), _kwargs = has_change_permission.call_args self.assertEqual(user.pk, self.admin.pk) def test_view_user_password_is_readonly(self): - u = User.objects.get(username='testclient') + u = User.objects.get(username="testclient") u.is_superuser = False u.save() original_password = u.password - u.user_permissions.add(get_perm(User, 'view_user')) - response = self.client.get(reverse('auth_test_admin:auth_user_change', args=(u.pk,)),) - algo, salt, hash_string = (u.password.split('$')) + u.user_permissions.add(get_perm(User, "view_user")) + response = self.client.get( + reverse("auth_test_admin:auth_user_change", args=(u.pk,)), + ) + algo, salt, hash_string = u.password.split("$") self.assertContains(response, '<div class="readonly">testclient</div>') # ReadOnlyPasswordHashWidget is used to render the field. self.assertContains( response, - '<strong>algorithm</strong>: %s\n\n' - '<strong>salt</strong>: %s********************\n\n' - '<strong>hash</strong>: %s**************************\n\n' % ( - algo, salt[:2], hash_string[:6], + "<strong>algorithm</strong>: %s\n\n" + "<strong>salt</strong>: %s********************\n\n" + "<strong>hash</strong>: %s**************************\n\n" + % ( + algo, + salt[:2], + hash_string[:6], ), html=True, ) # Value in POST data is ignored. data = self.get_user_data(u) - data['password'] = 'shouldnotchange' - change_url = reverse('auth_test_admin:auth_user_change', args=(u.pk,)) + data["password"] = "shouldnotchange" + change_url = reverse("auth_test_admin:auth_user_change", args=(u.pk,)) response = self.client.post(change_url, data) self.assertEqual(response.status_code, 403) u.refresh_from_db() @@ -1296,35 +1478,43 @@ class ChangelistTests(AuthViewsTestCase): @override_settings( - AUTH_USER_MODEL='auth_tests.UUIDUser', - ROOT_URLCONF='auth_tests.urls_custom_user_admin', + AUTH_USER_MODEL="auth_tests.UUIDUser", + ROOT_URLCONF="auth_tests.urls_custom_user_admin", ) class UUIDUserTests(TestCase): - def test_admin_password_change(self): - u = UUIDUser.objects.create_superuser(username='uuid', email='foo@bar.com', password='test') - self.assertTrue(self.client.login(username='uuid', password='test')) + u = UUIDUser.objects.create_superuser( + username="uuid", email="foo@bar.com", password="test" + ) + self.assertTrue(self.client.login(username="uuid", password="test")) - user_change_url = reverse('custom_user_admin:auth_tests_uuiduser_change', args=(u.pk,)) + user_change_url = reverse( + "custom_user_admin:auth_tests_uuiduser_change", args=(u.pk,) + ) response = self.client.get(user_change_url) self.assertEqual(response.status_code, 200) - password_change_url = reverse('custom_user_admin:auth_user_password_change', args=(u.pk,)) + password_change_url = reverse( + "custom_user_admin:auth_user_password_change", args=(u.pk,) + ) response = self.client.get(password_change_url) # The action attribute is omitted. self.assertContains(response, '<form method="post" id="uuiduser_form">') # A LogEntry is created with pk=1 which breaks a FK constraint on MySQL with connection.constraint_checks_disabled(): - response = self.client.post(password_change_url, { - 'password1': 'password1', - 'password2': 'password1', - }) + response = self.client.post( + password_change_url, + { + "password1": "password1", + "password2": "password1", + }, + ) self.assertRedirects(response, user_change_url) - row = LogEntry.objects.latest('id') + row = LogEntry.objects.latest("id") self.assertEqual(row.user_id, 1) # hardcoded in CustomUserAdmin.log_change() self.assertEqual(row.object_id, str(u.pk)) - self.assertEqual(row.get_change_message(), 'Changed password.') + self.assertEqual(row.get_change_message(), "Changed password.") # The LogEntry.user column isn't altered to a UUID type so it's set to # an integer manually in CustomUserAdmin to avoid an error. To avoid a diff --git a/tests/auth_tests/urls.py b/tests/auth_tests/urls.py index 70857e866a..9f8cd14bdd 100644 --- a/tests/auth_tests/urls.py +++ b/tests/auth_tests/urls.py @@ -28,143 +28,175 @@ def remote_user_auth_view(request): def auth_processor_no_attr_access(request): - render(request, 'context_processors/auth_attrs_no_access.html') + render(request, "context_processors/auth_attrs_no_access.html") # *After* rendering, we check whether the session was accessed - return render(request, - 'context_processors/auth_attrs_test_access.html', - {'session_accessed': request.session.accessed}) + return render( + request, + "context_processors/auth_attrs_test_access.html", + {"session_accessed": request.session.accessed}, + ) def auth_processor_attr_access(request): - render(request, 'context_processors/auth_attrs_access.html') - return render(request, - 'context_processors/auth_attrs_test_access.html', - {'session_accessed': request.session.accessed}) + render(request, "context_processors/auth_attrs_access.html") + return render( + request, + "context_processors/auth_attrs_test_access.html", + {"session_accessed": request.session.accessed}, + ) def auth_processor_user(request): - return render(request, 'context_processors/auth_attrs_user.html') + return render(request, "context_processors/auth_attrs_user.html") def auth_processor_perms(request): - return render(request, 'context_processors/auth_attrs_perms.html') + return render(request, "context_processors/auth_attrs_perms.html") def auth_processor_perm_in_perms(request): - return render(request, 'context_processors/auth_attrs_perm_in_perms.html') + return render(request, "context_processors/auth_attrs_perm_in_perms.html") def auth_processor_messages(request): info(request, "Message 1") - return render(request, 'context_processors/auth_attrs_messages.html') + return render(request, "context_processors/auth_attrs_messages.html") def userpage(request): pass -@permission_required('unknown.permission') +@permission_required("unknown.permission") def permission_required_redirect(request): pass -@permission_required('unknown.permission', raise_exception=True) +@permission_required("unknown.permission", raise_exception=True) def permission_required_exception(request): pass @login_required -@permission_required('unknown.permission', raise_exception=True) +@permission_required("unknown.permission", raise_exception=True) def login_and_permission_required_exception(request): pass class CustomDefaultRedirectURLLoginView(LoginView): def get_default_redirect_url(self): - return '/custom/' + return "/custom/" # special urls for auth test cases urlpatterns = auth_urlpatterns + [ - path('logout/custom_query/', views.LogoutView.as_view(redirect_field_name='follow')), - path('logout/next_page/', views.LogoutView.as_view(next_page='/somewhere/')), - path('logout/next_page/named/', views.LogoutView.as_view(next_page='password_reset')), - path('logout/allowed_hosts/', views.LogoutView.as_view(success_url_allowed_hosts={'otherserver'})), - path('remote_user/', remote_user_auth_view), - - path('password_reset_from_email/', views.PasswordResetView.as_view(from_email='staffmember@example.com')), path( - 'password_reset_extra_email_context/', + "logout/custom_query/", views.LogoutView.as_view(redirect_field_name="follow") + ), + path("logout/next_page/", views.LogoutView.as_view(next_page="/somewhere/")), + path( + "logout/next_page/named/", views.LogoutView.as_view(next_page="password_reset") + ), + path( + "logout/allowed_hosts/", + views.LogoutView.as_view(success_url_allowed_hosts={"otherserver"}), + ), + path("remote_user/", remote_user_auth_view), + path( + "password_reset_from_email/", + views.PasswordResetView.as_view(from_email="staffmember@example.com"), + ), + path( + "password_reset_extra_email_context/", views.PasswordResetView.as_view( - extra_email_context={'greeting': 'Hello!', 'domain': 'custom.example.com'}, + extra_email_context={"greeting": "Hello!", "domain": "custom.example.com"}, ), ), path( - 'password_reset/custom_redirect/', - views.PasswordResetView.as_view(success_url='/custom/')), + "password_reset/custom_redirect/", + views.PasswordResetView.as_view(success_url="/custom/"), + ), path( - 'password_reset/custom_redirect/named/', - views.PasswordResetView.as_view(success_url=reverse_lazy('password_reset'))), + "password_reset/custom_redirect/named/", + views.PasswordResetView.as_view(success_url=reverse_lazy("password_reset")), + ), path( - 'password_reset/html_email_template/', + "password_reset/html_email_template/", views.PasswordResetView.as_view( - html_email_template_name='registration/html_password_reset_email.html' - )), + html_email_template_name="registration/html_password_reset_email.html" + ), + ), path( - 'reset/custom/<uidb64>/<token>/', - views.PasswordResetConfirmView.as_view(success_url='/custom/'), + "reset/custom/<uidb64>/<token>/", + views.PasswordResetConfirmView.as_view(success_url="/custom/"), ), path( - 'reset/custom/named/<uidb64>/<token>/', - views.PasswordResetConfirmView.as_view(success_url=reverse_lazy('password_reset')), + "reset/custom/named/<uidb64>/<token>/", + views.PasswordResetConfirmView.as_view( + success_url=reverse_lazy("password_reset") + ), ), path( - 'reset/custom/token/<uidb64>/<token>/', - views.PasswordResetConfirmView.as_view(reset_url_token='set-passwordcustom'), + "reset/custom/token/<uidb64>/<token>/", + views.PasswordResetConfirmView.as_view(reset_url_token="set-passwordcustom"), ), path( - 'reset/post_reset_login/<uidb64>/<token>/', + "reset/post_reset_login/<uidb64>/<token>/", views.PasswordResetConfirmView.as_view(post_reset_login=True), ), path( - 'reset/post_reset_login_custom_backend/<uidb64>/<token>/', + "reset/post_reset_login_custom_backend/<uidb64>/<token>/", views.PasswordResetConfirmView.as_view( post_reset_login=True, - post_reset_login_backend='django.contrib.auth.backends.AllowAllUsersModelBackend', + post_reset_login_backend="django.contrib.auth.backends.AllowAllUsersModelBackend", ), ), - path('reset/missing_parameters/', views.PasswordResetConfirmView.as_view()), - path('password_change/custom/', - views.PasswordChangeView.as_view(success_url='/custom/')), - path('password_change/custom/named/', - views.PasswordChangeView.as_view(success_url=reverse_lazy('password_reset'))), - path('login_required/', login_required(views.PasswordResetView.as_view())), - path('login_required_login_url/', login_required(views.PasswordResetView.as_view(), login_url='/somewhere/')), - - path('auth_processor_no_attr_access/', auth_processor_no_attr_access), - path('auth_processor_attr_access/', auth_processor_attr_access), - path('auth_processor_user/', auth_processor_user), - path('auth_processor_perms/', auth_processor_perms), - path('auth_processor_perm_in_perms/', auth_processor_perm_in_perms), - path('auth_processor_messages/', auth_processor_messages), - path( - 'custom_request_auth_login/', - views.LoginView.as_view(authentication_form=CustomRequestAuthenticationForm)), - re_path('^userpage/(.+)/$', userpage, name='userpage'), - path('login/redirect_authenticated_user_default/', views.LoginView.as_view()), - path('login/redirect_authenticated_user/', - views.LoginView.as_view(redirect_authenticated_user=True)), - path('login/allowed_hosts/', - views.LoginView.as_view(success_url_allowed_hosts={'otherserver'})), - path('login/get_default_redirect_url/', CustomDefaultRedirectURLLoginView.as_view()), - path('login/next_page/', views.LoginView.as_view(next_page='/somewhere/')), - path('login/next_page/named/', views.LoginView.as_view(next_page='password_reset')), - - path('permission_required_redirect/', permission_required_redirect), - path('permission_required_exception/', permission_required_exception), - path('login_and_permission_required_exception/', login_and_permission_required_exception), - - path('setlang/', set_language, name='set_language'), + path("reset/missing_parameters/", views.PasswordResetConfirmView.as_view()), + path( + "password_change/custom/", + views.PasswordChangeView.as_view(success_url="/custom/"), + ), + path( + "password_change/custom/named/", + views.PasswordChangeView.as_view(success_url=reverse_lazy("password_reset")), + ), + path("login_required/", login_required(views.PasswordResetView.as_view())), + path( + "login_required_login_url/", + login_required(views.PasswordResetView.as_view(), login_url="/somewhere/"), + ), + path("auth_processor_no_attr_access/", auth_processor_no_attr_access), + path("auth_processor_attr_access/", auth_processor_attr_access), + path("auth_processor_user/", auth_processor_user), + path("auth_processor_perms/", auth_processor_perms), + path("auth_processor_perm_in_perms/", auth_processor_perm_in_perms), + path("auth_processor_messages/", auth_processor_messages), + path( + "custom_request_auth_login/", + views.LoginView.as_view(authentication_form=CustomRequestAuthenticationForm), + ), + re_path("^userpage/(.+)/$", userpage, name="userpage"), + path("login/redirect_authenticated_user_default/", views.LoginView.as_view()), + path( + "login/redirect_authenticated_user/", + views.LoginView.as_view(redirect_authenticated_user=True), + ), + path( + "login/allowed_hosts/", + views.LoginView.as_view(success_url_allowed_hosts={"otherserver"}), + ), + path( + "login/get_default_redirect_url/", CustomDefaultRedirectURLLoginView.as_view() + ), + path("login/next_page/", views.LoginView.as_view(next_page="/somewhere/")), + path("login/next_page/named/", views.LoginView.as_view(next_page="password_reset")), + path("permission_required_redirect/", permission_required_redirect), + path("permission_required_exception/", permission_required_exception), + path( + "login_and_permission_required_exception/", + login_and_permission_required_exception, + ), + path("setlang/", set_language, name="set_language"), # This line is only required to render the password reset with is_admin=True - path('admin/', admin.site.urls), + path("admin/", admin.site.urls), ] diff --git a/tests/auth_tests/urls_admin.py b/tests/auth_tests/urls_admin.py index 21b0073210..a606402404 100644 --- a/tests/auth_tests/urls_admin.py +++ b/tests/auth_tests/urls_admin.py @@ -9,10 +9,10 @@ from django.contrib.auth.urls import urlpatterns from django.urls import path # Create a silo'd admin site for just the user/group admins. -site = admin.AdminSite(name='auth_test_admin') +site = admin.AdminSite(name="auth_test_admin") site.register(User, UserAdmin) site.register(Group, GroupAdmin) urlpatterns += [ - path('admin/', site.urls), + path("admin/", site.urls), ] diff --git a/tests/auth_tests/urls_custom_user_admin.py b/tests/auth_tests/urls_custom_user_admin.py index e761662044..1c7ce1eb42 100644 --- a/tests/auth_tests/urls_custom_user_admin.py +++ b/tests/auth_tests/urls_custom_user_admin.py @@ -3,7 +3,7 @@ from django.contrib.auth import get_user_model from django.contrib.auth.admin import UserAdmin from django.urls import path -site = admin.AdminSite(name='custom_user_admin') +site = admin.AdminSite(name="custom_user_admin") class CustomUserAdmin(UserAdmin): @@ -19,5 +19,5 @@ class CustomUserAdmin(UserAdmin): site.register(get_user_model(), CustomUserAdmin) urlpatterns = [ - path('admin/', site.urls), + path("admin/", site.urls), ] |