Describe the bug
When a user successfully authenticates via LDAP bind but cannot be found by DN search during the subsequent group membership verification, an unhandled UserNotFound exception causes a 500 Internal Server Error.
In ldap.authenticate(), the UserNotFound exception is caught during user.bind() (line 154), but not during the group membership check that follows. When require_group is configured, user.is_group_member() calls self.get_user_dn(), which may call search_dn(). If the LDAP search returns no results for the user, UserNotFound is raised and propagates unhandled all the way up to Django's error handler.
This can happen when the LDAP bind uses a suffix-based method (so the DN is never resolved during bind), and the subsequent DN search during group membership verification fails to find the user.
To Reproduce
- Configure NAV with LDAP authentication using a
suffix for binding
- Configure
require_group to require group membership verification
- Configure
lookupmethod=search
- Have a user who can authenticate via bind but whose DN search returns no results (e.g. because
search_dn() rebinds as manager, changing the connection state)
- Attempt to log in
- Observe a 500 error:
UserNotFound at /index/login/
Expected behavior
If a user cannot be found during group membership verification, the login should fail gracefully with an "invalid credentials" message, not crash with a 500 error.
Tracebacks
Traceback (most recent call last):
File "django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "nav/web/webfront/views.py", line 356, in login
return do_login(request)
File "nav/web/webfront/views.py", line 403, in do_login
account = authenticate(request, username=username, password=password)
File "django/contrib/auth/__init__.py", line 77, in authenticate
user = backend.authenticate(request, **credentials)
File "nav/web/auth/ldap_auth_backend.py", line 70, in authenticate
if not (ldap_user := self._ldap_authenticate(username, password)):
File "nav/web/auth/ldap_auth_backend.py", line 93, in _ldap_authenticate
ldap_user = ldap.authenticate(username, password)
File "nav/web/auth/ldap.py", line 163, in authenticate
if user.is_group_member(group_dn):
File "nav/web/auth/ldap.py", line 314, in is_group_member
user_dn = self.get_user_dn()
File "nav/web/auth/ldap.py", line 238, in get_user_dn
self.user_dn, self.username = self.search_dn()
File "nav/web/auth/ldap.py", line 269, in search_dn
raise UserNotFound(filter_)
nav.web.auth.ldap.UserNotFound: User object was not found: (sAMAccountName=rudolf)
Environment
Additional context
The UserNotFound exception is already handled during the user.bind() phase of authenticate(), but the same exception can also be raised during the group membership and entitlement verification phases that follow. These post-bind code paths need the same exception handling.
Describe the bug
When a user successfully authenticates via LDAP bind but cannot be found by DN search during the subsequent group membership verification, an unhandled
UserNotFoundexception causes a 500 Internal Server Error.In
ldap.authenticate(), theUserNotFoundexception is caught duringuser.bind()(line 154), but not during the group membership check that follows. Whenrequire_groupis configured,user.is_group_member()callsself.get_user_dn(), which may callsearch_dn(). If the LDAP search returns no results for the user,UserNotFoundis raised and propagates unhandled all the way up to Django's error handler.This can happen when the LDAP bind uses a
suffix-based method (so the DN is never resolved during bind), and the subsequent DN search during group membership verification fails to find the user.To Reproduce
suffixfor bindingrequire_groupto require group membership verificationlookupmethod=searchsearch_dn()rebinds as manager, changing the connection state)UserNotFound at /index/login/Expected behavior
If a user cannot be found during group membership verification, the login should fail gracefully with an "invalid credentials" message, not crash with a 500 error.
Tracebacks
Environment
Additional context
The
UserNotFoundexception is already handled during theuser.bind()phase ofauthenticate(), but the same exception can also be raised during the group membership and entitlement verification phases that follow. These post-bind code paths need the same exception handling.