[Django] #36325: Inconsistent error handling for inactive users in ModelBackend

7 views
Skip to first unread message

Django

unread,
Apr 13, 2025, 2:17:53 PM4/13/25
to django-...@googlegroups.com
#36325: Inconsistent error handling for inactive users in ModelBackend
-------------------------------------+-------------------------------------
Reporter: Ariel Souza | Type: Bug
Status: new | Component:
| contrib.auth
Version: 5.2 | Severity: Normal
Keywords: | Triage Stage:
ModelBackend;authenticate | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
### Bug Description

In the `ModelBackend`, the `authenticate` method checks whether
`user_can_authenticate(user)` returns `True` before calling
`confirm_login_allowed`. This causes `authenticate()` to return `None`
silently if the user is inactive (`is_active=False`), even when the
credentials are valid.

As a result, any login attempt with an inactive user results in a generic
"email or password is incorrect" error message. This is especially
misleading in the Django Admin, where users expect a specific message
indicating that the account is inactive.

### Proposed Solution

Refactor the logic in `authenticate()` to ensure that
`confirm_login_allowed(user)` is always called after the user is found and
credentials are valid, regardless of the user's active status. This way,
custom validation errors (such as inactive account warnings) are properly
raised.

### Steps to Reproduce

1. Create a user with `is_active=False`.
2. Attempt to log in using the correct credentials (e.g., via Django
Admin).
3. Observe that the system returns a generic "email or password is
incorrect" error.

### Expected Behavior

A clear message should be displayed indicating that the account is
inactive, as raised by `confirm_login_allowed`.


### My comment

I removed the self.user_can_authenticate(user) function from ModelBackend,
which solves the problem,

{{{
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
if username is None or password is None:
return
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user
(#20760).
UserModel().set_password(password)
else:
if user.check_password(password):
return user
}}}


but I couldn't create the test because the test always gave an error in
self.user_can_authenticate(user) of the ModelBackend, returning True for
the inactive user. Since I started studying Django recently and I'm
currently unemployed, I'll leave this up to you.

Here's my code:

{{{
def test_get_inactive_login_error(self):
User.objects.create_user(username="testinactive", password="pwd",
is_active=False)
data = {
"username": "testinactive",
"password": "pwd",
}
form = AuthenticationForm(None, data)
self.assertIn("This account is inactive.",
form.non_field_errors())
}}}


Thank you for reading this far.
--
Ticket URL: <https://code.djangoproject.com/ticket/36325>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Apr 13, 2025, 2:32:14 PM4/13/25
to django-...@googlegroups.com
#36325: Inconsistent error handling for inactive users in ModelBackend
-------------------------------------+-------------------------------------
Reporter: Ariel Souza | Owner: (none)
Type: Bug | Status: new
Component: contrib.auth | Version: 5.2
Severity: Normal | Resolution:
Keywords: | Triage Stage:
ModelBackend;authenticate | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Ariel Souza):

* Attachment "image-20250413-153205.png" added.

Django

unread,
Apr 13, 2025, 8:22:15 PM4/13/25
to django-...@googlegroups.com
#36325: Inconsistent error handling for inactive users in ModelBackend
-------------------------------------+-------------------------------------
Reporter: Ariel Souza | Owner: (none)
Type: Bug | Status: closed
Component: contrib.auth | Version: 5.2
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
ModelBackend;authenticate | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by ontowhee):

* resolution: => invalid
* status: new => closed

Comment:

Hello! Thanks for the report.

> As a result, any login attempt with an inactive user results in a
generic "email or password is incorrect" error message. This is especially
misleading in the Django Admin, where users expect a specific message
indicating that the account is inactive.

Returning a generic error message is desirable from a security perspective
and is recommended by OWASP:
[https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#login].

> A clear message should be displayed indicating that the account is
inactive, as raised by confirm_login_allowed.

The use case you are describing goes against the security practices.
Closing this ticket because the use case is not aligned with the security
practices.

If you need assistance in using Django please feel free to ask for help
from a friendly community member on [https://chat.djangoproject.com/
Discord] or the [https://forum.djangoproject.com/ Django forum]
--
Ticket URL: <https://code.djangoproject.com/ticket/36325#comment:1>

Django

unread,
Apr 14, 2025, 4:23:33 AM4/14/25
to django-...@googlegroups.com
#36325: Inconsistent error handling for inactive users in ModelBackend
-------------------------------------+-------------------------------------
Reporter: Ariel Souza | Owner: (none)
Type: Bug | Status: closed
Component: contrib.auth | Version: 5.2
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
ModelBackend;authenticate | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Ariel Souza):

Thank you very much for the reply!
--
Ticket URL: <https://code.djangoproject.com/ticket/36325#comment:2>
Reply all
Reply to author
Forward
0 new messages