Перейти на главную страничку сайта (список статей, файлы для скачивания)

ФОРУМ (здесь можно обсудить эту статью, а также любые проблемы программирования на различных макроязыках и в скриптовых средах)

Использование протокола LDAP в скриптах

Содержание:

Введение

Протокол LDAP (Lightweight Directory Access Protocol, упрощённый протокол для доступа к каталогу) служит для доступа к службам каталогов, в том числе Active Directory в Windows 2000/2003. Провайдер LDAP является одним из провайдеров ADSI (Active Directory Service Interface). Все примеры сценариев в настоящей статье будут приводиться на языке Python.

Служба каталогов Active Directory является LDAP-совместимой реализацией службы каталогов Microsoft для операционных систем семейства Windows и хранит информацию о сетевых ресурсах - пользователях, компьютерах, файлах, папках и принтерах, а также информацию безопасности, касающуюся этих ресурсов. Active Directory упрощает администрирование путём централизации управления. Домен - это логическая группа компьютеров и метод организации административной безопасности. Логическая структура Active Directory состоит из доменов, лесов и деревьев, а физическая структура состоит из серверов - контроллеров домена и сайтов (IP-подсетей). Active Directory использует модель репликации, когда копия каталога существует на каждом контроллере домена, что повышает отказоустойчивость (домен может содержать один или более контроллеров домена). Сайт (Site) Active Directory - это совокупность одной или нескольких IP-подсетей, объединенных высокоскоростными каналами связи. Сайт может содержать один или более доменов, а домен может быть размещен в нескольких сайтах. Сайты предназначены для управления репликацией Active Directory между сетями, соединёнными каналами связи с низкой пропускной способностью.

Домены в Active Directory организованы в иерархические структуры - деревья. Ветви такого дерева называются поддоменами. Имя дочернего домена включает имя родительского, например: microsoft.com, msdn.microsoft.com, vb.msdn.microsoft.com и т.д. Лес представляет собой группу деревьев, связанных доверительными отношениями - контроллеры домена в одном домене доверяют пользователям из другого домена (дают возможность использовать свои ресурсы). Отношения доверия транзитивны, то есть если домен А доверяет домену Б, а домен Б доверяет домену В, то домен А также доверяет домену В. Все деревья в лесу используют общую схему и общий глобальный каталог (Global Catalog, GC). Доверительными отношениями связываются корневые домены деревьев леса.

Схема (Schema) содержит формальное описание содержания и структуры хранилища Active Directory, включая все атрибуты, классы и свойства классов. Для каждого класса объектов схема определяет, какими атрибутами должен обладать экземпляр класса, какие дополнительные атрибуты он может иметь и какой класс объектов является предком текущего класса. При установке Active Directory создаётся стандартная схема, содержащая определения наиболее часто используемых объектов и их свойств, таких как пользователи, группы, компьютеры, принтеры и т.п. Схема Active Directory расширяема, т.е. вы можете определить новые типы объектов каталога и их атрибуты, в том числе и новые атрибуты для существующих объектов. Схема хранится вместе с данными Active Directory в глобальном каталоге и обновляется динамически (т.е. добавленные и изменённые атрибуты можно использовать практически сразу). Схема определяет структуру леса Active Directory, который может содержать несколько деревьев, которые, в свою очередь, могут содержать несколько иерархически структурированных доменов. В лесе Active Directory один из контроллеров объявляется мастером схемы (Schema Master) и отвечает за репликацию данных схемы на все контроллеры доменов. Cтруктурой леса и деревьев Active Directory является конфигурация (Configuration).

Глобальный каталог (Global Catalog, GC) - это центральное хранилище информации об объектах в дереве доменов и лесе Active Directory. Глобальный каталог является физическим хранилищем части атрибутов всех объектов леса Active Directory. Процесс частичной репликации позволяет находить большинство сведений непосредственно в глобальном каталоге, без обращения к исходному домену. По умолчанию в глобальном каталоге хранятся атрибуты, наиболее часто используемые при поиске (например имя пользователя, его учетной записи и т.п.), а также сведения, необходимые для обнаружения объекта (полный LDAP-путь к соответствующему объекту каталога). Хранение только основных атрибутов объектов в глобальном каталоге позволяет уменьшить его размер, поэтому один сервер глобального каталога может обслуживать много контроллеров домена Windows. При установке первого контроллера домена в лесу Active Directory он становится сервером глобального каталога. При наличии нескольких контроллеров домена можно перенести глобальный каталог на другой сервер или настроить несколько серверов на его поддержку.

В ADSI предусмотрен специальный провайдер "ADs", который возвращает ссылку на объект IADsNamespaces, который можно использовать для получения информации об установленных на компьютере провайдерах ADSI:

import win32com.client

adsi = win32com.client.GetObject("ADs:")
print adsi.Class, "\n"
for i in adsi:
    print i.Name

Корневой объект пространства имён провайдера LDAP (объект IADsNamespace) может быть получен следующим образом:

# -*- coding: cp1251 -*-
import win32com.client

# получение объекта текущего домена в локальной сети:
adsi = win32com.client.GetObject("LDAP:")
print adsi.Class, adsi.ADsPath, '\n'
for i in adsi:
    print i.Class, i.ADsPath
    print i.Name, "\n"

# получение объекта корневого домена в локальной сети:
adsi = win32com.client.GetObject("GC:")
print adsi.Class, adsi.ADsPath, '\n'
for i in adsi:
    print i.Class, i.ADsPath
    print i.Name, "\n"
# Примечание: в данном случае идёт обращение
# к глобальному каталогу контроллера домена (Global Catalog, GC).

LDAP имеет иерархическую модель данных. Вы можете исследовать структуру ADSI с помощью оснастки ADSI Edit для MMC из пакета Windows Support Tools (пакет доступен для скачивания на сайте Microsoft). Для идентификации объектов существует два вида имен:

Отличительное имя объекта содержит полный путь к этому объекту в иерархии. Относительное отличительное имя объекта — часть отличительного имени, являющаяся именем объекта.

Кроме того, в каталоге существуют организационные блоки (организационные единицы или подразделения) Organization Units - OU, с помощью которых администратор каталога может создавать иерархию логических групп записей. Организационное подразделение - это контейнерный объект, предназначенный для группировки других объектов в логические административные группы в рамках домена. Организационные подразделения могут содержать такие объекты, как учетные записи пользователей, группы, компьютеры, принтеры и т.п. Иерархия организационных единиц домена не зависит от других доменов - каждый домен может поддерживать свою собственную иерархию. Часто групповые политики применяются именно к подразделениям (групповые политики сами являются объектами Active Directory).

Пользователь или группа имеет "дружественное" имя – основное имя пользователя (UPN – User Principal Name). Основное имя пользователя составляется из "сокращённого" имени пользователя и имени домена DNS, где находится объект, определяющий пользователя. UPN известны как адреса электронной почты. Например, пользователь James Smith в дереве microsoft.com может иметь UPN вида "JamesS@Microsoft.com".

Каждый объект каталога обладает глобальным уникальным идентификатором (Globally Unique Identifier, GUID) - 128-битным числом, генерируемым при создании объекта. GUID не изменяется в течение всего срока жизни объекта, даже при его переименовании или перемещении в другой домен. Поэтому приложения могут хранить GUID объекта и всегда однозначно находить его в каталоге.

Аббревиатуры, используемые в строках подключения (в так называемых URL LDAP):

Для связывания (определения) объекта с помощью технологии ADSI можно использовать два способа:

Как видно из примеров, строки связывания в разных формах отличаются в основном направлением переходов по иерархии (вверх или вниз по иерархии). Примечание: порт можно указать только во второй форме, порт по умолчанию - 389.

Имя сервера (контроллера домена) и номер порта можно не указывать. В этом случае программные модули ADSI автоматически найдут контроллер домена для указанного вами домена и произведут к нему подключение с параметрами по умолчанию. При этом используются те же механизмы, что и при входе клиентского компьютера в сеть (такой вариант называется привязкой без сервера - serverless binding). Например:

adsi = win32com.client.GetObject("LDAP://DC=ru/DC=имяДомена/OU=название подразделения/CN=имя пользователя")
adsi = win32com.client.GetObject("LDAP://CN=имя пользователя, OU=название подразделения, DC=имяДомена, DC=ru")

Для просмотра атрибутов записи каталога можно связать запись, а затем использовать метод Get. Если сервер LDAP разрешает анонимный доступ к каталогу, можно использовать следующий подход:

adsi = win32com.client.GetObject("LDAP://DC=ru/DC=имяДомена/OU=название подразделения")
for entry in adsi:
    print entry.Class, entry.Get('objectClass')

Если сервер LDAP не разрешает анонимный доступ к каталогу, можно использовать следующий подход:

dso = win32com.client.GetObject("LDAP:")
adsi = dso.OpenDSObject("LDAP://DC=ru/DC=имяДомена/OU=название подразделения",
                        "имя_пользователя", "пароль", 0)
for entry in adsi:
    print entry.Class, entry.Get('objectClass')

Для просмотра архитектуры существующего каталога LDAP используйте скрипт, приведённый чуть ниже. Изменяя отправную точку (startingPoint), можно просмотреть различные части каталога:

startingPoint = "/OU=название подразделения"
adsi = win32com.client.GetObject("LDAP://DC=ru/DC=имяДомена" + startingPoint)
for entry in adsi:
    print entry.Name, entry.Class

Рекурсивный просмотр архитектуры существующего каталога LDAP, вглубь от указанной отправной точки (startingPoint):

# -*- coding: cp1251 -*-
import win32com.client

def structLDAP(startingPoint, level):
    adsi = win32com.client.GetObject("LDAP://" + startingPoint)
    for entry in adsi:
        print '  ' * level + entry.Name + ' (' + entry.Class + ')'
        # для перенаправления в файл:
        # print ('  ' * level + entry.Name + ' (' + entry.Class + ')').encode('cp1251')
        structLDAP(startingPoint + '/' + entry.Name.replace('/', '\\/'), level + 1)

startingPoint = "DC=ru/DC=имяДомена"
structLDAP(startingPoint, 0)

Специальный объект RootDSE (Root Directory Service Entry) автоматически вернёт имя того домена, к которому принадлежит данный компьютер:

# получение имени домена, к которому принадлежит данный компьютер:
adsi = win32com.client.GetObject("LDAP://RootDSE")
domain = adsi.Get("defaultNamingContext")
adsi = win32com.client.GetObject("LDAP://" + domain)
print adsi.Name, adsi.Class

Объект RootDSE предоставляет различную информацию о возможностях LDAP-сервера:

# -*- coding: cp1251 -*-
import win32com.client
adsi = win32com.client.GetObject("LDAP://RootDSE")
print adsi.Get("configurationNamingContext") # отличительное имя контейнера конфигурации
print adsi.Get("currentTime") # текущее время на этом сервере каталога
print adsi.Get("defaultNamingContext") # отличительное имя домена, членом которого является этот сервер каталога
print adsi.Get("dnsHostName") # DNS адрес этого сервера каталога
print adsi.Get("dsServiceName") # отличительное имя объекта NTDS параметров настройки этого сервера каталога
# наивысший USN, используемый на этом сервере каталога (это свойство используется репликацией каталога)
print adsi.Get("highestCommittedUSN")
print adsi.Get("LDAPServiceName") # Service Principal Name (SPN) этого сервера каталога
print
for namingContext in adsi.Get("namingContexts"): # отличительные имена всех контекстов, имеющихся на этом сервере каталога
   print namingContext
print
# отличительное имя корневого домена в лесу, который содержит домен, членом которого является этот сервер каталога
print adsi.Get("rootDomainNamingContext")
print adsi.Get("schemaNamingContext") # отличительное имя контейнера схемы
print adsi.Get("serverName") # отличительное имя объекта сервера этого сервера каталога в контейнере конфигурации
print adsi.Get("subschemaSubentry") # отличительное имя объекта subschema (LDAP 3.0.)
# объектные идентификаторы (OID), которые идентифицирует поддерживаемые возможности сервера
print adsi.Get("supportedCapabilities")
print
for supportedControl in adsi.Get("supportedControl"): # расширенные OID
    print supportedControl
print
for supportedLDAPPolice in adsi.Get("supportedLDAPPolicies"): # поддерживаемые LDAP политики управления
    print supportedLDAPPolice
print
for supportedLDAPVersion in adsi.Get("supportedLDAPVersion"): # версии LDAP, поддерживаемые этим сервером каталога
    print supportedLDAPVersion
print
for supportedSASLMechanism in adsi.Get("supportedSASLMechanisms"): # поддерживаемые механизмы безопасности
    print supportedSASLMechanism

Поиск объектов в каталоге

В ADSI реализовано несколько технологий поиска. Основная технология связана с применением для этой цели возможностей объектной модели ADO. При этом подключение к службе каталогов производится при помощи объекта ADODB.Connection, формулировка текста запроса и его выполнение — при помощи объекта ADODB.Command, а результаты запроса возвращаются в виде обычного объекта ADODB.Recordset. Объектная модель ADO полностью поддерживает OLE Automation, поэтому эту технологию можно использовать из любых языков программирования, которые поддерживают OLE Automation, в том числе VBA, VBScript, JScript и т.п. Остальные технологии поиска ADSI могут использоваться в основном только из программ на языке C++, и здесь рассматриваться не будут.

Запросы к службам каталогов в ADSI могут выполняться на двух диалектах - диалекте LDAP (фильтры запроса определяются в соответствии с правилами синтаксиса запросов LDAP по RFC 2254) и диалекте SQL (фильтры запроса определяются в соответствии со стандартом ANSI SQL с учетом особенностей работы со службами каталогов).

Пример запроса на диалекте LDAP:

<LDAP://DC=domainName,DC=ru>;(objectClass=*);AdsPath, cn;subTree

Первая часть запроса - базовое отличительное имя (base distinguished name) - использует синтаксис вида <LDAP://отличительное_имя>. Отличительное имя должно принадлежать контейнерному объекту, в котором производится поиск (обычно домену, сайту или организационному подразделению).

Вторая часть запроса (в примере - (objectClass=*)) является поисковым фильтром LDAP. В примере фильтр означает "искать любые объекты".

Третья часть запроса (в примере - AdsPath, cn) является набором атрибутов (столбцов), которые будут возвращаться в ходе выполнения запроса. Если необходимо вернуть несколько атрибутов для объекта, наименования атрибутов должны быть разделены запятыми.

Четвертая часть запроса (в примере - subTree) задаёт диапазон поиска. Возможные значения:

Для поисковых фильтров LDAP предусмотрено два варианта синтаксиса. Первый вариант использует только один фильтр:

(<имя_атрибута><оператор><значение>)

Второй вариант использует несколько фильтров, объединённых логическим оператором:

(<оператор><фильтр1><фильтр2>...<фильтрN>)

Операторы, используемые в фильтрах поиска LDAP:


=Равно.
~=Приблизительно равно.
<=Меньше или равно.
>=Больше или равно.
&И
|ИЛИ
!НЕ
*Групповой подстановочный символ (любое количество символов).

Примеры:


(objectClass=*) Для атрибута objectClass может быть использовано любое значение (т.е. вернутся все объекты).
(&(objectCategory=person)(objectClass=user)(!cn=andy)) Несколько фильтров объединены при помощи оператора "И". Вернутся только те объекты, у которых одновременно: атрибут objectCategory имеет значение "person", атрибут objectClass - значение "user", атрибут cn - значение, не равное "andy".
(&(objectCategory=person)(objectClass=contact)(|(sn=Lee)(sn=Smith))) Вернутся все объекты, у которых значение атрибута objectCategory равно "Person", objectClass - "contact", а значение атрибута sn равно либо "Lee", либо "Smith".

Для проверки наличия определенных флагов в атрибутах объектов применяется синтаксис с использованием так называемых объектных идентификаторов (object identifiers, OIDs). LDAP поддерживает два OID:

Чаще всего OID используются при проверке флагов типов групп. Например, если необходимо найти все группы безопасности, но не группы распределения, синтаксис может быть таким:

(&(objectCategory=group)(groupType:1.2.840.113556.1.4.803:=2147483648))

Здесь число 2147483648 - это десятичное представление числа 0x80000000, которое соответствует флагу ADS_GROUP_TYPE_SECURITY_ENABLED в атрибуте groupType.

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


*\2a
(\28
)\29
\\5c
NUL\00
/\2f

Пример скрипта, разыскивающего все объекты в домене, в имени которых используется прямой слеш:

# -*- coding: cp1251 -*-
import win32com.client
conn = win32com.client.Dispatch("ADODB.Connection")
conn.Provider = "ADSDSOObject"
conn.Open("ADs Provider")
query = "<LDAP://DC=имяДомена,DC=ru>;(Name=*\\2f*);ADsPath;subTree"
rs = conn.Execute(query)[0]
while not rs.EOF:
    obj = win32com.client.GetObject(rs.Fields(0).Value)
    print obj.Class, obj.Name
    rs.MoveNext()
conn.Close()

Пример запроса на диалекте языка SQL к службе каталогов:

SELECT ADsPath, cn
FROM 'LDAP://OU=имяПодразделения,DC=имяДомена,DC=ru'
WHERE objectCategory='person' AND objectClass='user' AND sn = 'H*'
ORDER BY sn

В разделе SELECT перечисляются атрибуты объектов Active Directory, которые будут возвращаться запросом. В результатах запроса они будут представлены полями объекта ADODB.Recordset. Несколько имен атрибутов должны разделяться запятыми. Вместо списка атрибутов можно использовать ключевое слово ALL или звездочку (*). Эти значения определяют, что должны вернуться все атрибуты.

В разделе FROM указывается отличительное имя базового объекта поиска (то есть того контейнерного объекта, начиная с которого будет производиться поиск). Этот путь обязательно должен быть заключен в одинарные кавычки.

В разделе WHERE указываются условия, поисковые фильтры, которые используются для выбора объектов при поиске. Синтаксис соответствует стандартам языка SQL.

В разделе ORDER BY указывается атрибут объекта службы каталогов, по значению которого будет производиться сортировка возвращаемых результатов. Active Directory поддерживает сортировку только по одному атрибуту. Однако можно указать порядок сортировки при помощи ключевых слов ASC и DESC (по умолчанию используется ASC).

Оператор JOIN в запросах к Active Directory не поддерживается (если запрос производится из SQL Server, а Active Directory используется в качестве внешнего источника данных, то можно производить JOIN между таблицами SQL Server и информацией, возвращаемой Active Directory).

Пример скрипта, разыскивающего все объекты в домене, в имени которых используется прямой слеш:

# -*- coding: cp1251 -*-
import win32com.client
conn = win32com.client.Dispatch("ADODB.Connection")
conn.Provider = "ADSDSOObject"
conn.Open("Active Directory Provider")
query = "SELECT ADsPath FROM 'LDAP://DC=имяДомена,DC=ru' WHERE Name='*/*'"
rs = conn.Execute(query)[0]
while not rs.EOF:
    obj = win32com.client.GetObject(rs.Fields(0).Value)
    print obj.Class, obj.Name
    rs.MoveNext()
conn.Close()

В случае необходимости подключения под конкретной учётной записью следует использовать строку подключения, аналогично следующему примеру:

conn = win32com.client.Dispatch("ADODB.Connection")
conn.Open("Provider=ADSDSOObject;User Id=myDomain\\myUsername;Password=myPassword;")

Классы ADSI

Интерфейс IADs определяет набор базовых свойств и методов для любого объекта ADSI:


ADsPath Это свойство возвращает отличительное имя объекта в Active Directory. Значение этого свойства может выглядеть по разному в зависимости от того, как именно получена ссылка на данный объект. Значение этого свойства выглядит как путь LDAP и может использоваться для получения этого объекта функцией GetObject.
Class Это свойство возвращает имя класса Active Directory, к которому принадлежит данный объект, согласно схеме Active Directory. Например, "domainDNS" или "user".
GUID Глобальный уникальный идентификатор объекта Active Directory.
Name Это свойство возвращает относительное отличительное имя данного объекта (relative distinguished name, RDN), например, "cn=TestUser1".
Parent Это свойство возвращает значение свойства ADsPath родительского контейнера данного объекта.
Schema Это свойство возвращает ADsPath объекта в схеме Active Directory.
GetInfo() Этот метод позволяет заново получить в оперативную память компьютера, на котором создан объект ADSI, информацию о значениях свойств этого объекта с контроллера домена.
SetInfo() Этот метод записывает информацию об изменениях, произведённых с объектом ADSI в оперативной памяти, на контроллер домена, делая таким образом изменения постоянными. Фактически любая операция по внесению изменений в Active Directory средствами ADSI завершается вызовом метода SetInfo(). Контроллер домена по разным причинам может отказаться сохранять внесенные изменения (например, настроенный для пользователя пароль не соответствует парольной политике домена), поэтому лучше всего при вызове этого метода позаботиться об обработке ошибок.
Get() Этот метод, как и метод GetInfo(), обновляет кэш свойств, скачивая значения заново с контроллера домена. Однако GetInfo() обновляет значения всех свойств, а Get() - только указанного. Имя этого свойства передается в качестве параметра.
GetEx() Этот метод делает практически то же, что и метод Get(). Если для какого-то свойства предусмотрено единственное значение (например, строковое), метод Get() вернет просто это строковое значение. Если для этого свойства предусмотрено несколько строковых значений, метод Get() вернет массив строковых значений. Метод GetEx() всегда возвращает массив значений типа Variant, вне зависимости от того, было ли для свойства настроено одно значение или несколько. Поэтому метод GetEx() очень удобно использовать в ситуации, когда неизвестно, вернется одно значение или несколько.
GetInfoEx() Этот метод аналогичен методу GetEx(). Отличием является то, что метод GetEx() принимает в качестве параметра имя единственного свойства, а метод GetInfoEx() - массив с именами свойств. Соответственно, этот метод может обновить значения не для одного свойства, а для набора свойств.
Put() Этот метод позволяет присвоить значение свойству в кэше свойств для объекта ADSI в оперативной памяти. Чаще всего он используется в ситуации, когда объект ADSI только что создан и ещё не сохранен на контроллере домена (в этом случае прямое присвоение значения свойству вызовет ошибку). Потом при вызове метода SetInfo() настроенные значения свойств будут сохранены вместе с объектом в базе данных Active Directory. Обычно метод Put() используется только для присвоения значений обязательным свойствам, без которых сохранение объекта невозможно. Далее вызывается метод SetInfo(), и работа со значениями свойств идёт уже обычным порядком.
PutEx() Этот метод предназначен для тех же целей, что и метод Put(), но в качестве ещё одного параметра принимает информацию о том, что именно нужно сделать с указанным значением свойства (далее указаны значения перечисления ADS_PROPERTY_OPERATION_ENUM):
  • ADS_PROPERTY_CLEAR (1) - очистить данное свойство, убрав все его значения;
  • ADS_PROPERTY_UPDATE (2) - обновить значение для данного свойства, заменив его указанным новым значением;
  • ADS_PROPERTY_APPEND (3) - новое значение должно добавиться к уже существующим (если свойство поддерживает набор значений);
  • ADS_PROPERTY_DELETE (4) - указанное значение должно быть удалено из набора значений для данного свойства.

Интерфейс IADsContainer обеспечивает набор свойств и методов для контейнерных объектов Active Directory (в основном - объектов организационных подразделений и доменов):


Filter Это свойство позволяет настроить фильтр для элементов в данном контейнере. Элементы, которые не соответствуют данному фильтру, при работе с контейнером (переборе его элементов) будут игнорироваться. Это свойство в качестве значения принимает массив значений типа Variant с именами классов объектов Active Directory согласно схеме (например, "user", "computer" и т.п.).
Create() Этот метод позволяет создать новый элемент в данном контейнере. Он принимает два обязательных параметра: имя класса создаваемого объекта (например, "user', "group", "organizationalUnit", "computer" и т.п.) и относительное отличительное имя для данного объекта (точно в таком же формате, в котором это имя возвращается при помощи свойства IADs.Name). Этот метод возвращает ссылку на созданный объект. Затем можно присвоить значение свойствам данного объекта (лучше при помощи метода IADs.Put(), чтобы гарантировать отсутствие ошибок) и сохранить созданный объект при помощи метода SetInfo().
Delete() Этот метод позволяет удалить элемент из данного контейнерного объекта. Он принимает в качестве параметров имя класса и относительное отличительное имя удаляемого объекта. Если класс в Active Directory уже отключен, вместо имени класса можно передать NULL.
GetObject() Этот метод позволяет вернуть ссылку на элемент в контейнерном объекте. В качестве параметров этот элемент принимает класс объекта и его относительное отличительное имя.
MoveHere() Этот метод позволяет переместить какой-либо элемент в данный контейнерный объект. В качестве параметров принимает полное отличительное имя существующего объекта и его новое относительное отличительное имя. Возвращает ссылку на интерфейс IADs для перемещённого объекта, которую можно использовать для дальнейшей настройки свойств объекта. Если переместить объект в тот же контейнер, в котором он уже находится, указав при помощи второго параметра новое имя, тем самым можно переименовать объект. При помощи этого метода можно перемещать в данный контейнерный объект как объекты из того же домена, так и объекты из других доменов данного леса. Однако для перемещения объектов из других доменов необходимо, чтобы домен назначения работал по крайней мере в режиме Windows 2000 Native, и перемещать можно только конечные объекты (например, объекты пользователей) или пустые контейнерные объекты (например, организационное подразделение, в котором нет никаких вложенных объектов). При перемещении объекта между доменами для объекта создается новый SID, а старый сохраняется при помощи атрибута SIDHistory. Явно предоставленные разрешения для пользователя при этом сохраняются, но теряется его членство в глобальных группах. Для перемещаемых объектов пользователей назначенные им пароли сохраняются.

Интерфейс IADsPropertyList предназначен для работы со свойствами объектов Active Directory. В принципе, работать со свойствами можно и без него (например, при помощи метода Put), однако средствами IADsPropertyList можно получить информацию о всех свойствах конкретного объекта, их типе и т.п. Использовать свойства и методы этого интерфейса можно только после того, как для соответствующего объекта Active Directory будет вызван метод IADs.GetInfo() или GetInfoEx(), или Get(), или GetEx().

Пример получения информации об имени, типе и значениях всех свойств объекта:

# -*- coding: cp1251 -*-
import win32com.client
GetObject = win32com.client.GetObject
propList = GetObject("LDAP://CN=Фамилия Имя,OU=Подразделение,DC=домен,DC=ru")
propList.GetInfo()
v = propList.Next()
ADSTYPE_UNKNOWN = 26
while 1:
    print v.Name, v.ADsType, v.Values[0].GetObjectProperty(ADSTYPE_UNKNOWN)
    try:
        v = propList.Next()
    except:
        break

Свойства и методы интерфейса IADsPropertyList:


PropertyCount Это свойство интерфейса IADsPropertyList возвращает информацию о количестве свойств, предусмотренных для данного объекта.
GetPropertyItem() Этот метод позволяет вернуть свойство по его имени. В качестве параметров этот метод принимает имя свойства и его тип в виде значения перечисления ADSTYPEENUM (в нём предусмотрено 28 значений). Если тип свойства вам не известен, можно передать специальное значение ADSTYPE_UNKNOWN (26). Этот метод возвращает информацию в виде ссылки на объект IADsPropertyEntry, который можно использовать для получения информации о значении свойства.
Item() Этот метод отличается от метода GetPropertyItem() тем, что позволяет получить свойство (то есть объект IADsPropertyEntry) по имени или номеру. Тип свойства передавать при этом не надо.
Next() Этот метод позволяет вернуть следующее свойство в виде объекта IADsPropertyEntry. Обычно он используется для перебора всех свойств какого-либо объекта.
PurgePropertyList() Этот метод можно считать обратным методу IADs.GetInfo() - он очищает кэш свойств, удаляя из него информацию для всех свойств данного объекта. При этом сам объект Active Directory никак не затрагивается — этот метод работает только с представлением данного объекта в памяти. Обычно он используется, чтобы высвободить память на компьютере, на котором производятся операции с объектами Active Directory средствами ADSI.
PutPropertyItem() Этот метод позволяет присвоить новое значение свойству объекта Active Directory. По своим возможностям этот метод очень похож на метод Put() интерфейса IADs, и после его вызова необходимо вызвать метод IADs.SetInfo(). В качестве параметра метод PutPropertyInfo() принимает объект PropertyEntry, в котором должно быть задано новое значение для свойства.
Reset() Этот метод позволяет вернутся на начало списка свойств после вызова метода Next(), чтобы вернуться к исходному состоянию.
ResetPropertyItem() Этот метод позволяет удалить указанное свойство из кэша свойств. Этому методу можно передать как имя свойства, так и его номер. Этот метод используется только для экономии оперативной памяти, на сам объект Active Directory он никак не влияет.
Skip() Этот метод позволяет переместить курсор для списка свойств на указанное количество позиций. В качестве параметра этот метод принимает количество позиций, на которое следует переместиться. Обычно этот метод используется вместо метода Next() или вместе с ним для сокращения количества выполняемых операций.

Интерфейс IADsPropertyEntry предназначен для работы со значением (или значениями) свойства объекта Active Directory. Он может использоваться как для получения информации о значении свойства, так и для назначения свойству нового значения или значений. Свойства и методы:


Name Имя свойства, которое всегда соответствует наименованию соответствующего атрибута для объекта Active Directory согласно схеме.
ADsType Тип свойства в соответствии со значением перечисления ADSTYPEENUM.
ControlCode Позволяет определить тип операции, выполняемой со свойством. Возможные значения (перечисление ADS_PROPERTY_OPERATION_ENUM):
  • ADS_PROPERTY_CLEAR (1) - очистить объект свойства, убрав все настроенные для него ранее значения свойств;
  • ADS_PROPERTY_UPDATE (2) - заменить существующее значение свойства другим значением;
  • ADS_PROPERTY_APPEND (3) - добавить указанное значение к уже существующим;
  • ADS_PROPERTY_DELETE (4) - убрать ранее настроенное конкретное значение.
Values Определяет значения для свойства. Свойство Values работает с массивом объектов типа Variant. Любой из объектов типа Variant, который находится в данном массиве, должен обязательно реализовывать интерфейс IADsPropertyValue.

Интерфейсы IADsPropertyValue и IADsPropertyValue2 используются непосредственно для работы со значениями свойств. Каждому объекту IADsPropertyValue соответствует конкретное значение свойства. Массив значений (то есть массив объектов IADsPropertyValue) передаётся при помощи свойства Values объекта IADsPropertyEntry.

Свойства и методы интерфейса IADsPropertyValue:


ADsType Это свойство позволяет определить тип данных для свойства в соответствии с набором значений, предусмотренных перечислением ADSTYPEENUM.
Clear() Этот метод позволяет очистить все значения, заданные ранее для объекта IADsPropertyValue.
DNString
CaseExactString
CaseIgnoreString
PrintableString
NumericString
Boolean
Integer
OctetString
UTCTime
LargeInteger
SecurityDescriptor
Эти свойства предназначены для работы с атрибутами соответствующих типов (в соответствии с перечислением ADSTYPEENUM). Попытка обращения к свойству несоответствующего типа вернёт ошибку. Если вам потребовалось выполнить какую-либо операцию со значением такого типа, который не представлен в этой таблице, интерфейс IADsPropertyValue для этой цели использовать будет невозможно. Вместо этого вам придётся воспользоваться интерфейсом IADsPropertyValue2.

Методы интерфейса IADsPropertyValue2:


GetObjectProperty() Этот метод позволяет получить значение атрибута объекта Active Directory. Он принимает единственный параметр: тип атрибута в соответствии с перечислением ADSTYPEENUM и возвращает значение этого атрибута при помощи типа данных Variant.
PutObjectProperty() Этот метод позволяет задать значение для атрибута объекта Active Directory. В качестве параметров он принимает тип атрибута в соответствии с перечислением ADSTYPEENUM и само значение (как Variant).

Значения перечисления ADSTYPEENUM:


ADSTYPE_INVALID0
ADSTYPE_DN_STRING1
ADSTYPE_CASE_EXACT_STRING2
ADSTYPE_CASE_IGNORE_STRING3
ADSTYPE_PRINTABLE_STRING4
ADSTYPE_NUMERIC_STRING5
ADSTYPE_BOOLEAN6
ADSTYPE_INTEGER7
ADSTYPE_OCTET_STRING8
ADSTYPE_UTC_TIME9
ADSTYPE_LARGE_INTEGER10
ADSTYPE_PROV_SPECIFIC11
ADSTYPE_OBJECT_CLASS12
ADSTYPE_CASEIGNORE_LIST13
ADSTYPE_OCTET_LIST14
ADSTYPE_PATH15
ADSTYPE_POSTALADDRESS16
ADSTYPE_TIMESTAMP17
ADSTYPE_BACKLINK18
ADSTYPE_TYPEDNAME19
ADSTYPE_HOLD20
ADSTYPE_NETADDRESS21
ADSTYPE_REPLICAPOINTER22
ADSTYPE_FAXNUMBER23
ADSTYPE_EMAIL24
ADSTYPE_NT_SECURITY_DESCRIPTOR25
ADSTYPE_UNKNOWN26
ADSTYPE_DN_WITH_BINARY27
ADSTYPE_DN_WITH_STRING28

В интерфейсе IADsDomain реализованы свойства, обращаться к которым можно только через провайдер WinNT. Пример работы со свойствами объекта домена приведён в статье Введение в Active Directory Service Interface (ADSI): провайдер WinNT. Впрочем, можно работать через значения атрибутов и интерфейсы IADsPropertyList, IADsPropertyEntry, IADsPropertyValue.

Объект организационного подразделения реализует стандартные интерфейсы IADs, IADsContainer, IADsPropertyList, а также специализированный интерфейс IADsOU. Свойства IADsOU (например, BusinessCategory, Description, FaxNumber, LocalityName, TelephoneNumber) достаточно очевидны.

Объект группы поддерживает стандартные интерфейсы IADs и IADsPropertyList, а также специализированный интерфейс IADsGroup. Многие важные свойства групп (например, тип группы) через данный интерфейс недоступны и работать с ними нужно средствами интерфейсов IADsPropertyList, IADsPropertyEntry, IADsPropertyValue. Для атрибута groupType (тип группы) используются значения:

Свойства и методы интерфейса IADsGroup:


Description Это свойство представляет текстовое описание для данной группы.
Add() Этот метод позволяет добавить объект Active Directory (чаще всего учетную запись пользователя) в группу. Ему можно передавать путь в формате AdsPath или SID объекта в различных форматах.
IsMember() Этот метод позволяет проверить, является ли объект Active Directory членом данной группы и возвращает True или False. Учитывается только непосредственное членство: если, например, объект пользователя входит в глобальную группу, которая в свою очередь входит в локальную, то проверка членства для пользователя в локальной группе вернет False. Проверка может быть произведена только для объектов того же домена. Метод принимает в качестве параметра путь AdsPath или SID объекта (для провайдера WinNT проверка по SID не поддерживается).
Members() Этот метод возвращает коллекцию объектов Active Directory, которые являются членами данной группы (как Variant).
Remove() Метод, обратный методу Add(), позволяет удалить объект из группы. Этот метод принимает параметры в том же формате, что и метод Add().

Объект пользователя в ADSI поддерживает свойства и методы стандартных интерфейсов IADs и IADsPropertyList. Также для него реализован специализированный интерфейс IADsUser, в который сведены свойства для доступа к наиболее часто используемым атрибутам. Для объекта пользователя в Active Directory предусмотрено огромное количество атрибутов (несколько сотен), и для многих из них доступ возможен только через интерфейсы IADsPropertyList, IADsPropertyEntry, IADsPropertyValue (но не через IADsUser). Большая часть свойств (Department, Division, EmailAddress, FaxNumber, FirstName, FullName и т.п.) очевидна и комментариев не требует. Некоторые не самые очевидные свойства и методы:


AccountDisabled Это свойство определяет, отключена ли учетная запись. По умолчанию объект пользователя создается в отключенном состоянии. Для этого свойства используются значения True и False. Однако для атрибута UserAccountControl объекта пользователя в Active Directory, который соответствует этому свойству, предусмотрено несколько десятков значений. Значению False свойства AccountDisabled соответствует значение атрибута UserAccountControl 544, а значению True (то есть учетная запись отключена) - 546.
AccountExpirationDate Время и дата, когда учётная запись автоматически отключится. Обычно используется для временных сотрудников.
BadLoginAddress Информация о компьютере, с которого была произведена последняя попытка неудачного входа (с неверным паролем) для данной учётной записи. Эту информацию (свойство доступно только на чтение) можно использовать для обнаружения вторжений.
BadLoginCount Информация о количестве неудачных попыток входа (с неверным паролем) после последнего сброса счётчика.
GraceLoginsAllowed Информация о количестве входов в сеть, которые пользователь может произвести после того, как срок его пароля истек.
GraceLoginsRemaining Количество оставшихся входов в сеть для данного пользователя (когда срок действия пароля закончился).
IsAccountLocked Заблокирована ли учетная запись пользователя после превышения порогового значения неверных попыток входа. Это свойство доступно и на чтение, и на запись, поэтому его можно использовать для разблокирования учетной записи.
LastFailedLogin Информация о дате и времени последней неудачной попытки (по причине неверного пароля) входа пользователя. Можно использовать для расследования попыток вторжения.
LastLogin Информация о дате и времени последнего входа в сеть.
LastLogoff Информация о последнем выходе пользователя из сети (если этот выход был произведен корректно).
MaxLogins Информация о максимальном количестве пользователей, которые могут одновременно входить в сеть от имени данной учетной записи.
PasswordExpirationDate Дата и время, когда срок действия пароля данного пользователя истечет.
PasswordLastChanged Дата и время последнего изменения пароля.
PasswordMinimumLength Минимальная длина пароля в символах.
PasswordRequired Это свойство (доступное и на чтение, и на запись) позволяет определить, обязателен ли пароль для данного пользователя.
RequireUniquePassword Это свойство (доступное и на чтение, и на запись) позволяет определить, распространяются ли на данную учетную запись требования по уникальности пароля (то есть будет ли к нему применяться проверка истории паролей).
ChangePassword() Этот метод позволяет поменять пароль пользователя. В качестве параметров этот метод принимает старый пароль и новый пароль. Обычно этот метод используется для того, чтобы создать свой собственный интерфейс, при помощи которого пользователь сможет менять себе пароль.
SetPassword() Этот метод предназначен для администраторов и позволяет поменять пароль, не зная старого. В качестве параметра он принимает только новый пароль.
Groups() Этот метод позволяет вернуть коллекцию объектов групп, в которые входит данный пользователь. При этом системные группы (такие, как Domain Users) не учитываются.

Примеры

Просмотр атрибутов объекта:

# -*- coding: cp1251 -*-
import win32com.client
GetObject = win32com.client.GetObject
obj = GetObject("LDAP://DC=ru/DC=домен/OU=подразделение/CN=Фамилия Имя")
print obj.Get("sAMAccountName"), obj.Get("cn"), obj.Get("sn")

Модификация атрибутов объекта:

# -*- coding: cp1251 -*-
import win32com.client
dso = win32com.client.GetObject("LDAP:")
obj = dso.OpenDSObject("LDAP://DC=ru/DC=домен/OU=подразделение/CN=Фамилия Имя",
                       "домен\\пользователь", "пароль", 0)
obj.Put("sn", "НовоеИмя")
obj.SetInfo()

Отображение всех объектов пользователей, групп или компьютеров указанного контейнера:

# -*- coding: cp1251 -*-
import win32com.client
GetObject = win32com.client.GetObject
obj = GetObject("LDAP://DC=ru/DC=домен/OU=подразделение")
obj.Filter = ["User"]
# obj.Filter = ["Group"]
# obj.Filter = ["Computer"]
for o in obj:
    print o.ADsPath

Просмотр всех обязательных свойств класса объекта (важно для создания объектов):

# -*- coding: cp1251 -*-
import win32com.client
GetObject = win32com.client.GetObject
obj = GetObject("LDAP://DC=ru/DC=домен/OU=подразделение/CN=Фамилия Имя")
objClass = GetObject(obj.Schema)
for prop in objClass.MandatoryProperties:
    print prop

Создание объекта:

# -*- coding: cp1251 -*-
import win32com.client
dso = win32com.client.GetObject("LDAP:")
obj = dso.OpenDSObject("LDAP://DC=ru/DC=домен/OU=подразделение",
                       "домен\\пользователь", "пароль", 0)
objClass = "user"
objRelativeName = "CN=_TestAdmin"
Prop1Name = "sAMAccountName"
Prop1Value = "TestAdmin"
# здесь могут быть заданы значения других обязательных свойств
newObject = obj.Create(objClass, objRelativeName)
newObject.Put(Prop1Name, Prop1Value)
# здесь могут быть присвоены другие обязательные свойства
newObject.SetInfo()

Переименование объекта:

# -*- coding: cp1251 -*-
import win32com.client
dso = win32com.client.GetObject("LDAP:")
obj = dso.OpenDSObject("LDAP://DC=ru/DC=домен/OU=подразделение",
                       "домен\\пользователь", "пароль", 0)
obj.MoveHere("LDAP://DC=ru/DC=домен/OU=подразделение/CN=_TestAdmin", "CN=_CoolAdmin")

Перемещение объекта в другой контейнер:

# -*- coding: cp1251 -*-
import win32com.client
dso = win32com.client.GetObject("LDAP:")
obj = dso.OpenDSObject("LDAP://DC=ru/DC=домен/OU=подразделениеКуда",
                       "домен\\пользователь", "пароль", 0)
obj.MoveHere("LDAP://DC=ru/DC=домен/OU=подразделениеОткуда/CN=_CoolAdmin", "CN=_CoolAdmin")

Удаление объекта:

# -*- coding: cp1251 -*-
import win32com.client
dso = win32com.client.GetObject("LDAP:")
obj = dso.OpenDSObject("LDAP://DC=ru/DC=домен/OU=подразделение",
                       "домен\\пользователь", "пароль", 0)
objClass = "user"
objRelativeName = "CN=_CoolAdmin"
obj.Delete(objClass, objRelativeName)

Людоговский Александр

Перейти на главную страничку сайта (список статей, файлы для скачивания)

© 2007 http://www.script-coding.com При любом использовании материалов сайта обязательна ссылка на него как на источник информации, а также сохранение целостности и авторства материалов.