From ecc94434006659aad43183d27f59491a79fb6f23 Mon Sep 17 00:00:00 2001 From: dddennnisss Date: Sat, 4 Jul 2026 09:43:46 +0700 Subject: [PATCH] fix: remove root test_ad_lookup.py, moved to ad/ --- test_ad_lookup.py | 283 ---------------------------------------------- 1 file changed, 283 deletions(-) delete mode 100644 test_ad_lookup.py diff --git a/test_ad_lookup.py b/test_ad_lookup.py deleted file mode 100644 index f078d75..0000000 --- a/test_ad_lookup.py +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/env python3 -""" -Тестовый скрипт для проверки обращения к Active Directory. -Аналог find_user_in_ad() из sd_dispatcher.py — standalone. - -Установка зависимостей (на сервере 192.168.1.106): - python3 -m pip install ldap3 - -Использование: - # 1) Через аргументы: - python3 test_ad_lookup.py --user "sibcem\\svc_dispatcher" --pass "password" --login ivanov - - # 2) Через env-переменные: - export AD_USER="sibcem\\svc_dispatcher" - export AD_PASS="password" - python3 test_ad_lookup.py --login ivanov - - # 3) По email: - python3 test_ad_lookup.py --email ivanov@sibcem.ru - - # 4) По телефону: - python3 test_ad_lookup.py --phone 79131234567 - - # 5) Тест: найти первого попавшегося пользователя и проверить все методы: - python3 test_ad_lookup.py --test-all -""" - -import argparse -import os -import re -import sys - -# --------------------------------------------------------------------------- -# 1. Загрузка учётных данных -# --------------------------------------------------------------------------- - -def get_credentials(): - """Возвращает (user, password, base_dn).""" - user = os.getenv("AD_USER", "").strip() - password = os.getenv("AD_PASS", "").strip() - base = os.getenv("AD_BASE", "").strip() or "OU=-Пользователи,DC=sibcem,DC=ru" - - return user, password, base - - -# --------------------------------------------------------------------------- -# 2. Подключение к LDAP -# --------------------------------------------------------------------------- - -def connect_to_ad(ad_user, ad_pass, ad_base): - """Возвращает подключённый ldap3.Connection.""" - from ldap3 import Server, Connection - - server = Server( - "ldap://172.16.20.20", - get_info=None, # не тянем schema — экономим время - connect_timeout=5, - ) - conn = Connection( - server, - user=ad_user, - password=ad_pass, - auto_bind=True, - receive_timeout=5, - ) - return conn, ad_base - - -# --------------------------------------------------------------------------- -# 3. Поиск пользователя -# --------------------------------------------------------------------------- - -def find_user(conn, ad_base, login=None, email=None, phone=None): - """ - Ищет пользователя в AD. Приоритет: телефон > логин > email. - Возвращает dict с атрибутами или None. - """ - if phone: - filt = ( - f"(|(telephoneNumber=*{phone}*)(mobile=*{phone}*) " - f"(homePhone=*{phone}*)(pager=*{phone}*) " - f"(facsimileTelephoneNumber=*{phone}*)(ipPhone=*{phone}*))" - ) - by = f"телефону {phone}" - elif login: - clean = login.split("\\")[-1].split("/")[-1] - filt = f"(sAMAccountName={clean})" - by = f"логину {clean}" - elif email: - filt = f"(mail={email})" - by = f"почте {email}" - else: - print("❌ Укажите --login, --email или --phone") - sys.exit(1) - - print(f"\n[LDAP] Поиск: {filt}") - print(f"[LDAP] Base DN: {ad_base}") - - # Запрос 1 — основной - conn.search( - search_base=ad_base, - search_filter=filt, - attributes=["l", "company", "manager", "department", "ou", - "displayName", "mail", "sAMAccountName", "title", - "telephoneNumber", "mobile", "givenName", "sn"], - ) - - if not conn.entries: - print(f"\n❌ Пользователь не найден по {by}") - return None - - user = conn.entries[0] - print(f"\n✅ Найдено: {user.entry_dn}") - - result = { - "sam": user.sAMAccountName.value if "sAMAccountName" in user else None, - "given_name": user.givenName.value if "givenName" in user else None, - "surname": user.sn.value if "sn" in user else None, - "display_name": user.displayName.value if "displayName" in user else None, - "mail": user.mail.value if "mail" in user else None, - "title": user.title.value if "title" in user else None, - "department": user.department.value if "department" in user else None, - "city": user.l.value if "l" in user and user.l.value else None, - "company": user.company.value if "company" in user and user.company.value else None, - "dn": user.entry_dn, - "phone": user.telephoneNumber.value if "telephoneNumber" in user else None, - "mobile": user.mobile.value if "mobile" in user else None, - } - - # Город из OU-пути если атрибут l пустой - if not result["city"]: - match = re.search(r"OU=([^,]+),OU=-Пользователи", result["dn"], re.IGNORECASE) - if match: - result["city"] = match.group(1).strip() - if result["city"].lower() == "красноярск" and "OU=ООО Комбинат Волна" in result["dn"]: - result["company"] = "ООО Комбинат Волна" - print(f" Город извлечён из OU: {result['city']}") - - # Запрос 2 — email руководителя - manager_dn = user.manager.value if "manager" in user else None - if manager_dn: - conn.search( - search_base=manager_dn, - search_filter="(objectClass=user)", - attributes=["mail", "displayName"], - search_scope="BASE", - ) - if conn.entries and "mail" in conn.entries[0]: - result["manager_email"] = conn.entries[0].mail.value - result["manager_name"] = conn.entries[0].displayName.value if "displayName" in conn.entries[0] else None - else: - result["manager_email"] = None - else: - result["manager_email"] = None - - return result - - -# --------------------------------------------------------------------------- -# 4. Форматирование вывода -# --------------------------------------------------------------------------- - -def print_report(data): - """Красивый вывод результатов.""" - print("\n" + "=" * 60) - print(" РЕЗУЛЬТАТ ПОИСКА В ACTIVE DIRECTORY") - print("=" * 60) - print(f" sAMAccountName: {data['sam']}") - print(f" Имя: {data['given_name']}") - print(f" Фамилия: {data['surname']}") - print(f" ФИО: {data['display_name']}") - print(f" Email: {data['mail']}") - print(f" Должность: {data['title']}") - print(f" Отдел: {data['department']}") - print(f" Город: {data['city'] or '—'}") - print(f" Компания: {data['company'] or '—'}") - print(f" Телефон: {data['phone'] or '—'}") - print(f" Мобильный: {data['mobile'] or '—'}") - print(f" Руководитель: {data['manager_name'] or '—'}") - if data.get("manager_email"): - print(f" Email руково.: {data['manager_email']}") - print("-" * 60) - print(f" DN: {data['dn']}") - - # OU-дерево - dn = data["dn"] - parts = [p.strip() for p in dn.split(",")] - ou_parts = [p for p in parts if p.startswith("OU=")] - if ou_parts: - print(f"\n OU-структура:") - for i, ou in enumerate(reversed(ou_parts)): - indent = " " * i - print(f" {indent}└── {ou}") - - print("=" * 60) - - -# --------------------------------------------------------------------------- -# 5. Тестирование всех методов поиска -# --------------------------------------------------------------------------- - -def test_all_methods(conn, ad_base): - """Находит первого пользователя и проверяет все методы поиска.""" - print("\n" + "─" * 60) - print(" РЕЖИМ ТЕСТИРОВАНИЯ: поиск по всем методам") - print("─" * 60) - - conn.search( - search_base=ad_base, - search_filter="(objectClass=user)", - attributes=["sAMAccountName", "mail", "telephoneNumber", "displayName", - "l", "company", "department"], - size_limit=1, - ) - - if not conn.entries: - print("❌ В AD нет пользователей.") - return - - sample = conn.entries[0] - sam = sample.sAMAccountName.value - mail = sample.mail.value if "mail" in sample else None - phone = sample.telephoneNumber.value if "telephoneNumber" in sample else None - - print(f"\n📌 Тестовый пользователь: {sam} ({mail})") - - for label, kwargs in [("логину", {"login": sam}), - ("email", {"email": mail}) if mail else None, - ("телефону", {"phone": phone}) if phone else None]: - if kwargs is None: - continue - print(f"\n[Тест] Поиск по {label}...") - r = find_user(conn, ad_base, **kwargs) - if r: - print_report(r) - - print("\n" + "─" * 60) - print(" ✅ Тестирование завершено") - print("─" * 60) - - -# --------------------------------------------------------------------------- -# MAIN -# --------------------------------------------------------------------------- - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Тестовый поиск пользователя в AD") - parser.add_argument("--user", help="LDAP user (sAMAccountName или DN)") - parser.add_argument("--pass", dest="password", help="LDAP password") - parser.add_argument("--base", help="Base DN (по умолчанию OU=-Пользователи,DC=sibcem,DC=ru)") - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("--login", help="sAMAccountName пользователя для поиска") - group.add_argument("--email", help="Email пользователя для поиска") - group.add_argument("--phone", help="Номер телефона для поиска") - parser.add_argument("--test-all", action="store_true", - help="Найти первого пользователя и протестировать все методы поиска") - args = parser.parse_args() - - # Учётные данные: аргументы > env > prompt - ad_user = args.user or os.getenv("AD_USER", "") - ad_pass = args.password or os.getenv("AD_PASS", "") - ad_base = args.base or os.getenv("AD_BASE", "OU=-Пользователи,DC=sibcem,DC=ru") - - if not ad_user or not ad_pass: - # Пробуем получить из .env файла проекта - env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "sd_dispatcher", "config", ".env") - if os.path.exists(env_path): - print(f"[.env] Загружено: {env_path}") - else: - print("❌ Укажите --user и --pass, или задайте AD_USER / AD_PASS") - sys.exit(1) - - conn, ad_base = connect_to_ad(ad_user, ad_pass, ad_base) - print(f"[LDAP] Подключено к ldap://172.16.20.20 как {ad_user}") - - if args.test_all: - test_all_methods(conn, ad_base) - else: - data = find_user(conn, ad_base, login=args.login, email=args.email, phone=args.phone) - if data: - print_report(data) - - conn.unbind()