Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions django/contrib/auth/checks.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from itertools import chain
from types import MethodType

from django.apps import apps
from django.conf import settings
Expand Down Expand Up @@ -98,7 +97,7 @@ def check_user_model(app_configs, **kwargs):
)
)

if isinstance(cls().is_anonymous, MethodType):
if callable(cls().is_anonymous):
errors.append(
checks.Critical(
"%s.is_anonymous must be an attribute or property rather than "
Expand All @@ -108,7 +107,7 @@ def check_user_model(app_configs, **kwargs):
id="auth.C009",
)
)
if isinstance(cls().is_authenticated, MethodType):
if callable(cls().is_authenticated):
errors.append(
checks.Critical(
"%s.is_authenticated must be an attribute or property rather "
Expand Down
1 change: 1 addition & 0 deletions django/utils/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ class Urlizer:
simple_url_re = _lazy_re_compile(r"^https?://\[?\w", re.IGNORECASE)
simple_url_2_re = _lazy_re_compile(
rf"^www\.|^(?!http)(?:{DomainNameValidator.hostname_re})"
rf"(?:{DomainNameValidator.domain_re})"
r"\.(com|edu|gov|int|mil|net|org)($|/.*)$",
re.IGNORECASE,
)
Expand Down
39 changes: 39 additions & 0 deletions tests/auth_tests/test_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,45 @@ def is_authenticated(self):
],
)

@override_settings(AUTH_USER_MODEL="auth_tests.VulnerableStaticUser")
def test_is_anonymous_authenticated_static_methods(self):
"""
<User Model>.is_anonymous/is_authenticated must not be static methods.
"""

class VulnerableStaticUser(AbstractBaseUser):
username = models.CharField(max_length=30, unique=True)
USERNAME_FIELD = "username"

@staticmethod
def is_anonymous():
return False

@staticmethod
def is_authenticated():
return False

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!" % VulnerableStaticUser,
obj=VulnerableStaticUser,
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!" % VulnerableStaticUser,
obj=VulnerableStaticUser,
id="auth.C010",
),
],
)


@isolate_apps("auth_tests", attr_name="apps")
@override_system_checks([check_models_permissions])
Expand Down
4 changes: 4 additions & 0 deletions tests/utils_tests/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,10 @@ def test_urlize(self):
'<a href="mailto:idna-2008@%DE%89%DE%A8%DE%80%DE%A7%DE%83%DE%AA.ex'
'ample.mv">idna-2008@މިހާރު.example.mv</a>',
),
(
"host.djangoproject.com",
'<a href="https://host.djangoproject.com">host.djangoproject.com</a>',
),
)
for value, output in tests:
with self.subTest(value=value):
Expand Down