From 2123f361ce5cff426191d74d31493fe46d0d9328 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Thu, 31 Oct 2024 14:44:31 +0100 Subject: [PATCH] Fix parsing of search response We were using conn.response but should have used conn.entries as we only cared for search results and not other kinds of messages that could be part of conn.response. --- ldapauthenticator/ldapauthenticator.py | 52 ++++++++++++++------------ 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/ldapauthenticator/ldapauthenticator.py b/ldapauthenticator/ldapauthenticator.py index 3d26b4d..92755bd 100644 --- a/ldapauthenticator/ldapauthenticator.py +++ b/ldapauthenticator/ldapauthenticator.py @@ -455,38 +455,41 @@ def resolve_username(self, username_supplied_by_user): search_filter=search_filter, attributes=[self.lookup_dn_user_dn_attribute], ) - response = conn.response - if len(response) == 0: + + # identify unique search response entry + n_entries = len(conn.entries) + if n_entries == 0: self.log.warning( f"Failed to lookup a DN for username '{username_supplied_by_user}'" ) return (None, None) - if len(response) > 1: + if n_entries > 1: self.log.warning( f"Failed to lookup a unique DN for username '{username_supplied_by_user}'" ) return (None, None) - if "attributes" not in response[0].keys(): + entry = conn.entries[0] + + # identify unique attribute value within the entry + attribute_values = entry.entry_attributes_as_dict.get( + self.lookup_dn_user_dn_attribute + ) + if not attribute_values: self.log.warning( - f"Failed to lookup attribute '{self.lookup_dn_user_dn_attribute}' for username '{username_supplied_by_user}'" + f"Failed to lookup attribute '{self.lookup_dn_user_dn_attribute}' " + f"for username '{username_supplied_by_user}'" ) return (None, None) + if len(attribute_values) > 1: + self.log.error( + f"A lookup of the username '{username_supplied_by_user}' returned multiple " + f"values for the attribute '{self.lookup_dn_user_dn_attribute}': " + f"({', '.join(attribute_values)})" + ) + return None, None - userdn = response[0]["dn"] - username = response[0]["attributes"][self.lookup_dn_user_dn_attribute] - if isinstance(username, list): - if len(username) == 0: - return (None, None) - elif len(username) == 1: - username = username[0] - else: - self.log.error( - f"A lookup of the username '{username_supplied_by_user}' returned a list " - f"of entries for the attribute '{self.lookup_dn_user_dn_attribute}': " - f"({', '.join(username)})" - ) - return None, None - + userdn = entry.entry_dn + username = attribute_values[0] return (username, userdn) def get_connection(self, userdn, password): @@ -547,6 +550,9 @@ def get_user_attributes(self, conn, userdn): search_filter="(objectClass=*)", attributes=self.auth_state_attributes, ) + # FIXME: Handle situations with multiple entries below or comment + # why its not important to do. + # if found: attrs = conn.entries[0].entry_attributes_as_dict return attrs @@ -632,14 +638,14 @@ async def authenticate(self, handler, data): ), attributes=self.attributes, ) - n_users = len(conn.response) - if n_users == 0: + n_entries = len(conn.entries) + if n_entries == 0: self.log.warning( "Configured search_filter found no user associated with " f"userattr='{self.user_attribute}' and username='{resolved_username}'" ) return None - if n_users > 1: + if n_entries > 1: self.log.warning( "Configured search_filter found multiple users associated with " f"userattr='{self.user_attribute}' and username='{resolved_username}', "