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
3 changes: 3 additions & 0 deletions django/contrib/auth/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
from django.db.models import Exists, OuterRef, Q
from django.views.decorators.debug import sensitive_variables

UserModel = get_user_model()

Expand Down Expand Up @@ -56,6 +57,7 @@ class ModelBackend(BaseBackend):
Authenticates against settings.AUTH_USER_MODEL.
"""

@sensitive_variables("password")
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
Expand All @@ -71,6 +73,7 @@ def authenticate(self, request, username=None, password=None, **kwargs):
if user.check_password(password) and self.user_can_authenticate(user):
return user

@sensitive_variables("password")
async def aauthenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
Expand Down
14 changes: 14 additions & 0 deletions tests/auth_tests/models/custom_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,17 @@ class ExtensionUser(AbstractUser):
custom_objects = UserManager()

REQUIRED_FIELDS = AbstractUser.REQUIRED_FIELDS + ["date_of_birth"]


class ErrorUserManager(BaseUserManager):
def get_by_natural_key(self, _):
raise TypeError

async def aget_by_natural_key(self, _):
raise TypeError


with RemoveGroupsAndPermissions():

class ErrorAdminUser(AbstractUser):
custom_objects = ErrorUserManager()
36 changes: 36 additions & 0 deletions tests/auth_tests/test_auth_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,42 @@ async def test_aauthenticate_sensitive_variables(self):
status_code=500,
)

@override_settings(AUTH_USER_MODEL="auth_tests.ErrorAdminUser")
def test_model_backend_authenticate_sensitive_variables(self):
try:
authenticate(username="testusername", password=self.sensitive_password)
except TypeError:
exc_info = sys.exc_info()
rf = RequestFactory()
response = technical_500_response(rf.get("/"), *exc_info)
self.assertNotContains(response, self.sensitive_password, status_code=500)
self.assertContains(
response,
'<tr><td>password</td><td class="code">'
"<pre>&#39;********************&#39;</pre></td></tr>",
html=True,
status_code=500,
)

@override_settings(AUTH_USER_MODEL="auth_tests.ErrorAdminUser")
async def test_model_backend_async_authenticate_sensitive_variables(self):
try:
await aauthenticate(
username="testusername", password=self.sensitive_password
)
except TypeError:
exc_info = sys.exc_info()
rf = RequestFactory()
response = technical_500_response(rf.get("/"), *exc_info)
self.assertNotContains(response, self.sensitive_password, status_code=500)
self.assertContains(
response,
'<tr><td>password</td><td class="code">'
"<pre>&#39;********************&#39;</pre></td></tr>",
html=True,
status_code=500,
)

def test_clean_credentials_sensitive_variables(self):
try:
# Passing in a list to cause an exception
Expand Down
Loading