You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

checks.py 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. from itertools import chain
  2. from types import MethodType
  3. from django.apps import apps
  4. from django.conf import settings
  5. from django.core import checks
  6. from .management import _get_builtin_permissions
  7. def check_user_model(app_configs=None, **kwargs):
  8. if app_configs is None:
  9. cls = apps.get_model(settings.AUTH_USER_MODEL)
  10. else:
  11. app_label, model_name = settings.AUTH_USER_MODEL.split('.')
  12. for app_config in app_configs:
  13. if app_config.label == app_label:
  14. cls = app_config.get_model(model_name)
  15. break
  16. else:
  17. # Checks might be run against a set of app configs that don't
  18. # include the specified user model. In this case we simply don't
  19. # perform the checks defined below.
  20. return []
  21. errors = []
  22. # Check that REQUIRED_FIELDS is a list
  23. if not isinstance(cls.REQUIRED_FIELDS, (list, tuple)):
  24. errors.append(
  25. checks.Error(
  26. "'REQUIRED_FIELDS' must be a list or tuple.",
  27. obj=cls,
  28. id='auth.E001',
  29. )
  30. )
  31. # Check that the USERNAME FIELD isn't included in REQUIRED_FIELDS.
  32. if cls.USERNAME_FIELD in cls.REQUIRED_FIELDS:
  33. errors.append(
  34. checks.Error(
  35. "The field named as the 'USERNAME_FIELD' "
  36. "for a custom user model must not be included in 'REQUIRED_FIELDS'.",
  37. obj=cls,
  38. id='auth.E002',
  39. )
  40. )
  41. # Check that the username field is unique
  42. if not cls._meta.get_field(cls.USERNAME_FIELD).unique:
  43. if (settings.AUTHENTICATION_BACKENDS ==
  44. ['django.contrib.auth.backends.ModelBackend']):
  45. errors.append(
  46. checks.Error(
  47. "'%s.%s' must be unique because it is named as the 'USERNAME_FIELD'." % (
  48. cls._meta.object_name, cls.USERNAME_FIELD
  49. ),
  50. obj=cls,
  51. id='auth.E003',
  52. )
  53. )
  54. else:
  55. errors.append(
  56. checks.Warning(
  57. "'%s.%s' is named as the 'USERNAME_FIELD', but it is not unique." % (
  58. cls._meta.object_name, cls.USERNAME_FIELD
  59. ),
  60. hint='Ensure that your authentication backend(s) can handle non-unique usernames.',
  61. obj=cls,
  62. id='auth.W004',
  63. )
  64. )
  65. if isinstance(cls().is_anonymous, MethodType):
  66. errors.append(
  67. checks.Critical(
  68. '%s.is_anonymous must be an attribute or property rather than '
  69. 'a method. Ignoring this is a security issue as anonymous '
  70. 'users will be treated as authenticated!' % cls,
  71. obj=cls,
  72. id='auth.C009',
  73. )
  74. )
  75. if isinstance(cls().is_authenticated, MethodType):
  76. errors.append(
  77. checks.Critical(
  78. '%s.is_authenticated must be an attribute or property rather '
  79. 'than a method. Ignoring this is a security issue as anonymous '
  80. 'users will be treated as authenticated!' % cls,
  81. obj=cls,
  82. id='auth.C010',
  83. )
  84. )
  85. return errors
  86. def check_models_permissions(app_configs=None, **kwargs):
  87. if app_configs is None:
  88. models = apps.get_models()
  89. else:
  90. models = chain.from_iterable(app_config.get_models() for app_config in app_configs)
  91. Permission = apps.get_model('auth', 'Permission')
  92. permission_name_max_length = Permission._meta.get_field('name').max_length
  93. errors = []
  94. for model in models:
  95. opts = model._meta
  96. builtin_permissions = dict(_get_builtin_permissions(opts))
  97. # Check builtin permission name length.
  98. max_builtin_permission_name_length = (
  99. max(len(name) for name in builtin_permissions.values())
  100. if builtin_permissions else 0
  101. )
  102. if max_builtin_permission_name_length > permission_name_max_length:
  103. verbose_name_max_length = (
  104. permission_name_max_length - (max_builtin_permission_name_length - len(opts.verbose_name_raw))
  105. )
  106. errors.append(
  107. checks.Error(
  108. "The verbose_name of model '%s.%s' must be at most %d characters "
  109. "for its builtin permission names to be at most %d characters." % (
  110. opts.app_label, opts.object_name, verbose_name_max_length, permission_name_max_length
  111. ),
  112. obj=model,
  113. id='auth.E007',
  114. )
  115. )
  116. codenames = set()
  117. for codename, name in opts.permissions:
  118. # Check custom permission name length.
  119. if len(name) > permission_name_max_length:
  120. errors.append(
  121. checks.Error(
  122. "The permission named '%s' of model '%s.%s' is longer than %d characters." % (
  123. name, opts.app_label, opts.object_name, permission_name_max_length
  124. ),
  125. obj=model,
  126. id='auth.E008',
  127. )
  128. )
  129. # Check custom permissions codename clashing.
  130. if codename in builtin_permissions:
  131. errors.append(
  132. checks.Error(
  133. "The permission codenamed '%s' clashes with a builtin permission "
  134. "for model '%s.%s'." % (
  135. codename, opts.app_label, opts.object_name
  136. ),
  137. obj=model,
  138. id='auth.E005',
  139. )
  140. )
  141. elif codename in codenames:
  142. errors.append(
  143. checks.Error(
  144. "The permission codenamed '%s' is duplicated for model '%s.%s'." % (
  145. codename, opts.app_label, opts.object_name
  146. ),
  147. obj=model,
  148. id='auth.E006',
  149. )
  150. )
  151. codenames.add(codename)
  152. return errors