Files
trueconf_bot/utils/ad_search.py
T
Денис Кривоченко 3fa7543477 fix: LDAP filter malformed — добавлен символ '|' в or_filter
search_by_user_id: or_filter был '(...)' вместо '(|...)' — LDAP требовал OR-оператор
2026-07-22 18:53:34 +07:00

74 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# /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 []