add: AD lookup test script in ad/

This commit is contained in:
ohmo
2026-07-04 09:42:03 +07:00
parent 33a480a0cd
commit e9861bb5ea
+250
View File
@@ -0,0 +1,250 @@
#!/usr/bin/env python3
"""
Тестовый скрипт — поиск пользователя в Active Directory.
Аналог find_user_in_ad() из sd_dispatcher.py.
Единственная зависимость: ldap3
pip install ldap3
Запуск (перенесите на любой сервер с доступом к AD):
python3 test_ad_lookup.py --user "DOMAIN\\service_account" --pass "password" --login ivanov
python3 test_ad_lookup.py --user "DOMAIN\\service_account" --pass "password" --email ivanov@sibcem.ru
python3 test_ad_lookup.py --user "DOMAIN\\service_account" --pass "password" --phone 79131234567
python3 test_ad_lookup.py --user "DOMAIN\\service_account" --pass "password" --test-all
"""
import argparse
import os
import re
import sys
# =========================================================================
# 1. Подключение к LDAP
# =========================================================================
def connect_to_ad(ad_user, ad_pass):
from ldap3 import Server, Connection
server = Server(
"ldap://172.16.20.20",
get_info=None,
connect_timeout=5,
)
conn = Connection(
server,
user=ad_user,
password=ad_pass,
auto_bind=True,
receive_timeout=5,
)
return conn
# =========================================================================
# 2. Поиск пользователя
# =========================================================================
def find_user(conn, login=None, email=None, phone=None):
"""
Приоритет: телефон > логин > 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: OU=-Пользователи,DC=sibcem,DC=ru")
conn.search(
search_base="OU=-Пользователи,DC=sibcem,DC=ru",
search_filter=filt,
attributes=[
"sAMAccountName", "displayName", "givenName", "sn",
"mail", "title", "department", "l", "company",
"manager", "telephoneNumber", "mobile",
],
)
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']}")
# Руководитель — второй запрос
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
# =========================================================================
# 3. Вывод
# =========================================================================
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-дерево
ou_parts = [p.strip() for p in data["dn"].split(",") if p.strip().startswith("OU=")]
if ou_parts:
print(f"\n OU-структура:")
for i, ou in enumerate(reversed(ou_parts)):
print(f" {' ' * i}└── {ou}")
print("=" * 60)
# =========================================================================
# 4. Тест всех методов
# =========================================================================
def test_all_methods(conn):
print("\n" + "" * 60)
print(" ТЕСТИРОВАНИЕ: все методы поиска")
print("" * 60)
conn.search(
search_base="OU=-Пользователи,DC=sibcem,DC=ru",
search_filter="(objectClass=user)",
attributes=["sAMAccountName", "mail", "telephoneNumber"],
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, **kwargs)
if r:
print_report(r)
print("\n" + "" * 60)
print(" ✅ Готово")
print("" * 60)
# =========================================================================
# MAIN
# =========================================================================
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Поиск пользователя в Active Directory",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Примеры:
python3 test_ad_lookup.py --user "sibcem\\\\svc_ad" --pass "pass" --login ivanov
python3 test_ad_lookup.py --user "sibcem\\\\svc_ad" --pass "pass" --email ivanov@sibcem.ru
python3 test_ad_lookup.py --user "sibcem\\\\svc_ad" --pass "pass" --phone 79131234567
python3 test_ad_lookup.py --user "sibcem\\\\svc_ad" --pass "pass" --test-all
""",
)
parser.add_argument("--user", required=True, help="LDAP user (DOMAIN\\\\account)")
parser.add_argument("--pass", dest="password", required=True, help="LDAP password")
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()
conn = connect_to_ad(args.user, args.password)
print(f"[LDAP] Подключено к ldap://172.16.20.20 как {args.user}")
if args.test_all:
test_all_methods(conn)
else:
data = find_user(conn, login=args.login, email=args.email, phone=args.phone)
if data:
print_report(data)
conn.unbind()