mirror of
https://github.com/jazzband/django-axes.git
synced 2026-05-03 13:14:46 +00:00
Fix #1159: Fallback to USERNAME_FIELD when AXES_USERNAME_FORM_FIELD not in credentials
This commit is contained in:
parent
e27ce891ea
commit
856d74aef3
2 changed files with 81 additions and 2 deletions
|
|
@ -5,6 +5,7 @@ from string import Template
|
|||
from typing import Callable, Optional, Type, Union, List
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.cache import BaseCache, caches
|
||||
from django.http import HttpRequest, HttpResponse, JsonResponse, QueryDict
|
||||
from django.shortcuts import redirect, render
|
||||
|
|
@ -164,14 +165,37 @@ def get_client_username(
|
|||
log.debug(
|
||||
"Using parameter credentials to get username with key settings.AXES_USERNAME_FORM_FIELD"
|
||||
)
|
||||
return credentials.get(settings.AXES_USERNAME_FORM_FIELD, None) # type: ignore[return-value]
|
||||
username = credentials.get(settings.AXES_USERNAME_FORM_FIELD, None)
|
||||
if username is None:
|
||||
# Fallback to Django's USERNAME_FIELD for compatibility with
|
||||
# Django's user_login_failed signal which uses USERNAME_FIELD as the key
|
||||
# See: https://github.com/jazzband/django-axes/issues/1159
|
||||
username_field = get_user_model().USERNAME_FIELD
|
||||
if username_field != str(settings.AXES_USERNAME_FORM_FIELD):
|
||||
log.debug(
|
||||
"Falling back to USERNAME_FIELD '%s' for credentials lookup",
|
||||
username_field,
|
||||
)
|
||||
username = credentials.get(username_field, None)
|
||||
return username # type: ignore[return-value]
|
||||
|
||||
log.debug(
|
||||
"Using parameter request.POST to get username with key settings.AXES_USERNAME_FORM_FIELD"
|
||||
)
|
||||
|
||||
request_data = getattr(request, "data", request.POST)
|
||||
return request_data.get(settings.AXES_USERNAME_FORM_FIELD, None)
|
||||
username = request_data.get(settings.AXES_USERNAME_FORM_FIELD, None)
|
||||
if username is None:
|
||||
# Fallback to Django's USERNAME_FIELD for compatibility
|
||||
# See: https://github.com/jazzband/django-axes/issues/1159
|
||||
username_field = get_user_model().USERNAME_FIELD
|
||||
if username_field != str(settings.AXES_USERNAME_FORM_FIELD):
|
||||
log.debug(
|
||||
"Falling back to USERNAME_FIELD '%s' for request data lookup",
|
||||
username_field,
|
||||
)
|
||||
username = request_data.get(username_field, None)
|
||||
return username # type: ignore[return-value]
|
||||
|
||||
|
||||
def get_client_ip_address(
|
||||
|
|
|
|||
|
|
@ -792,6 +792,61 @@ class UsernameTestCase(AxesTestCase):
|
|||
def test_get_client_username_str(self):
|
||||
self.assertEqual(get_client_username(HttpRequest(), {}), "username")
|
||||
|
||||
@override_settings(AXES_USERNAME_FORM_FIELD="auth-username")
|
||||
def test_get_client_username_fallback_to_username_field_from_credentials(self):
|
||||
"""
|
||||
Test that when AXES_USERNAME_FORM_FIELD is set to a custom value that
|
||||
doesn't exist in credentials, we fallback to Django's USERNAME_FIELD.
|
||||
|
||||
This fixes https://github.com/jazzband/django-axes/issues/1159
|
||||
"""
|
||||
expected = "test-username"
|
||||
|
||||
request = HttpRequest()
|
||||
# Credentials from Django's user_login_failed signal use USERNAME_FIELD (e.g., "username")
|
||||
# not the custom AXES_USERNAME_FORM_FIELD value
|
||||
credentials = {"username": expected}
|
||||
|
||||
actual = get_client_username(request, credentials)
|
||||
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
@override_settings(AXES_USERNAME_FORM_FIELD="auth-username")
|
||||
def test_get_client_username_fallback_to_username_field_from_request(self):
|
||||
"""
|
||||
Test that when AXES_USERNAME_FORM_FIELD is set to a custom value that
|
||||
doesn't exist in request.POST, we fallback to Django's USERNAME_FIELD.
|
||||
|
||||
This fixes https://github.com/jazzband/django-axes/issues/1159
|
||||
"""
|
||||
expected = "test-username"
|
||||
|
||||
request = HttpRequest()
|
||||
# POST data might use Django's USERNAME_FIELD instead of custom form field
|
||||
request.POST["username"] = expected
|
||||
|
||||
actual = get_client_username(request)
|
||||
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
@override_settings(AXES_USERNAME_FORM_FIELD="auth-username")
|
||||
def test_get_client_username_custom_field_takes_priority(self):
|
||||
"""
|
||||
Test that AXES_USERNAME_FORM_FIELD takes priority when it exists in credentials.
|
||||
"""
|
||||
expected = "custom-field-username"
|
||||
fallback = "username-field-value"
|
||||
|
||||
request = HttpRequest()
|
||||
credentials = {
|
||||
"auth-username": expected, # Custom field - should be used
|
||||
"username": fallback, # Django's USERNAME_FIELD - should be ignored
|
||||
}
|
||||
|
||||
actual = get_client_username(request, credentials)
|
||||
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
|
||||
def get_username(request, credentials: dict) -> str:
|
||||
return "username"
|
||||
|
|
|
|||
Loading…
Reference in a new issue