Выгрузка почтовых адресов из глобального каталога с помощью Python

Мы предоставляем услуги удаленного администрирования серверов

Выгрузка почтовых адресов из глобального каталога с помощью Python

Опубликовано:

Мы рассмотрим простой скрипт для получение всех возможных почтовых адресов по LDAP из Active Directory. Скрипт можно взять за основу и использовать для других реализаций глобального каталога.

Подготовка системы

Рассмотрим процесс подготовки компьютера, на котором будет запускаться скрипт и сервера Active Directory.

Компьютер

В данном примере скрипт будет запускаться на компьютере с Linux.

1. Для начала установим сам Python и дополнительные компоненты:

а) На системах RPM (Red Hat, CentOS, Fedora):

yum install python3 python3-devel openldap-devel

б) На системах DEB (Debian, Ubuntu):

apt-get install python3 python3-pip libsasl2-dev python-dev libldap2-dev libssl-dev

2. Также установим модуль ldap для python:

pip3 install python-ldap

3. Создадим каталог, в котором будет находиться скрипт:

mkdir /scripts

Создадим сам скрипт:

vi /scripts/get_email_from_ad.py

#!/usr/bin/env python3
# -*- encoding: utf-8 -*-

* в данном примере мы создали скрипт get_email_from_ad.py с двумя строчками — шебангом и определением кодировки.

4. Даем разрешение скрипту на запуск:

chmod +x /scripts/get_email_from_ad.py

Active Directory

Для подключения к глобальному каталогу по LDAP нам нужна учетная запись для прохождения авторизации на сервере. Нужна учетная запись с минимальными правами.

Лучше всего для задач скрипта создать отдельного пользователя. В данной инструкции для связывания с Active Directory будет использоваться учетная запись export_emails. Создать ее можно с помощью инструмента Пользователи и компьютеры Active Directory.

Написание скрипта

Чтобы было проще разобраться, начнем разработку по шагам.

1. Подключение по LDAP

Для начала просто подключимся к глобальному каталогу. В наш скрипт добавим:

import ldap

try:
    lconn = ldap.initialize(‘ldap://admins24.local:389’)
    lconn.protocol_version = ldap.VERSION3
    lconn.set_option(ldap.OPT_REFERRALS, 0)
    lconn.simple_bind_s(‘[email protected]’, ‘export_emails_12345!’)
except ldap.SERVER_DOWN:
    print(«Error connection to AD»)

* в данном примере мы подключаемся к серверу admins24.local (домен должен разрешаться в любой из серверов глобального каталога) по порту 389. Для прохождения аутентификации мы используем логин export_emails и пароль export_emails_12345! (учетная запись, которая заранее нами была создана в Active Directory). Также мы указываем, что используется 3 версия протокола ldap и не должны использоваться рефералы.

Пробуем запустить скрипт:

/scripts/get_email_from_ad.py

Он должен вернуть пустую строку. Если мы получим ошибку, то необходимо проверить связь с сервером и корректность введелнных данных (логина и пароля).

2. Получение списка пользователей

Научимся извлекать пользователей по ldap. Добавим в наш скрипт:

base = «DC=admins24,DC=local»
scope = ldap.SCOPE_SUBTREE
filter = «(&(objectcategory=person))»
attrs = [‘displayname’,’title’]
result_set = []

ldap_result_id = lconn.search_ext(base, scope, filter, attrs)

try:
  while 1:
    result_type, result_data = lconn.result(ldap_result_id, 0)
    if (result_data == []):
      break
    else:
      if result_type == ldap.RES_SEARCH_ENTRY:
        result_set.append(result_data)
except ldap.SIZELIMIT_EXCEEDED:
    print()

print(result_set)

* где:

  • base — начальный контейнер, с которого начинаем поиск объектов.
  • scope — область поиска. В нашем примере используется SCOPE_SUBTREE, что означает искать также в дочерних объектах.
  • filter — задаем фильтр. В текущем примере ищем объекты person (пользователи).
  • attrs — атрибуты объектов, которые нас интересуют.
  • result_set — массив данных с полученным результатом.
  • ldap_result_id — идентификатор поиска объектов в каталоге.

Запускаем наш скрипт:

/scripts/get_email_from_ad.py

Мы должны получить массив данных всех найденных пользователей и их атрибутов.

3. Получение почтовых атрибутов

На этом этапе мы отсеем все объекты, у которых нет адреса электронной почты. В итоге, наш массив данных будет содержать пользователей и атрибуты с адресами электронной почты.

Откроем наш скрипт и заменим строки:


filter = «(&(objectcategory=person))»
attrs = [‘displayname’,’title’]

… на:

filter = «(&(mail=*))»
attrs = [‘mail’,’proxyAddresses’]

* в данном примере мы выгрузим все объекты, у которых есть адрес почты (не пустой атрибут mail). Нас будут интересовать 2 атрибута — собственно, mail и proxyAddresses, в котором могут быть перечислены все возможные адреса объекта.
* данный фильтр позволит получить список не только пользователей, но и групп. Возможно, вам это не нужно. Тогда можно изменить наш фильтр, например на «(&(objectcategory=person)(mail=*))» — тогда мы получим только пользователей, у которых есть электронные адреса.

Запускаем наш скрипт:

/scripts/get_email_from_ad.py

Мы должны получить список объектов с адресами электронной почты.

4. Получение списка адресов электронной почты

На конец, вытащим почтовые адреса и составим общий список.

В нашем скрипте удаляем строку:

print(result_set)

Добавляем строки:

all_emails = []
for user in result_set:
    proxyAddresses = user[0][1].get(‘proxyAddresses’)
    mail = user[0][1].get(‘mail’)
    if (proxyAddresses):
        for email_b in proxyAddresses:
            email = email_b.decode(«utf-8»)
            all_emails.append(email.split(‘:’)[1])
    else:
        all_emails.append(mail[0].decode(«utf-8»))

unique_all_emails = list(set(all_emails))
print(*unique_all_emails, sep = ‘\n’)

* и так, данными действиями мы перебираем полученный массив пользователей и извлекаем все email-адреса. Если у пользователя не пустой атрибут proxyAddresses, значит берем адреса из него, если у пользователя есть только mail, то берем его. В итоге, все данные помещаем в массив all_emails, который в конце преобразовываем для получения уникальных значений (в каталоге могут хранится одинаковые email для разных объектов).

Запускаем наш скрипт:

/scripts/get_email_from_ad.py

Мы должны получить список уникальных email-адресов для всех объектов, которые были найдены в глобальном каталоге.

Пример готового скрипта

Написанный нами скрипт можно представить так:

  1. #!/usr/bin/env python3
  2. # -*- encoding: utf-8 -*-
  3.  
  4. # Импортируем python-модули
  5. import ldap
  6.  
  7. # Задаем необходимые переменные
  8. domain = ‘admins24.local’
  9. base = ‘DC=admins24,DC=local’
  10. bind_dn = f’[email protected]{domain}’
  11. bind_dn_password = ‘export_emails_12345!’
  12. scope = ldap.SCOPE_SUBTREE
  13. filter = «(&(mail=*))»
  14. attrs = [‘mail’,’proxyAddresses’]
  15. result_set = []
  16. all_emails = []
  17.  
  18. # Подключаемся к глобальному каталогу по LDAP
  19. try:
  20.     lconn = ldap.initialize(f’ldap://{domain}:389′)
  21.     lconn.protocol_version = ldap.VERSION3
  22.     lconn.set_option(ldap.OPT_REFERRALS, 0)
  23.     lconn.simple_bind_s(bind_dn, bind_dn_password)
  24. except ldap.SERVER_DOWN:
  25.     print(«Error connection to AD»)
  26.  
  27. # Получаем результаты поиска объектов в AD
  28. ldap_result_id = lconn.search_ext(base, scope, filter, attrs)
  29.  
  30. Все результаты поиска объектов заносим в переменную result_set
  31. try:
  32.   while 1:
  33.     result_type, result_data = lconn.result(ldap_result_id, 0)
  34.     if (result_data == []):
  35.       break
  36.     else:
  37.       if result_type == ldap.RES_SEARCH_ENTRY:
  38.         result_set.append(result_data)
  39. except ldap.SIZELIMIT_EXCEEDED:
  40.     print()
  41.  
  42. # Получаем список email-адресов и заносим его в переменную all_emails
  43. for user in result_set:
  44.     proxyAddresses = user[0][1].get(‘proxyAddresses’)
  45.     mail = user[0][1].get(‘mail’)
  46.     if (proxyAddresses):
  47.         for email_b in proxyAddresses:
  48.             email = email_b.decode(«utf-8»)
  49.             all_emails.append(email.split(‘:’)[1])
  50.     else:
  51.         all_emails.append(mail[0].decode(«utf-8»))
  52.  
  53. # Получаем уникальные значения электронных адресов и заносим их в переменную unique_all_emails
  54. unique_all_emails = list(set(all_emails))
  55.  
  56. # Выводим результат на экран
  57. print(*unique_all_emails, sep = ‘\n’)

   Мы принимаем