# /opt/trueconf_bot/utils/ad_search.py # Универсальный поиск пользователей по нескольким OU в AD. # Каждая функция принимает user_id/email/логин и ищет по всем OU из AD_BASES. # Возвращает первую найденную запись (ldap3 Entry) или None. from ldap3 import Server, Connection, ALL from ldap3.utils.conv import escape_filter_chars import config.config as config def _get_conn(): """Создать соединение с AD.""" server = Server(config.AD_SERVER, get_info=ALL) return Connection(server, user=config.AD_USER, password=config.AD_PASSWORD, auto_bind=True) def search_by_login(login: str, attributes: list[str] | None = None) -> list: """ Найти пользователя по sAMAccountName во всех OU из AD_BASES. Возвращает список Entry (обычно 0 или 1). """ attrs = attributes or ["cn", "sAMAccountName"] conn = _get_conn() for base in config.AD_BASES: conn.search( search_base=base, search_filter="({}={})".format("sAMAccountName", login), attributes=attrs, ) if conn.entries: return list(conn.entries) return [] def search_by_user_id(user_id: str, attributes: list[str] | None = None) -> list: """ Найти пользователя по email/UPN/sAMAccountName во всех OU из AD_BASES. Возвращает список Entry (обычно 0 или 1). """ attrs = attributes or ["cn", "sAMAccountName", "mail", "userPrincipalName", "extensionAttribute2"] safe_id = escape_filter_chars(user_id) short_username = user_id.split("@")[0] if "@" in user_id else user_id safe_sam = escape_filter_chars(short_username) # Строим LDAP filter: (&(objectClass=user)(|(mail=...)(userPrincipalName=...)(sAMAccountName=...))) or_parts = [ "(mail={})".format(safe_id), "(userPrincipalName={})".format(safe_id), "(userPrincipalName={})".format(short_username + "@sibcem.ru"), "(sAMAccountName={})".format(safe_sam), ] or_filter = "(|{})".format("".join(or_parts)) search_filter = "(&{}{})".format("(objectClass=user)", or_filter) conn = _get_conn() for base in config.AD_BASES: conn.search(search_base=base, search_filter=search_filter, attributes=attrs) if conn.entries: return list(conn.entries) return [] def search_by_filter(search_filter: str, attributes: list[str]) -> list: """ Найти по произвольному LDAP-фильтру во всех OU из AD_BASES. Возвращает список Entry. """ conn = _get_conn() for base in config.AD_BASES: conn.search(search_base=base, search_filter=search_filter, attributes=attributes) if conn.entries: return list(conn.entries) return []