From bc3b18790722638c2b8df97b25946434ac408f55 Mon Sep 17 00:00:00 2001 From: Julian Rother <julian@cccv.de> Date: Wed, 6 Apr 2022 14:47:51 +0200 Subject: [PATCH] Fix behavior if LDAP errors occur during SEARCH LDAP errors were previously misinterpreted as an empty set of results, causing mass-unsubscription of list members. Fixes #1 --- .../commands/syncldapmemberships.py | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/postorius_ldap_membership_management/management/commands/syncldapmemberships.py b/postorius_ldap_membership_management/management/commands/syncldapmemberships.py index fffe710..9f7e672 100644 --- a/postorius_ldap_membership_management/management/commands/syncldapmemberships.py +++ b/postorius_ldap_membership_management/management/commands/syncldapmemberships.py @@ -14,6 +14,20 @@ from allauth.account.models import EmailAddress logger = logging.getLogger(__name__) +def execute_ldap_search_without_hiding_errors(search, connection, filterargs=(), escape=True): + '''If an LDAPError occurs during search.execute, it logs the error and returns + an empty list of results. This behavor is indistinguishable from a query + with no results.''' + if not isinstance(search, LDAPSearch): + raise NotImplementedError(f'{type(search)} is not supported by django_auth_ldap_remoteuser') + # This is a copy of django_auth_ldap.config.LDAPSearch.execute without the + # ldap.LDAPError eating try-except block + if escape: + filterargs = search._escape_filterargs(filterargs) + filterstr = search.filterstr % filterargs + results = connection.search_s(search.base_dn, search.scope, filterstr, search.attrlist) + return search._process_results(results) + class Command(BaseCommand): can_import_settings = True help = 'Synchronize mailing list memberships from a LDAP server' @@ -29,9 +43,6 @@ class Command(BaseCommand): client = get_mailman_client() - user_search = django.conf.settings.AUTH_LDAP_USER_SEARCH_ALL_NAME - results = user_search.execute(conn) - ldap_users = [list(attr.values())[0][0] for dn, attr in results ] django_users = get_user_model().objects.all() backref_mapping = {'member': 'members', 'moderator': 'moderators', 'owner': 'owners'} mm_users = {} @@ -61,11 +72,11 @@ class Command(BaseCommand): for membership_type in ldap_setting: if not ldap_setting[membership_type].get('enabled'): continue - ldap_members = LDAPSearch( + ldap_members = execute_ldap_search_without_hiding_errors(LDAPSearch( ldap_setting[membership_type]['dn'], ldap.SCOPE_SUBTREE, ldap_setting[membership_type]['filter'], - [ldap_setting[membership_type]['username_attr']]).execute(conn) - ldap_member_names = [list(attr.values())[0][0] for dn, attr in ldap_members ] + [ldap_setting[membership_type]['username_attr']]), conn) + ldap_member_names = [list(attr.values())[0][0] for dn, attr in ldap_members] # we refetch the mm_list each time because of wired caching problems mm_list = client.get_list(list_name) -- GitLab