test_checks.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. from django.contrib.auth.checks import (
  2. check_models_permissions, check_user_model,
  3. )
  4. from django.contrib.auth.models import AbstractBaseUser
  5. from django.core import checks
  6. from django.db import models
  7. from django.test import (
  8. SimpleTestCase, override_settings, override_system_checks,
  9. )
  10. from django.test.utils import isolate_apps
  11. from .models import CustomUserNonUniqueUsername
  12. @isolate_apps('auth_tests', attr_name='apps')
  13. @override_system_checks([check_user_model])
  14. class UserModelChecksTests(SimpleTestCase):
  15. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonListRequiredFields')
  16. def test_required_fields_is_list(self):
  17. """REQUIRED_FIELDS should be a list."""
  18. class CustomUserNonListRequiredFields(AbstractBaseUser):
  19. username = models.CharField(max_length=30, unique=True)
  20. date_of_birth = models.DateField()
  21. USERNAME_FIELD = 'username'
  22. REQUIRED_FIELDS = 'date_of_birth'
  23. errors = checks.run_checks(app_configs=self.apps.get_app_configs())
  24. self.assertEqual(errors, [
  25. checks.Error(
  26. "'REQUIRED_FIELDS' must be a list or tuple.",
  27. obj=CustomUserNonListRequiredFields,
  28. id='auth.E001',
  29. ),
  30. ])
  31. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserBadRequiredFields')
  32. def test_username_not_in_required_fields(self):
  33. """USERNAME_FIELD should not appear in REQUIRED_FIELDS."""
  34. class CustomUserBadRequiredFields(AbstractBaseUser):
  35. username = models.CharField(max_length=30, unique=True)
  36. date_of_birth = models.DateField()
  37. USERNAME_FIELD = 'username'
  38. REQUIRED_FIELDS = ['username', 'date_of_birth']
  39. errors = checks.run_checks(self.apps.get_app_configs())
  40. self.assertEqual(errors, [
  41. checks.Error(
  42. "The field named as the 'USERNAME_FIELD' for a custom user model "
  43. "must not be included in 'REQUIRED_FIELDS'.",
  44. obj=CustomUserBadRequiredFields,
  45. id='auth.E002',
  46. ),
  47. ])
  48. @override_settings(AUTH_USER_MODEL='auth_tests.CustomUserNonUniqueUsername')
  49. def test_username_non_unique(self):
  50. """
  51. A non-unique USERNAME_FIELD raises an error only if the default
  52. authentication backend is used. Otherwise, a warning is raised.
  53. """
  54. errors = checks.run_checks()
  55. self.assertEqual(errors, [
  56. checks.Error(
  57. "'CustomUserNonUniqueUsername.username' must be "
  58. "unique because it is named as the 'USERNAME_FIELD'.",
  59. obj=CustomUserNonUniqueUsername,
  60. id='auth.E003',
  61. ),
  62. ])
  63. with self.settings(AUTHENTICATION_BACKENDS=['my.custom.backend']):
  64. errors = checks.run_checks()
  65. self.assertEqual(errors, [
  66. checks.Warning(
  67. "'CustomUserNonUniqueUsername.username' is named as "
  68. "the 'USERNAME_FIELD', but it is not unique.",
  69. hint='Ensure that your authentication backend(s) can handle non-unique usernames.',
  70. obj=CustomUserNonUniqueUsername,
  71. id='auth.W004',
  72. ),
  73. ])
  74. @override_settings(AUTH_USER_MODEL='auth_tests.BadUser')
  75. def test_is_anonymous_authenticated_methods(self):
  76. """
  77. <User Model>.is_anonymous/is_authenticated must not be methods.
  78. """
  79. class BadUser(AbstractBaseUser):
  80. username = models.CharField(max_length=30, unique=True)
  81. USERNAME_FIELD = 'username'
  82. def is_anonymous(self):
  83. return True
  84. def is_authenticated(self):
  85. return True
  86. errors = checks.run_checks(app_configs=self.apps.get_app_configs())
  87. self.assertEqual(errors, [
  88. checks.Critical(
  89. '%s.is_anonymous must be an attribute or property rather than '
  90. 'a method. Ignoring this is a security issue as anonymous '
  91. 'users will be treated as authenticated!' % BadUser,
  92. obj=BadUser,
  93. id='auth.C009',
  94. ),
  95. checks.Critical(
  96. '%s.is_authenticated must be an attribute or property rather '
  97. 'than a method. Ignoring this is a security issue as anonymous '
  98. 'users will be treated as authenticated!' % BadUser,
  99. obj=BadUser,
  100. id='auth.C010',
  101. ),
  102. ])
  103. @isolate_apps('auth_tests', attr_name='apps')
  104. @override_system_checks([check_models_permissions])
  105. class ModelsPermissionsChecksTests(SimpleTestCase):
  106. def test_clashing_default_permissions(self):
  107. class Checked(models.Model):
  108. class Meta:
  109. permissions = [
  110. ('change_checked', 'Can edit permission (duplicate)')
  111. ]
  112. errors = checks.run_checks(self.apps.get_app_configs())
  113. self.assertEqual(errors, [
  114. checks.Error(
  115. "The permission codenamed 'change_checked' clashes with a builtin "
  116. "permission for model 'auth_tests.Checked'.",
  117. obj=Checked,
  118. id='auth.E005',
  119. ),
  120. ])
  121. def test_non_clashing_custom_permissions(self):
  122. class Checked(models.Model):
  123. class Meta:
  124. permissions = [
  125. ('my_custom_permission', 'Some permission'),
  126. ('other_one', 'Some other permission'),
  127. ]
  128. errors = checks.run_checks(self.apps.get_app_configs())
  129. self.assertEqual(errors, [])
  130. def test_clashing_custom_permissions(self):
  131. class Checked(models.Model):
  132. class Meta:
  133. permissions = [
  134. ('my_custom_permission', 'Some permission'),
  135. ('other_one', 'Some other permission'),
  136. ('my_custom_permission', 'Some permission with duplicate permission code'),
  137. ]
  138. errors = checks.run_checks(self.apps.get_app_configs())
  139. self.assertEqual(errors, [
  140. checks.Error(
  141. "The permission codenamed 'my_custom_permission' is duplicated for "
  142. "model 'auth_tests.Checked'.",
  143. obj=Checked,
  144. id='auth.E006',
  145. ),
  146. ])
  147. def test_verbose_name_max_length(self):
  148. class Checked(models.Model):
  149. class Meta:
  150. verbose_name = 'some ridiculously long verbose name that is out of control' * 5
  151. errors = checks.run_checks(self.apps.get_app_configs())
  152. self.assertEqual(errors, [
  153. checks.Error(
  154. "The verbose_name of model 'auth_tests.Checked' must be at most 244 "
  155. "characters for its builtin permission names to be at most 255 characters.",
  156. obj=Checked,
  157. id='auth.E007',
  158. ),
  159. ])
  160. def test_custom_permission_name_max_length(self):
  161. custom_permission_name = 'some ridiculously long verbose name that is out of control' * 5
  162. class Checked(models.Model):
  163. class Meta:
  164. permissions = [
  165. ('my_custom_permission', custom_permission_name),
  166. ]
  167. errors = checks.run_checks(self.apps.get_app_configs())
  168. self.assertEqual(errors, [
  169. checks.Error(
  170. "The permission named '%s' of model 'auth_tests.Checked' is longer "
  171. "than 255 characters." % custom_permission_name,
  172. obj=Checked,
  173. id='auth.E008',
  174. ),
  175. ])
  176. def test_empty_default_permissions(self):
  177. class Checked(models.Model):
  178. class Meta:
  179. default_permissions = ()
  180. self.assertEqual(checks.run_checks(self.apps.get_app_configs()), [])