BUG: Setting `AXES_USERNAME_FORM_FIELD` to a custom value fails to fill the username field for `AccessAttempt`
jur-clerkx opened this issue · comments
Describe the bug
In our project, we have set the AXES_USERNAME_FORM_FIELD
to a custom value. When doing this, AccessAttempt
in the database doesn't get a username set, this stays None.
After a quick debug, it showed that there is a call being made where the credentials are given. However, in the credentials dict, the username is stored in a field named username
in stead of the value set in AXES_USERNAME_FORM_FIELD
. Since the code tries to fetch the username based on the name in the settings, this will return None. Assumption for now is that this were it goes wrong.
To Reproduce
Steps to reproduce the behavior:
- Create a custom login form with a username field that has a custom name (e.g.
auth-username
) - Set the
AXES_USERNAME_FORM_FIELD
toauth-username
- Do a failed login attempt
- The username field on the
AccessAttempt
will be empty.
Expected behavior
The username field on the AccessAttempt
model is filled with the correct username.
Your environment
python version: 3.8.18
django version: 3.2.23
django-axes version: 6.3.0
Operating system: Mac OS
Additional context
What was interesting was that the credentials that were shown in the debugger was:
username
: username filled in the form
password
: ***********************
Possibly this conflicts with the logging implementation.
Possible implementation
Probably an easy bugfix where username
is used in stead of the value set in AXES_USERNAME_FORM_FIELD
So after some digging, it turns out that the code tries to fetch the username out of the Django login failed signal by using the AXES_USERNAME_FORM_FIELD
as key. However, in our case, Django always uses the username
key. Probably need to use the USERNAME_FIELD
setting here?
Good catch. Would someone like to open a PR that changes the username
field to a the more appropriate AXES_USERNAME_FORM_FIELD
or USERNAME_FIELD
value?
I managed to trace it down to where the code conflicts with the data that is sent by the the Django user_login_failed
signal:
django-axes/axes/handlers/database.py
Line 136 in 6c54cf4
The get_client_username
method will try to fetch the username from the credentials using the AXES_USERNAME_FORM_FIELD
setting. However, the Django signal will use the regular name of the field used as username (username
, e-mail
etc).
I'll try to make a PR to fix this, probably by just preferring to look in the request for the username in stead of the credentials.
For people who are also having this issue, you can implement a workaround by using the AXES_USERNAME_CALLABLE
setting:
AXES_USERNAME_CALLABLE = lambda request, _: request.POST.get("<your username field>", None) # noqa