Недавно я написал о том, что такое LDAP и с чем его едят. Сегодня, в продолжение этой темы, расскажу, как работать с LDAP сервером из программы на языке программирования Python. Для создания примеров я использую Python 2.7 и MS Active Directory. В примерах все имена организаций, подразделений и пользователей являются вымышленными, а всякое совпадение с реальностью является совершенно случайным :)
Для работы с LDAP из Python нам понадобится пакет python-ldap. Пакет позволяят работать с различными LDAP-серверами, и с Active Directory, в частности.
>>> import ldap
>>> ad = ldap.initialize("ldap://192.168.0.16")
>>> ad.simple_bind_s("trofimov_a@SKY", "nooneknows")
(97, [], 1, [])
По LDAP URL ldap://192.168.0.16
, который указывает на Active Directory сервер, получен объект LDAPObject
и присвоен переменной ad
. Далее используем метод simple_bind_s
этого объекта для присоединения к серверу, передавая имя и пароль пользователя для аутентификации. (Символы _s
в конце имени метода означают, что метод выполняется синхронно.)
Аутентификация пользователей - одна из функций LDAP сервера, реализуемая операцией bind. Другие функции: поиск, чтение и модификация данных в каталоге.
Найдем и выведем на экран атрибут name
всех подразделений (objectClass=organizationalUnits
) верхнего уровня (ldap.SCOPE_ONELEVEL
) для организации "Синее Небо" (O=Синее Небо,DC=org,DC=ru
):
>>> basedn = 'O=Синее Небо,DC=org,DC=ru'
>>> scope = ldap.SCOPE_ONELEVEL
>>> filterexp = 'objectClass=organizationalUnit'
>>> attrlist = ['name']
>>> results = ad.search_s(basedn, scope, filterexp, attrlist)
>>> for result in results:
... print result[0].decode('utf-8'), result[1]['name'][0].decode('utf-8')
...
OU=Коммерческий отдел,O=Синее Небо,DC=org,DC=ru Коммерческий отдел
OU=Общее руководство,O=Синее Небо,DC=org,DC=ru Общее руководство
OU=Отдел обеспечения,O=Синее Небо,DC=org,DC=ru Отдел обеспечения
OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru Производственный отдел
Метод search_s
возвращает результат поиска как список кортежей (DN записи, словарь с запрошенными атрибутами). А поскольку атрибут может иметь больше одного значения, то значения атрибутов представлены списком. В рассмотренном примере атрибут name
имеет одно значение, то есть, список значений содержит единственный элемент result[1]['name'][0]
.
Значения, которые может принимать параметр scope
(в соответствии со спецификацией LDAP):
ldap.SCOPE_BASE
- запись base DN,ldap.SCOPE_ONELEVEL
- дочерние записи base DN,ldap.SCOPE_SUBTREE
- поддерево с вершиной base DN.
Найду запись о пользователе (objectClass=user)
, указав в списке атрибутов objectClass
, - этот атрибут имеет несколько значений:
>>> basedn = 'O=Синее Небо,DC=org,DC=ru'
>>> scope = ldap.SCOPE_SUBTREE
>>> filterexp = "(&(cn=Трофимов Андрей*)(objectClass=user))"
>>> attrlist = ["sAMAccountName", "mail", "objectClass"]
>>> results = ad.search_s(basedn, scope, filterexp, attrlist)
>>> for result in results:
... print 'DN'.rjust(15) + ' = ' + result[0].decode('utf-8')
... print '\n'.join(x.rjust(15) + ' = ' + str(result[1][x]) for x in attrlist)
...
DN = CN=Трофимов Андрей,OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru
sAMAccountName = ['trofimov_a']
mail = ['trofimov_a@sineenebo.org.ru']
objectClass = ['top', 'person', 'organizationalPerson', 'user']
Несколько значений атрибута objectClass
отражают тот факт, что класс user
явлется наследником классов organizationalPerson
, person
и top
. Таким образом, запись класса user
является одновременно записью каждого из классов-предков.
Атрибут sAMAccountName
содержит имя пользователя, под которым пользователь регистрируется в корпоративном домене, атрибут mail
- адрес электронной почты.
Следующий скрипт выводит на экран имя и адрес электронной почты всех активных пользователей организации "Синее Небо". Приблизительно то же самое делает адресная книга вашего почтового клиента, чтобы вывести доступных адресатов электронной почты.
# -*- coding: utf-8 -*-
import ldap
LDAP_URL = "ldap://192.168.0.16"
USERNAME = "trofimov_a@SKY"
PASSWORD = "nooneknows"
ad = ldap.initialize(LDAP_URL)
ad.simple_bind_s(USERNAME, PASSWORD)
basedn = "O=Синее Небо,DC=org,DC=ru"
scope = ldap.SCOPE_SUBTREE
filterexp = "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(cn=*)(mail=*))"
attrlist = ["cn", "mail"]
results = ad.search_s(basedn, scope, filterexp, attrlist)
for result in results:
print result[1]["cn"][0].decode("utf-8").rjust(35), result[1]["mail"][0]
ad.unbind_s()
Здесь в выражении фильтра расширенная проверка с атрибутом userAccountControl
выбирает только пользователей с отключенной учетной записью (AccountDisabled
), а ее отрицание, соответственно, выбирает активных пользователей. Выражение фильтра также требует наличия у записей атрибутов cn
и mail
.
В отличие от операции поиска, операции LDAP для изменения данных всегда выполняются ровно для одной записи в каталоге, идентифицированной ее уникальным именем DN.
Добавим новую запись класса organizationalPerson
в Производственный отдел:
>>> dn = "CN=Обломов Илья,OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru"
>>> addlist = [
... ("cn", "Обломов Илья"),
... ("sn", "Обломов"),
... ("objectClass", ["organizationalPerson","person","top"]),
... ("telephoneNumber", "2121212")
... ]
>>> ad.add_s(dn, addlist)
(105, [])
Метод add_s
объекта LDAPObject
принимает в качестве параметров DN новой записи и список кортежей (атрибут, значение). Запись успешно добавлена. Для чтения записи создам функцию:
>>> def show_entry(dn):
... try:
... results = ad.search_s(dn, ldap.SCOPE_BASE)
... print "DN".rjust(20), "=", results[0][0].decode("utf-8")
... for attr in ["cn", "sn", "givenName", "telephoneNumber"]:
... print attr.rjust(20), "=", (results[0][1][attr][0].decode("utf-8") if results[0][1].get(attr) else '')
... except:
... print ("Не найден DN %s" % dn).decode("utf-8")
...
>>> show_entry(dn)
DN = CN=Обломов Илья,OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru
cn = Обломов Илья
sn = Обломов
givenName =
telephoneNumber = 2121212
Для изменения существующей записи нужно подготовить список модификаций:
>>> modlist = [
... (ldap.MOD_ADD, "givenName", "Илья"),
... (ldap.MOD_REPLACE, "sn", "Обломоff"),
... (ldap.MOD_DELETE, "telephoneNumber", None)
... ]
Первый элемент каждого кортежа в списке определяет тип модификации, одно из:
- ldap.MOD_ADD - добавить атрибут
- ldap.MOD_REPLACE - заменить атрибут
- ldap.MOD_DELETE - удалить атрибут (или одно из его значений)
Изменяю запись и смотрю результат:
>>> ad.modify_s(dn, modlist)
(103, [])
>>> show_entry(dn)
DN = CN=Обломов Илья,OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru
cn = Обломов Илья
sn = Обломоff
givenName = Илья
telephoneNumber =
Метод rename_s
объекта LDAPObject
позволяет изменить RDN записи:
>>> ad.rename_s(dn, "cn=Обломов Илья Ильич")
(109, [], 10, [])
>>> show_entry(dn)
Не найден DN CN=Обломов Илья Ильич,OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru
>>> dn = "CN=Обломов Илья Ильич,OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru"
>>> show_entry(dn)
DN = CN=Обломов Илья Ильич,OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru
cn = Обломов Илья Ильич
sn = Обломоff
givenName = Илья
telephoneNumber =
Наконец, удаляю экспериментальную запись:
>>> ad.delete_s(dn)
(107, [], 12, [])
>>> show_entry(dn)
Не найден DN CN=Обломов Илья Ильич,OU=Производственный отдел,O=Синее Небо,DC=org,DC=ru
Закрываю соединение с Active Directory:
>>> ad.unbind_s()
Все примеры выше используют синхронные операции с LDAP. Объект LDAPObject
предоставляет также асинхронные методы search
, add
, modify
, rename
, delete
. Эти методы возвращают целочисленный идентификатор операции, который затем нужно передать методу result
для получения результата операции, или методу abandon
- для отмены операции.
Были рассмотрены базовые возможности, предоставлемые пакетом python-ldap
, для чтения и изменения данных в LDAP каталоге.
Позвольте мне представить услуги LE-MERIDIAN FINANCING. кредитная компания, которая предоставляет мне кредит в размере 5 000 000,00 долларов США. Когда другие кредитные инвесторы игнорируют мое предложение, но Le_Meridian Funding Service предоставляет мне успешный кредит. Они непосредственно участвуют в финансировании кредита и проекте с точки зрения инвестиций. они предоставляют финансовые решения компаниям и частным лицам, желающим получить доступ к фондам на рынках капитала, они могут помочь вам профинансировать ваш проект или расширить ваш бизнес. Адрес электронной почты: :::: lfdsloans@lemeridianfds.com Также lfdsloans@outlook.com или напишите на WhatsApp Number 1- (989-394-3740)
ОтветитьУдалитьДоброе намерение,
Нахер ты здесь нужен?
Удалить