From 97726636201a328591a75cebd9826f8ecadb8002 Mon Sep 17 00:00:00 2001
From: Julian Rother <julian@cccv.de>
Date: Wed, 6 Apr 2022 11:45:22 +0200
Subject: [PATCH] Fix behavior if LDAP errors occur during SEARCH

LDAP errors were previously misinterpreted as empty set of results, causing
mass-deletion of all user accounts. This works around the issue, but limits the
allowed type of AUTH_LDAP_USER_SEARCH_ALL_NAME to LDAPSearch.

Fixes #1
---
 .../management/commands/syncldap.py              | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/django_auth_ldap_remoteuser/management/commands/syncldap.py b/django_auth_ldap_remoteuser/management/commands/syncldap.py
index 5541bb6..92fd7d2 100644
--- a/django_auth_ldap_remoteuser/management/commands/syncldap.py
+++ b/django_auth_ldap_remoteuser/management/commands/syncldap.py
@@ -4,8 +4,22 @@ from django.core.management.base import BaseCommand
 from django.contrib.auth import load_backend, login
 from django.contrib.auth.backends import RemoteUserBackend
 from django.contrib.auth import get_user_model
+from django_auth_ldap.config import LDAPSearch
 import django.conf
 
+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
@@ -21,7 +35,7 @@ class Command(BaseCommand):
 		conn.simple_bind_s(ldap_backend.settings.BIND_DN, ldap_backend.settings.BIND_PASSWORD)
 
 		user_search = django.conf.settings.AUTH_LDAP_USER_SEARCH_ALL_NAME
-		results = user_search.execute(conn)
+		results = execute_ldap_search_without_hiding_errors(user_search, conn)
 		ldap_users = [list(attr.values())[0][0] for dn, attr in results ]
 		django_users = get_user_model().objects.all()
 
-- 
GitLab