@@ -500,21 +500,23 @@ async def authenticate(self, handler, data):
500
500
501
501
ref: https://jupyterhub.readthedocs.io/en/latest/reference/authenticators.html#authenticator-authenticate
502
502
"""
503
- username = data ["username" ]
503
+ login_username = data ["username" ]
504
504
password = data ["password" ]
505
505
506
506
# 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 ):
508
508
self .log .warning (
509
509
"username:%s Illegal characters in username, must match regex %s" ,
510
- username ,
510
+ login_username ,
511
511
self .valid_username_regex ,
512
512
)
513
513
return None
514
514
515
515
# No empty passwords!
516
516
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
+ )
518
520
return None
519
521
520
522
# sanity check
@@ -525,9 +527,10 @@ async def authenticate(self, handler, data):
525
527
return None
526
528
527
529
bind_dn_template = self .bind_dn_template
530
+ resolved_username = login_username
528
531
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 :
531
534
return None
532
535
if not bind_dn_template :
533
536
bind_dn_template = [resolved_dn ]
@@ -537,12 +540,21 @@ async def authenticate(self, handler, data):
537
540
for dn in bind_dn_template :
538
541
# DN's attribute values should be escaped with escape_rdn to respect
539
542
# 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 ))
541
544
conn = self .get_connection (userdn , password )
542
545
if conn :
543
546
break
544
547
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
+ )
546
558
return None
547
559
548
560
if self .search_filter :
@@ -551,22 +563,22 @@ async def authenticate(self, handler, data):
551
563
search_scope = ldap3 .SUBTREE ,
552
564
search_filter = self .search_filter .format (
553
565
userattr = self .user_attribute ,
554
- username = escape_filter_chars (username ),
566
+ username = escape_filter_chars (resolved_username ),
555
567
),
556
568
attributes = self .attributes ,
557
569
)
558
570
n_users = len (conn .response )
559
571
if n_users == 0 :
560
572
self .log .warning (
561
573
"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 } '"
563
575
)
564
576
return None
565
577
if n_users > 1 :
566
578
self .log .warning (
567
579
"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."
570
582
)
571
583
return None
572
584
@@ -577,14 +589,14 @@ async def authenticate(self, handler, data):
577
589
"Missing group_search_filter or group_attributes. Both are required."
578
590
)
579
591
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 )
581
593
for group in self .allowed_groups :
582
594
found = conn .search (
583
595
search_base = group ,
584
596
search_scope = ldap3 .BASE ,
585
597
search_filter = self .group_search_filter .format (
586
598
userdn = escape_filter_chars (userdn ),
587
- uid = escape_filter_chars (username ),
599
+ uid = escape_filter_chars (resolved_username ),
588
600
),
589
601
attributes = self .group_attributes ,
590
602
)
@@ -596,15 +608,18 @@ async def authenticate(self, handler, data):
596
608
# we should keep fetching membership
597
609
break
598
610
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
601
614
602
615
user_attributes = self .get_user_attributes (conn , userdn )
616
+ self .log .debug ("username:%s attributes:%s" , username , user_attributes )
617
+
603
618
auth_state = {
604
619
"ldap_groups" : ldap_groups ,
605
620
"user_attributes" : user_attributes ,
606
621
}
607
- self . log . debug ( "username:%s attributes:%s" , username , user_attributes )
622
+
608
623
return {"name" : username , "auth_state" : auth_state }
609
624
610
625
async def check_allowed (self , username , auth_model ):
0 commit comments