Рашид Ачилов
Введение
В корпоративной среде часто возникает необходимость создания неких справочников, содержащих адреса электронной почты, телефоны или другую информацию о всех сотрудниках, что приводит к появлению различных приложений разной степени работоспособности. Однако, возможно, разрабатывать новые приложения и не потребуется, если суметь воспользоваться уже имеющимися ресурсами, например Microsoft Active Directory, который нередко используется для построения внутренней сети.
В приведенных ниже примерах используется имя домена - shelton.int, короткое имя - CATS.
Часто используемые сокращения:
- AD - Active Directory (служба каталогов);
- LDAP - Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам);
- DN - Distinguished Name (уникальное имя).
Подключение к службе Active Directory и просмотр объектов
Если рассматривать любой контроллер домена Windows как LDAP-сервер, то становится очевидным, что с ним можно работать стандартными средствами, предназначенными для чтения и записи данных в LDAP. Так, на нем можно обнаружить список открытых портов, похожий на приведенный в листинге 1 (из списка удалены порты, не относящиеся к LDAP):
Листинг 1. Список открытых портов типичного контроллера домена Windows
Starting Nmap 4.62 ( http://nmap.org ) at 2008-08-01 01:45 NOVST
Interesting ports on bigcat (192.168.50.1):
Not shown: 1699 closed ports
PORT STATE SERVICE
88/tcp open kerberos-sec
389/tcp open ldap
464/tcp open kpasswd5
636/tcp open ldapssl
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
|
Как видно из листинга 1, контроллер домена предоставляет все необходимые сервисы: ldap на порту 389, ldap over ssl на порту 636 и т.д. В данном случае компания Microsoft не стала разрабатывать собственное решение, а воспользовалась хорошо известной и документированной службой LDAP. Правда, сама схема LDAP от Microsoft значительно отличается от существующих аналогов, так в листинге 2 приведено описание стандартного объекта "пользователь" (некоторые поля были опущены), полученное с помощью утилиты ldapsearch.
Листинг 2. Поля стандартного объекта AD "пользователь", создаваемые по умолчанию.
dn: CN=LDAP Reader,CN=Users,DC=shelton,DC=int
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: LDAP Reader
sn: Reader
givenName: LDAP
distinguishedName: CN=LDAP Reader,CN=Users,DC=shelton,DC=int
instanceType: 4
displayName: LDAP Reader
name: LDAP Reader
objectGUID:: S2M6nZo2XkCfS2jjHt4XBg==
userAccountControl: 66048
badPwdCount: 0
countryCode: 0
badPasswordTime: 128634384464218750
lastLogoff: 0
lastLogon: 128634384682968750
pwdLastSet: 128634383003906250
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAtInjRe4dmI0lvJgpVwQAAA==
accountExpires: 9223372036854775807
logonCount: 0
sAMAccountName: ldapread
sAMAccountType: 805306368
userPrincipalName: ldapread@shelton.int
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=shelton,DC=int
|
Для просмотра и редактирования объектов, загруженных из LDAP, существуют различные программы, например, GUI-приложение ldapbrowser, написанное на Java, или ldapsearch - программа, работающая из командной строки.
Программа ldapsearch - это важный инструмент администратора LDAP-сервера, примерно как ping и traceroute для системного администратора. Она позволяет загружать и использовать практически любые данные, существующие в LDAP. Некоторая проблема может возникнуть из-за того, что в этой программе используется собственный язык запросов. Он построен в соответствии с принципом "обратной польской записи", как в старинных программируемых калькуляторах, когда сначала задается знак операции, а потом перечисляются операнды. Все операнды разделяются отдельными скобками, из-за чего выражения становятся очень громоздкими. Поскольку это язык запросов, то в нем присутствуют только логические операции - И (&), ИЛИ (/), НЕ (!). Рассмотрим несколько примеров с использованием данного языка запросов.
- (
description=*
) - любой объект, у которого определено поле description. При этом совершенно неважно какой будет длина этого поля, так, один символ точно так же попадет под фильтр "*
", как и длинная строка.
- (
&(objectClass=user)(mail=*)
) - любой объект, у которого поле objectClass
равно user
И определено полеmail
.
- В листинге 3 приведен огромный запрос, используемый для загрузки глобальной адресной книги из LDAP (все содержимое запроса - это одна строка).
Листинг 3. Пример запроса к LDAP-серверу
(&(&(&(mailnickname=*)(/(&(objectCategory=person)(objectClass=user)
(!(homeMDB=*))(!(msExchHomeServerName=*)))(&(objectCategory=person)
(objectClass=user)(/(homeMDB=*)(msExchHomeServerName=*)))
(&(objectCategory=person)(objectClass=contact))(objectCategory=group)
(objectCategory=publicFolder)))))
|
Это запрос можно упросить, если воспользоваться знанием структуры каталога AD:
(&(sAMAccountName=*)(/(sAMAccountType=805306368)(sAMAccountType=268435456))(mail=*)).
|
В значениях sAMAccountType
нет ничего секретного - это просто 0x30000000
и 0x10000000
в десятичной форме, обозначающие соответственно тип объекта "пользователь" или "контакт". Ссылку на подробное описание языка запросов можно найти в разделе "Ресурсы".
После изучения языка запросов остается решить вопрос - как подключиться к LDAP из командной строки? При этом необходимо учитывать несколько моментов.
- В Windows Server отсутствует так называемый anonymous bind (возможность подключения к LDAP без указания имени пользователя и пароля). Эту возможность можно активировать при наличии необходимых полномочий, но по умолчанию она отключена. Поэтому перед тем, как начать работать с LDAP через ldapsearch или создавать сценарии, необходимо получить отдельную учетную запись и установить достаточно простой пароль. Я обычно использую пароль "
qwerty{123}
", так как Windows 2003 Server считает его достаточно сложным, и имя пользователя ldapread
. Для ldapsearch (и далее повсюду) в качестве значения параметра bind dn
указывается строка <имя_пользователя>@<ДОМЕН>
, где домен - это имя AD, переведенное в верхний регистр, напримерldapread@SHELTON.INT
.
- Что указывать в качестве исходной точки для подключения (
base dn
)? Обычно base dn
формируется следующим образом: если AD называется shelton.int
, то соответствующим значением base dn
будет dc=shelton,dc=int
. Если же оно называется kitten.cats.shelton.int
(такие длинные имена возможны в больших инсталляциях), то соответствующим значением base dn
будет dc=kitten,dc=cats,dc=shelton,dc=int
. Разумеется, при подключении можно указать не корень AD, а какую-либо его ветку, например,CN=Computers,DC=shelton,DC=int
, но в таком случае поиск никогда не поднимется выше ее границы. Проблема состоит в том, что логически правильным является создание организационных единиц (ou
- Organizational Unit), соответствующих разным филиалам, непосредственно в корне AD, поскольку эти ou
будут содержать объекты разных типов - пользователей, компьютеры, группы и т.д. Поэтому для просмотра всей структуры AD лучше указывать корневой элемент.
- Как в AD хранится не-ASCII информация, т.е. данные на национальных (и на русском, в том числе) языках? Подобная информация хранится в виде текста в кодировке UTF-8, преобразованного с помощью Base64 в набор символов ASCII (см. соответствующую ссылку в разделе "Ресурсы").
- Сразу же после установки OpenLDAP необходимо внести в файл /usr/local/etc/openldap/ldap.conf (который может храниться и в другом месте) строку "
REFERRALS off
". Это необходимо сделать для всех версий AD, начиная с Windows 2003 Server.
После подготовки можно переходить к практическому использованию ldapsearch.
Листинг 4. Пример использования ldapsearch
# ldapsearch -D ldapread@SHELTON.INT -w qwerty{123} -LLL -h 192.168.50.1 -b dc=shelton,dc=int -P 3 -a always (sAMAccountName=ld*) distinguishedName sAMAccountType
dn: CN=LDAP Reader,CN=Users,DC=shelton,DC=int
sAMAccountType: 805306368
|
Использованные ключи имеют следующее значение:
-D
задает значение bind dn
;
-w
- пароль для подключения;
-LLL
обеспечивает максимальное упрощение выводимой информации;
-h
- адрес сервера;
-b
задает значение base dn
;
-P
- версия протокола LDAP;
-a
описан в man ldapsearch.
Далее приводится простой фильтр отбора записей и перечень атрибутов, которые нужно вывести. Если ничего не указывать, то будут выведены все атрибуты. В данном случае мы запросили атрибуты distinguishedName
иsAMAccountType
. Обратите внимание, что атрибуты, которые необходимо вывести, перечисляются через пробел, а не через запятые. Теперь можно попробовать добавить в информацию о пользователе (средствами Microsoft) поле title
, равное "Читатель
" и запросить его через ldapsearch.
Листинг 5. Пример использования ldapsearch
# ldapsearch -D ldapread@SHELTON.INT -w qwerty{123} -LLL -h 192.168.50.1 -b dc=shelton,dc=int -P 3 -a always (sAMAccountName=ld*) title sAmAccountType
dn: CN=LDAP Reader,CN=Users,DC=shelton,DC=net
title:: 0KfQuNGC0LDRgtC10LvRjA==
sAMAccountType: 805306368
//проверка
# echo 0KfQuNGC0LDRgtC10LvRjA== / mmencode -u / iconv -f utf-8 -t koi8-r
Читатель
|
Заключение
В статье был представлен краткий обзор протокола LDAP и утилиты ldapsearch, использующейся для выполнения запросов к LDAP-серверам. В следующей статье мы рассмотрим использование ldapsearch из сценариев Bourne Shell.