Skip to content

Commit 86a3546

Browse files
committed
refactor: distinguish login_username from resolved_username
1 parent d37b6f1 commit 86a3546

File tree

1 file changed

+32
-17
lines changed

1 file changed

+32
-17
lines changed

ldapauthenticator/ldapauthenticator.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -500,21 +500,23 @@ async def authenticate(self, handler, data):
500500
501501
ref: https://jupyterhub.readthedocs.io/en/latest/reference/authenticators.html#authenticator-authenticate
502502
"""
503-
username = data["username"]
503+
login_username = data["username"]
504504
password = data["password"]
505505

506506
# Protect against invalid usernames as well as LDAP injection attacks
507-
if not re.match(self.valid_username_regex, username):
507+
if not re.match(self.valid_username_regex, login_username):
508508
self.log.warning(
509509
"username:%s Illegal characters in username, must match regex %s",
510-
username,
510+
login_username,
511511
self.valid_username_regex,
512512
)
513513
return None
514514

515515
# No empty passwords!
516516
if password is None or password.strip() == "":
517-
self.log.warning("username:%s Login denied for blank password", username)
517+
self.log.warning(
518+
"username:%s Login denied for blank password", login_username
519+
)
518520
return None
519521

520522
# sanity check
@@ -525,9 +527,10 @@ async def authenticate(self, handler, data):
525527
return None
526528

527529
bind_dn_template = self.bind_dn_template
530+
resolved_username = login_username
528531
if self.lookup_dn:
529-
username, resolved_dn = self.resolve_username(username)
530-
if not username:
532+
resolved_username, resolved_dn = self.resolve_username(login_username)
533+
if not resolved_dn:
531534
return None
532535
if not bind_dn_template:
533536
bind_dn_template = [resolved_dn]
@@ -537,12 +540,21 @@ async def authenticate(self, handler, data):
537540
for dn in bind_dn_template:
538541
# DN's attribute values should be escaped with escape_rdn to respect
539542
# https://datatracker.ietf.org/doc/html/rfc4514#section-2.4
540-
userdn = dn.format(username=escape_rdn(username))
543+
userdn = dn.format(username=escape_rdn(resolved_username))
541544
conn = self.get_connection(userdn, password)
542545
if conn:
543546
break
544547
if not conn:
545-
self.log.warning(f"Failed to bind user '{username}' to an LDAP user.")
548+
if login_username == resolved_username:
549+
self.log.warning(
550+
f"Failed to bind user '{login_username}' to an LDAP user."
551+
)
552+
else:
553+
self.log.warning(
554+
f"Failed to bind login username '{login_username}', "
555+
f"with looked up user attribute value '{resolved_username}', "
556+
"to an LDAP user."
557+
)
546558
return None
547559

548560
if self.search_filter:
@@ -551,22 +563,22 @@ async def authenticate(self, handler, data):
551563
search_scope=ldap3.SUBTREE,
552564
search_filter=self.search_filter.format(
553565
userattr=self.user_attribute,
554-
username=escape_filter_chars(username),
566+
username=escape_filter_chars(resolved_username),
555567
),
556568
attributes=self.attributes,
557569
)
558570
n_users = len(conn.response)
559571
if n_users == 0:
560572
self.log.warning(
561573
"Configured search_filter found no user associated with "
562-
f"userattr='{self.user_attribute}' and username='{username}'"
574+
f"userattr='{self.user_attribute}' and username='{resolved_username}'"
563575
)
564576
return None
565577
if n_users > 1:
566578
self.log.warning(
567579
"Configured search_filter found multiple users associated with "
568-
f"userattr='{self.user_attribute}' and username='{username}', a "
569-
"unique match is required."
580+
f"userattr='{self.user_attribute}' and username='{resolved_username}', "
581+
"a unique match is required."
570582
)
571583
return None
572584

@@ -577,14 +589,14 @@ async def authenticate(self, handler, data):
577589
"Missing group_search_filter or group_attributes. Both are required."
578590
)
579591
return None
580-
self.log.debug("username:%s Using dn %s", username, userdn)
592+
self.log.debug("username:%s Using dn %s", resolved_username, userdn)
581593
for group in self.allowed_groups:
582594
found = conn.search(
583595
search_base=group,
584596
search_scope=ldap3.BASE,
585597
search_filter=self.group_search_filter.format(
586598
userdn=escape_filter_chars(userdn),
587-
uid=escape_filter_chars(username),
599+
uid=escape_filter_chars(resolved_username),
588600
),
589601
attributes=self.group_attributes,
590602
)
@@ -596,15 +608,18 @@ async def authenticate(self, handler, data):
596608
# we should keep fetching membership
597609
break
598610

599-
if not self.use_lookup_dn_username:
600-
username = data["username"]
611+
username = login_username
612+
if self.use_lookup_dn_username:
613+
username = resolved_username
601614

602615
user_attributes = self.get_user_attributes(conn, userdn)
616+
self.log.debug("username:%s attributes:%s", username, user_attributes)
617+
603618
auth_state = {
604619
"ldap_groups": ldap_groups,
605620
"user_attributes": user_attributes,
606621
}
607-
self.log.debug("username:%s attributes:%s", username, user_attributes)
622+
608623
return {"name": username, "auth_state": auth_state}
609624

610625
async def check_allowed(self, username, auth_model):

0 commit comments

Comments
 (0)