Архив метки: Active Directory

Корзина в Active Directory (Active Directory Recycle Bin)

Корзина в Active Directory (Active Directory Recycle Bin)

В продолжении темы о восстановлении объектов в Active Directory. В данной статье речь пойдет об инструменте, который призван облегчить процесс восстановления данных и сделать его более эффективным. Речь идет о Active Directory Recycle Bin, или корзине для удаленных объектов Active Directory. Принцип работы корзины Для начала вспомним, как выглядит жизненный цикл объекта AD при удалении. Объект помечается как удаленный (атрибут isDeleted объекта устанавливается в true) и из него удаляются лишние атрибуты. Затем он переименовывается и перемещается в контейнер Deleted Objects, в котором хранится в течение срока жизни удаленного объекта. По истечении этого срока он удаляется окончательно.Принцип работы корзины Читать

Как скрыть неиспользуемые контейнеры в Active Directory

В статье пойдет речь о том как скрыть неиспользуемые контейнеры в Active Directory

В оснастке Active Directory Users and Computers (ADUC), находятся контейнеры (Organization Unit, OU), в которые помещаются учетные записи пользователей, компьютеров и групп. В зависимости от размера и структуры организации количество OU может быть весьма большим.

Также оснастке ADUC присутствуют предопределенные контейнеры. Большинство из них практически не используются, однако болтаются в оснастке, загромождая место и затрудняя администрирование AD.

Вот так выглядит оснастка ADUC сразу после установки служб Active Directory. По умолчанию в ней отображаются следующие контейнеры:

• Builtin — контейнер, который содержит встроенные группы безопасности (Administrators, Backup Operators, Event Log Readers и так далее);

• Computers — контейнер для компьютеров по умолчанию;

• Domain Controllers — контейнер для контроллеров домена;

• ForeignSecurityPrincipals — контейнер, используемый для хранения идентификаторов безопасности (SID), связанных с доверенными доменами;

• Managed Service Accounts — контейнер для управляемых учетных записей служб;

• Users — контейнер для пользователей и групп по умолчанию. В нем содержатся такие важные группы, как Domain, Enterprise и Schema Admins. Читать

Как работать с LDAP в Python

Недавно я написал о том, что такое 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 каталоге.

Автор: Andrei Trofimov
Дата публикации: 2013-11-10T18:05:00.000+11:00