From 2ad50f52bfcdec22e62fd2925ab37bbc277893dc Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 13:47:11 +0100 Subject: [PATCH 1/4] :bug: Continue processing groups even if attributes cannot be processed for one of them --- apricot/oauth/microsoft_entra_client.py | 35 ++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/apricot/oauth/microsoft_entra_client.py b/apricot/oauth/microsoft_entra_client.py index 4bc94c8..7ca1e07 100644 --- a/apricot/oauth/microsoft_entra_client.py +++ b/apricot/oauth/microsoft_entra_client.py @@ -1,5 +1,7 @@ from typing import Any, cast +from twisted.python import log + from apricot.types import JSONDict from .oauth_client import OAuthClient @@ -28,19 +30,19 @@ def extract_token(self, json_response: JSONDict) -> str: def groups(self) -> list[JSONDict]: output = [] - try: - queries = [ - "createdDateTime", - "displayName", - "id", - ] - group_data = self.query( - f"https://graph.microsoft.com/v1.0/groups?$select={','.join(queries)}" - ) - for group_dict in cast( - list[JSONDict], - sorted(group_data["value"], key=lambda group: group["createdDateTime"]), - ): + queries = [ + "createdDateTime", + "displayName", + "id", + ] + group_data = self.query( + f"https://graph.microsoft.com/v1.0/groups?$select={','.join(queries)}" + ) + for group_dict in cast( + list[JSONDict], + sorted(group_data["value"], key=lambda group: group["createdDateTime"]), + ): + try: group_uid = self.uid_cache.get_group_uid(group_dict["id"]) attributes: JSONDict = {} attributes["cn"] = group_dict.get("displayName", None) @@ -57,8 +59,11 @@ def groups(self) -> list[JSONDict]: if user["userPrincipalName"] ] output.append(attributes) - except KeyError: - pass + except KeyError as exc: + msg = ( + f"Failed to process group {group_dict} due to a missing key {exc}." + ) + log.msg(msg) return output def users(self) -> list[JSONDict]: From 9ce7f3dc51f365da50481929911d78b74266fce2 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 12:24:15 +0100 Subject: [PATCH 2/4] :memo: Add debug messages for each group and user added to the LDAP tree --- apricot/ldap/oauth_ldap_entry.py | 3 +++ apricot/ldap/oauth_ldap_tree.py | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apricot/ldap/oauth_ldap_entry.py b/apricot/ldap/oauth_ldap_entry.py index d945ef0..6845a33 100644 --- a/apricot/ldap/oauth_ldap_entry.py +++ b/apricot/ldap/oauth_ldap_entry.py @@ -83,3 +83,6 @@ def _bind(password: bytes) -> "OAuthLDAPEntry": raise LDAPInvalidCredentials(msg) return defer.maybeDeferred(_bind, password) + + def list_children(self) -> "list[OAuthLDAPEntry]": + return [cast(OAuthLDAPEntry, entry) for entry in self._children.values()] diff --git a/apricot/ldap/oauth_ldap_tree.py b/apricot/ldap/oauth_ldap_tree.py index 136ce31..88333ec 100644 --- a/apricot/ldap/oauth_ldap_tree.py +++ b/apricot/ldap/oauth_ldap_tree.py @@ -67,15 +67,29 @@ def root(self) -> OAuthLDAPEntry: # Add groups to the groups OU if self.debug: - log.msg(f"Adding {len(oauth_adaptor.groups)} groups to the LDAP tree.") + log.msg( + f"Attempting to add {len(oauth_adaptor.groups)} groups to the LDAP tree." + ) for group_attrs in oauth_adaptor.groups: groups_ou.add_child(f"CN={group_attrs.cn}", group_attrs.to_dict()) + if self.debug: + children = groups_ou.list_children() + for child in children: + log.msg(f"... {child.dn.getText()}") + log.msg(f"There are {len(children)} groups in the LDAP tree.") # Add users to the users OU if self.debug: - log.msg(f"Adding {len(oauth_adaptor.users)} users to the LDAP tree.") + log.msg( + f"Attempting to add {len(oauth_adaptor.users)} users to the LDAP tree." + ) for user_attrs in oauth_adaptor.users: users_ou.add_child(f"CN={user_attrs.cn}", user_attrs.to_dict()) + if self.debug: + children = users_ou.list_children() + for child in children: + log.msg(f"... {child.dn.getText()}") + log.msg(f"There are {len(children)} users in the LDAP tree.") # Set last updated time log.msg("Finished building LDAP tree.") From 801dfe516c65a7616b83dddc65b13606d7c567a9 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 13:48:37 +0100 Subject: [PATCH 3/4] :loud_sound: Add additional debug messages for user and group membership --- apricot/oauth/oauth_data_adaptor.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apricot/oauth/oauth_data_adaptor.py b/apricot/oauth/oauth_data_adaptor.py index 701e55a..2263af5 100644 --- a/apricot/oauth/oauth_data_adaptor.py +++ b/apricot/oauth/oauth_data_adaptor.py @@ -128,6 +128,11 @@ def _retrieve_entries( for parent_dict in oauth_groups + user_primary_groups + groups_of_groups if child_dn in parent_dict["member"] ] + if self.debug: + for group_name in child_dict["memberOf"]: + log.msg( + f"... user '{child_dict['cn']}' is a member of '{group_name}'" + ) # Ensure memberOf is set correctly for groups for child_dict in oauth_groups + user_primary_groups + groups_of_groups: @@ -137,6 +142,11 @@ def _retrieve_entries( for parent_dict in oauth_groups + user_primary_groups + groups_of_groups if child_dn in parent_dict["member"] ] + if self.debug: + for group_name in child_dict["memberOf"]: + log.msg( + f"... group '{child_dict['cn']}' is a member of '{group_name}'" + ) # Annotate group and user dicts with the appropriate LDAP classes annotated_groups = [ From af0653abc5cf5f8f2347cf1236d5cb634b8733fe Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 13:48:11 +0100 Subject: [PATCH 4/4] :bug: Ensure that userPrincipalName key exists before using it to construct group members --- apricot/oauth/microsoft_entra_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apricot/oauth/microsoft_entra_client.py b/apricot/oauth/microsoft_entra_client.py index 7ca1e07..eecfa41 100644 --- a/apricot/oauth/microsoft_entra_client.py +++ b/apricot/oauth/microsoft_entra_client.py @@ -56,7 +56,7 @@ def groups(self) -> list[JSONDict]: attributes["memberUid"] = [ str(user["userPrincipalName"]).split("@")[0] for user in members["value"] - if user["userPrincipalName"] + if user.get("userPrincipalName") ] output.append(attributes) except KeyError as exc: