Функции ldap


Содержание

Руководство по РНР 3.0 — LDAP функции

LDAP функции

Введение в LDAP

LDAP (Lightweight Directory Access Protocol) — Протокол Доступа к Директориям (каталогам), является протоколом, используемым для доступа к «Серверам Каталогов». Директория является специальной разновидностью базы данных, которая хранит информацию используя древовидную структуру.

Эта концепция аналогична структуре каталога на вашем жестком диске, за исключением того что в данном контексте корневой каталог рассматривается как «весь мир» а подкаталоги первого уровня как «страны». Более низкие уровни структуры директории содержат входы для компаний, организаций или мест, на уровне еще ниже находятся входы каталога для людей, и возможно для оборудования или документов.

Для ссылки на файл в подкаталоге на жестком диске используется нечто подобное

Прямая косая черта отмечает каждый раздел в ссылке, а вся последовательность символов ссылки читается слева направо.

Эквивалентом полностью определенной ссылки в LDAP является «distinguished name» (различаемое имя), обозначаемое просто как «dn». Примером dn может быть:

cn=John Smith,ou=Accounts,o=My Company,c=US

Каждый раздел такой ссылки отмечается запятой, а вся последовательность читается справа налево. Ссылка читается как ..

country = US
organization = My Company
organizationalUnit = Accounts
commonName = John Smith

Так же как и при организации структуры каталога на жестком диске, в данном способе нет жестких правил по организации структуры, и менеджер сервера директории LDAP допускает любую структуру, подходящую для выбранной цели. Однако имеется ряд соглашений. Суть их в том, что вы не можете написать код доступа к серверу директории, не зная его структуры, так же как вы не можете использовать базу данных без представления о ее предназначении. Пример полной программы

Поиск информации для всех записей, где фамилия начинается с «S», в сервере директории, вывод на дисплей и извлечение с именем и email-адресом.

Пример 1. Пример поиска в LDAP

Использование PHP LDAP вызовов

Вам потребуется установить и скомпилировать библиотеки LDAP-клиента или из пакета University of Michigan ldap-3.3, или из Netscape Directory SDK. Вам также потребуется перекомпилировать PHP с поддержкой LDAP для того чтобы применение PHP LDAP вызовов стало доступным.

Прежде чем использовать LDAP вызовы, необходимо знать ..

  • Имя или адрес сервера директории, который вы будете использовать
  • «Базовый dn» сервера (часть «мирового» каталога на данном сервере, которая может быть «o=My Company,c=US»)
  • Нужен ли пароль для доступа к данному серверу (многие серверы обеспечивают доступ для чтения для «anonymous связей» но требуют пароля для чего-либо еще)

Типичная последовательность LDAP-вызовов, которую вы можете применять в приложениях, представлена в следующем щаблоне:

ldap_connect() // установка соединения с сервером
|
ldap_bind() // анонимный или идентифицируемый «вход»
|
действия подобные поиску или обновлению каталога
с выводом результата

Дополнительная информация

Netscape SDK одержит полезное Руководство Программиста в .html формате.

ldap_add

ldap_add — добавляет записи в LDAP каталог

Описание

int ldap_add (целочисленный link_identifier, строковое dn, массив записи);

возвращает true при успехе и false при ошибке.

Функция ldap_add() используется для добавления записей в LDAP каталог. DN добавляемой записи выражается посредством dn. Массив записи определяет информацию о записи. Значения записей индексируются посредством индивидуальных атрибутов. В случае множественных значений для атрибута, они индексируются целыми числами начиная с 0.

запись[«атрибут1»] = значение
запись[«атрибут2»][0] = значение1
запись[«атрибут2»][1] = значение2

Пример 1. Полный прример с идентифицируемой связью

ldap_bind

ldap_bind — связь с LDAP каталогом

Описание

int ldap_bind (целое link_identifier, строковое bind_rdn, строковое bind_password);

Связь с LDAP каталогом с определенным RDN и паролем. Возвращает true при успехе и false при ошибке.

ldap_bind() осуществляет операцию связи с каталогом. bind_rdn и bind_password используются факультативно. Если не определено, применяется связь anonymous.

ldap_close

ldap_close — закрывает связь с LDAP сервером

Описание

int ldap_close (целое link_identifier);

Возвращает true при успехе, false при ошибке.

ldap_close() закрывает связь с LDAP сервером, которая ассоциировалась с определенным link_identifier.

Этот вызов внутренне идентичен ldap_unbind(). LDAP API использует вызов ldap_unbind(), поэтому возможно он предпочтительнее вызова ldap_close().

ldap_connect

ldap_connect — соединение с LDAP сервером

Описание

int ldap_connect (строковое hostname, целое port);

Возвращает положительный LDAP идентификатор связи при успехе, false при ошибке.

ldap_connect() устанавливает соединение с LDAP сервером по определенным hostname и port. Оба аргумента факультативные. Если аргументы не определены, то будет возвращен идентефикатор уже открытого соединения. Если определено только hostname, то по умолчанию используется порт 389.

ldap_count_entries

ldap_count_entries — подсчет количества записей при поиске

Описание

int ldap_count_entries (целое link_identifier, целое result_identifier);

Возвращает количество записей в результате или false при ошибке.

ldap_count_entries() возвращает количество записей хранимых в результате от предыдущей операции поиска. result_identifier идентифицирует внутренний ldap результат.

ldap_delete

ldap_delete — удаляет запись из каталога

Описание

int ldap_delete (целое link_identifier, строковое dn);

Возвращает true при успехе и false при ошибке.

ldap_delete() удаляет отдельную запись из LDAP каталога, определенную по dn.

ldap_dn2ufn

ldap_dn2ufn — конвертирует DN в User Friendly Naming формат

Описание

string ldap_dn2ufn (строковое dn);

ldap_dn2ufn() преобразует DN в более дружественную для пользователя форму, удаляя имена типа.

ldap_explode_dn

ldap_explode_dn — разбивает DN на составные части

Описание

array ldap_explode_dn (строковое dn, целое with_attrib);

ldap_explode_dn() разбивает DN возвращаемое по ldap_get_dn() на составные части. Каждая часть известна как Relative Distinguished Name, или RDN. ldap_explode_dn() возвращает массив всех компонентов. with_attrib используется для запроса, возвращать ли RDN толъко со значениями или также с их атрибутами. Чтобы получить RDN-части с атрибутами (т.е. в формате атрибут=значение) установите with_attrib в 1, чтобы получить только значения установите его в 0.

ldap_first_attribute

ldap_first_attribute — возвращает первый атрибут

Описание

string ldap_first_attribute (целое link_identifier, целое result_entry_identifier, целое ber_identifier);

Возвращает первый атрибут в записи при успехе и false при ошибке.

Подобно чтению записей, атрибуты также читаются один за другим из отдельной записи. ldap_first_attribute() возвращает первый атрибут в записи, отмеченной идентификатором записи. Оставшиеся атрибуты ищутся последовательными вызовами ldap_next_attribute(). ber_ >ber_identifier передается ldap_next_attribute() функции, которая изменяет этот указатель.


ldap_first_entry

ldap_first_entry — возвращает первый идентификатор (id) результата

Описание

int ldap_first_entry (целое link_identifier, целое result_identifier);

Возвращает идентификатор записи для первой записи результата при успехе и false при ошибке.

Записи в LDAP-результате считываются последовательно с использованием функций ldap_first_entry() и ldap_next_entry(). ldap_first_entry() возвращает идентификатор записи для первой записи в результате. Этот идентификатор записи передается затем в процедуру lap_next_entry() для получения последовательных записей из результата.

ldap_free_result

ldap_free_result — освобождает память результата

Описание

int ldap_free_result (целое result_identifier);

Возвращает true при успехе и false при ошибке.

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

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

ldap_get_attributes

ldap_get_attributes — получает атрибуты записи в результате от поиска

Описание

array ldap_get_attributes (целое link_identifier, целое result_entry_identifier);

Возвращает полную информацию о записи в многоразмерном массиве при успехе и false при ошибке.

ldap_get_attributes() используется для упрощения чтения атрибутов и значений из записи в результате от поиска. Возвращаемым значением функции является многоразмерный массив атрибутов и значений.

Разместив определенную запись в каталоге, вы можете узнать какая информация хранится для этой записи, используя данный вызов. Вы могли бы использовать этот вызов в приложении которое «просматривает» каталог записей и/или когда вам не известна структура каталога записей. Во многих приложениях вы можете искать определенные атрибуты, такие как email-адрес или фамилия, не озадачиваясь при этом содержимым других данных.

return_value[«count»] = количество атрибутов в записи
return_value[0] = первый атрибут
return_value[n] = n-ый атрибут

return_value[«attribute»][«count»] = количество значений атрибута
return_value[«attribute»][0] = первое значение атрибута
return_value[«attribute»][i] = i-тое значение атрибута

Пример 1. Показывает список атрибутов отдельной записи каталога

ldap_get_dn

ldap_get_dn — получает DN записи результата

Описание

string ldap_get_dn (целое link_identifier, целое result_entry_identifier);

Возвращает DN записи результата или false при ошибке.

ldap_get_dn() используется для нахождения DN записи в результате.

ldap_get_entries

ldap_get_entries — получает все записи результата

Описание

array ldap_get_entries (целое link_identifier, целое result_identifier);

Возвращает полную информацию о результате в многомерном массиве при успехе и false при ошибке.

ldap_get_entries() используется для упрощения чтения множества записей из результата и затем чтения атрибутов и множественных значений. Информация о записи возвращается по одиночному вызову функции в многомерном массиве. Структура массива представлена ниже.

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

return_value[«count»] = количество записей в результате
return_value[0] : ссылается на детали первой записи

return_value[i][«dn»] = DN i-той записи в результате

return_value[i][«count»] = количество атрибутов i-той записи
return_value[i][j] = j-тый атрибут i-той записи результата

return_value[i][«attribute»][«count»] = количество значений атрибута в i-той записи
return_value[i][«attribute»][j] = j-тое значение атрибута в i-той записи

ldap_get_values

ldap_get_values — получение всех значений из записи результата

Описание

array ldap_get_values (целое link_identifier, целое result_entry_identifier, строковое attribute);

Возвращает массив значений атрибута при успехе и false при ошибке.

ldap_get_values() используется для чтения всех значений атрибута в записи в данном результате. Запись определяется по result_entry_identifier. Количество значений может быть получено при индексации «счетчика» в результирующем массиве. Отдельные значения доступны по целочисленному индексу в массиве. Первый индекс начинается с 0.

Для данного вызова необходим result_entry_identifier, поэтому нужно предварительно сделать один вызов ldap поиска, и один из вызовов для получения отдельной записи.

Ваше приложение или может быть жестко настроено на поиск определенных атрибутов (таких как «фамилия» или «почта») или вы должны использовать вызов ldap_get_attributes() для получения информации о том, какие атрибуты существуют для данной записи.

В LDAP может быть более одной записи для атрибута, поэтому можно, например, хранить несколько адресов email в записи каталога для одной персоны, при этом все записи будут отмечены с атрибутом «mail»

return_value[«count»] = количество значений для атрибута
return_value[0] = первое значение атрибута
return_value[i] = i-тое значение атрибута

Пример 1. Список значений атрибута «mail» для записи каталога

ldap_list

ldap_list — одноуровневый поиск

Описание

int ldap_list (целое link_identifier, строковое base_dn, строковое filter);

Возвращает идентификатор результата поиска или false при ошибке.

ldap_list() выполняет поиск с определенным фильтром по каталогу с областью LDAP_SCOPE_ONELEVEL.

LDAP_SCOPE_ONELEVEL означает что такой поиск может вернуть только информацию, находящуюся на уровне непосредственно ниже базового dn, заданного в вызове. (Эквивалентно вводу «ls» и получению списка файлов и папок в текущем рабочем каталоге).

Этот вызов берет факультативно четвертый параметр который является массивом требуемых атрибутов. См. примечание к ldap_search().

Пример 1. Составление списка всех подразделений организации

ldap_modify

ldap_modify — изменение записи LDAP

Описание

int ldap_modify (целое link_identifier, строковое dn, массив entry);

Возвращает true при успехе и false при ошибке.

ldap_modify() используется для изменения существующих записей в каталоге LDAP. Структура записи такая же как и в ldap_add().

ldap_next_attribute

ldap_next_attribute — получает следующий атрибут в результате

Описание

string ldap_next_attribute (целое link_identifier, целое result_entry_identifier, целое ber_identifier);

Возвращает следующий атрибут в записи или false при ошибке.

ldap_next_entry

ldap_next_entry — получает следующую запись в результате

Описание

int ldap_next_entry (целое link_identifier, целое result_entry_identifier);

Возвращает идентефикатор записи для следующей записи в результате, записи которого начинали считываться функцией ldap_first_entry(). Если больше нет записей в результате, то возвращается false.


ldap_read

ldap_read — чтение записи

Описание

int ldap_read (целое link_ >attributes ]);

Возвращает идентификатор результата поиска или false при ошибке.

ldap_read() выполняет поиск при определенном фильтре по каталогу с областью LDAP_SCOPE_BASE. Таким образом, это эквивалентно чтению записи из каталога.

Пустой фильтр не допустим. Если вы хотите получить абсолютно всю информацию для данной записи, используйте фильтр «object .

Этот вызов берет факультативно четвертый параметр который является массивом требуемых атрибутов. См. примечание ldap_search().

ldap_search — поиск по дереву LDAP

Описание

int ldap_search (целое link_ >attributes ]);

Возвращает идентификатор результата поиска или false при ошибке.

ldap_search() осуществляет поиск для определенного фильтра по каталогу с областью LDAP_SCOPE_SUBTREE. Это эквивалентно поиску по всему каталогу. base_dn определяет базовый DN для данного каталога.

Имеется факультативный четвертый параметр, который может быть добавлен для ограничения атрибутов и значений возвращаемых сервером, если это требуется. Это значительно эффективнее чем действие по умолчанию (которое возвращает все атрибуты и их соответствующие значения). Использование четвертого параметра может поэтому рассматриваться как хорошая практика.

Четвертый параметр является стандартным строковым массивом PHP с требуемыми атрибутами, т.е. array(«mail»,»sn»,»cn»). Заметим, что «dn» требуется всегда, независимо от того, какие типы атрибутов запрашиваются.

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

Приведенный ниже пример отыскивает the отдел организации, фамилию, данное имя и адрес email для всех людей в «My Company» где фамилия или данное имя содержат подстроку $person. Этот пример использует логический фильтр для указания серверу на поиск информации более чем в одном атрибуте.

Пример 1. LDAP поиск

Когда вы выполняете поиск, и слишком много данных возвращается (много записей) вы получите предупреждение, и ldap_get_entries() выдаст сбой. Рассматриваемый здесь прием должен выключить это предупреждение, потом проверить полученную запись.

$normerr = error_reporting ();
error_reporting (0); // выключает предупреждение!
$sr = ldap_search ($ds, $dn, $searchfor);
$normerr = error_reporting ($normerr);
if (!$sr) <
print «слишком много записей!»;
> else .

Вы можете попробовать сузить эту область, добавив особый фильтр, т.е. (cn=a*), но было бы лучше иметь возможность захватить результаты в битах (т.е. 1-100, 101-200. ).

ldap_unbind

ldap_unbind — прекращение связи из каталога LDAP

Описание

int ldap_unbind (целое link_identifier);

Возвращает true при успехе и false при ошибке.

ldap_unbind() прекращает связь из каталога LDAP.

Использование протокола 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:

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

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

  • Отличительное (характерное) имя — Distinguished Name (DN).
  • Относительное отличительное (характерное) имя — Relatively Distinguished Name (RDN).

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

Кроме того, в каталоге существуют организационные блоки (организационные единицы или подразделения) 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):

  • OU — Organization Unit — организационный блок (организационная единица или подразделение), которая содержит такие объекты, как пользователи, контакты, группы и др.
  • CN — Common Name — общее (относительное) имя. Пользователь, контакт, группа или другой объект, который как правило не имеет дочерних объектов.
  • DC — Domain Component – компонент доменного имени.

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

  • «Развёрнутая» форма:
  • «Сокращённая» форма:

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

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

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

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

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

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

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

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

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

В 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:

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

Вторая часть запроса (в примере — (object .

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

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

  • base — поиск производится только по одному объекту, указанному в первой части запроса. Всегда возвращается либо один объект, либо пустой набор объектов. По сути это проверка существования объекта;
  • onelevel — поиск производится только по непосредственным дочерним объектам контейнерного объекта, указанного в первой части запроса. Поиск по вложенным объектам более низких уровней производится не будет. В поиск не попадёт и сам контейнерный объект;
  • subtree — поиск будет производиться по всем объектам вниз по иерархии — глубокий поиск (deep search). В поиск при этом не попадает сам контейнерный объект.

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

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

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

=

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

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

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

  • 1.2.840.113556.1.4.803 — совпадение будет признано только тогда, когда совпадут все биты в сравниваемых значениях (bitwise AND);
  • 1.2.840.113556.1.4.804 — совпадение будет признано в случае, если совпадет любой бит в сравниваемых значениях (bitwise OR).


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

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

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

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

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

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

В разделе 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).

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

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

Классы 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().

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

Свойства и методы интерфейса 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_INVALID
ADSTYPE_DN_STRING 1
ADSTYPE_CASE_EXACT_STRING 2
ADSTYPE_CASE_IGNORE_STRING 3
ADSTYPE_PRINTABLE_STRING 4
ADSTYPE_NUMERIC_STRING 5
ADSTYPE_BOOLEAN 6
ADSTYPE_INTEGER 7
ADSTYPE_OCTET_STRING 8
ADSTYPE_UTC_TIME 9
ADSTYPE_LARGE_INTEGER 10
ADSTYPE_PROV_SPECIFIC 11
ADSTYPE_OBJECT_CLASS 12
ADSTYPE_CASEIGNORE_LIST 13
ADSTYPE_OCTET_LIST 14
ADSTYPE_PATH 15
ADSTYPE_POSTALADDRESS 16
ADSTYPE_TIMESTAMP 17
ADSTYPE_BACKLINK 18
ADSTYPE_TYPEDNAME 19
ADSTYPE_HOLD 20
ADSTYPE_NETADDRESS 21
ADSTYPE_REPLICAPOINTER 22
ADSTYPE_FAXNUMBER 23
ADSTYPE_EMAIL 24
ADSTYPE_NT_SECURITY_DESCRIPTOR 25
ADSTYPE_UNKNOWN 26
ADSTYPE_DN_WITH_BINARY 27
ADSTYPE_DN_WITH_STRING 28

В интерфейсе 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 (тип группы) используются значения:

  • 1 — системная группа (такие группы создаются автоматически при создании домена, самостоятельно создать такую группу нельзя);
  • 2 — глобальная группа (по умолчанию);
  • 4 — доменная локальная группа;
  • 8 — универсальная группа;
  • 0x80000000 — группа безопасности. Это значение используется только в сочетании с другими значениями.

Свойства и методы интерфейса 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) не учитываются.

Примеры

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

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

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

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

АйТи бубен

Инструменты пользователя

Инструменты сайта

Содержание

LDAP (Lightweight Directory Access Protocol — «облегчённый протокол доступа к каталогам») — это сетевой протокол для доступа к службе каталогов X.500, разработанный IETF как облегчённый вариант разработанного ITU-T протокола DAP.

LDAP — относительно простой протокол, использующий TCP/IP и позволяющий производить операции авторизации (bind), поиска (search) и сравнения (compare), а также операции добавления, изменения или удаления записей. Обычно LDAP- сервер принимает входящие соединения на порт 389 по протоколам Порты TCP или UDP. Для LDAP- сеансов, инкапсулированных в SSL сертификаты для для сайта, почты, обычно используется порт 636. Служба директорий LDAP основана на клиент-серверной модели. Один или несколько серверов LDAP содержат данные, которые создают directory information tree (DIT). Клиент соединяется с сервером и спрашивает его. Сервер дает клиенту ответ и/или указание, где получить дополнительную информацию(обычно, другой LDAP сервер).

Реализации LDAP

LDAP является широко используемым стандартом доступа к службам каталогов. Из свободно распространяемых открытых реализаций наиболее известен сервер OpenLDAP, из проприетарных — поддержка протокола имеется в Active Directory — службе каталогов от компании Microsoft, предназначенной для централизации управления сетями Windows настройка, ускорение, частые вопросы. Другие реализации служб каталогов, поддерживающие LDAP как протокол доступа: Red Hat Directory Server, Mandriva Directory Server, Novell eDirectory, OpenDS.

OpenLDAP Software — открытая реализация LDAP, разработанная проектом OpenLDAP Project. Распространяется под собственной лицензией, называемой OpenLDAP Public License. LDAP — платформенно-независимый протокол. В числе прочих есть реализации для различных модификаций BSD, а также GNU/Linux, AIX, HP-UX, Mac OS X, Solaris, Microsoft Windows (2000, XP) и z/OS .

LDAP и Active Directory 2020

LDAP и Active Directory

LDAP (Lightweight Directory Access Protocol) — это протокол для доступа к службам каталогов для извлечения данных, а Active Directory — это реализация службы каталогов Microsoft. Поэтому вам необходимо будет соответствовать LDAP, чтобы Active Directory мог понять и ответить на ваш запрос. Эти два не являются взаимоисключающими, хотя существуют и другие варианты, которые вы можете использовать. Другие службы каталогов существуют помимо Active Directory, некоторые из которых бесплатны, как OpenLDAP. Microsoft также разработала Active Directory, чтобы выйти за пределы LDAP и использовать другие протоколы, такие как Kerberus.

LDAP является продуктом сотрудничества между телекоммуникационными компаниями для создания протокола для вытягивания данных с сервера через TCP / IP. Это было первоначально сделано в 1980-х годах и с тех пор было уточнено. Active Directory — это продукт от Microsoft, который был разработан в основном на LDAP, чтобы гарантировать, что он соответствует требованиям и работает безупречно с LDAP. Первоначально он предназначался для предоставления данных через LDAP, но вырос, чтобы включить другие услуги, как указано выше.

Поскольку LDAP не привязан к одной компании, его можно использовать практически в любой операционной системе, если у вас также есть служба каталогов, которая может работать в этой операционной системе. С другой стороны, Active Directory, принадлежащая Microsoft, обычно находится в операционной системе Windows, которая также принадлежит Microsoft. Несмотря на известность Windows как операционной системы, она не напрямую переводится на использование Active Directory, так как существует множество других опций, которые потребитель может выбрать.

В заключение, Active Directory — это всего лишь один продукт, который может предоставлять услуги, которые используют LDAP. LDAP, с другой стороны, является протоколом и, следовательно, более распространен по сравнению с Active Directory. Независимо от того, используете ли вы Active Directory или OpenLDAP или какие-либо другие сервисы каталогов других компаний, вы все равно, вероятно, будете использовать LDAP.

Резюме: 1.LDAP — это протокол для извлечения информации из службы каталогов, такой как Active Directory 2.LDAP намного старше, чем Active Directory, и огромная часть Active Directory поступает из LDAP 3. Активный каталог от Microsoft, а LDAP — результат усилий отрасли 4. Активный каталог обычно редко встречается за пределами операционной системы Windows 5.Active Directory предоставляет дополнительные услуги, кроме функций LDAP

Функции ldap

LDAP (Lightweight Directory Access Protocol — облегчённый протокол доступа к каталогам) — это сетевой протокол для доступа к службе каталогов. По сути это базы данных, хранящие в себе информацию о пользователях, узлах и объектах сети. Цель их создания — упростить администрирование. LDAP — простой протокол, использующий TCP/IP. Он позволяет компоновать (bind), искать (search) и сравнивать (compare) записи, а также производить операции добавления, изменения или удаления. Обычно LDAP-сервер принимает входящие соединения на порт 389 по протоколам TCP или UDP. Для LDAP-сеансов, инкапсулированных в SSL, обычно используется порт 636.

Содержание

Обзор протокола

Сессия LDAP начинается с того, что клиент подсоединяется к LDAP-серверу — по умолчанию это ТСР порт 389. клиент отправляет запрос на операцию, после чего получает ответ с сервера. В большинстве случаев клиент не должен ждать ответ перед отправкой следующего запроса, сервер же посылает ответы в произвольном порядке.

Запрос на операции

  • Старт TLS (Transport Layer Security) используя расширение LDAPv3 для обеспечения надёжного соединения.
  • Аутентификация и указание версии протокола LDAP.
  • Поиск записей в каталоге.
  • Сравнение содержит ли запись искомый атрибут.
  • Добавление новой записи.
  • Удаление записи.

  • Модификация записи.
  • Модификация отличительного имени (Distinguished Name, DN) — перемещение или переименование записи
  • Отмена предыдущего запроса.
  • Расширенные операции
  • Закрытие соединения.

Кроме того, сервер может послать не запрошенное уведомление, которое не является ответом на запрос. Например, прежде чем разорвать соединение.

Структура

Протокол доступа к каталогам LDAP соответствует модели X.500, принятой в качестве стандарта в 1993 году:

  • Каталог представляет собой дерево каталогов записей.
  • Запись состоит из набора атрибутов.
  • Атрибут имеет имя (атрибут типа или атрибут описания) и одно или несколько значений.
  • Каждая запись имеет уникальный идентификатор — отличительное имя (Distinguished Name, DN). Которое состоит из относительного отличительного имени (Relative Distinguished Name, RDN) составленное из атрибута(ов) записи, за которым следует родительская запись отличительного имени. То есть DN является полным именем файла, а RDN относительное имя в папке.

Имейте ввиду, что DN может меняться в течение существования записи. На пример, когда запись перемещается внутри дерева каталога. Чтобы надёжно и однозначно определить позиции записи в набор её оперативных атрибутов может быть включён UUID.

В LDAP запись может выглядеть примерно так:

dn: cn=Иван Иванов,dc=example,dc=com cn: Иван Иванов givenName: Иван sn: Иванов telephoneNumber: +1 888 555 6789 telephoneNumber: +1 888 555 1232 mail: ivan@example.com manager: cn=Ася Александрова, dc=example,dc=com objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person objectClass: top

Здесь: dn — это имя записи, которое не является не атрибутом, не частью записи. «cn=Иван Иванов» — это RDN записи, a «dc=example,dc=com» — DN родительской записи, в которой dc обозначает доменный компонент. В остальных строках показаны атрибуты записи.

Сервер хранит подкаталог (subtree) начиная с конкретной записи, например, «dc=example,dc=com» и её расширения. На сервере также могут храниться ссылки на другие серверы, таким образом, попытка найти «ou=department,dc=example,dc=com» может вернуть предложение или постоянную ссылку на сервер, который хранит эту часть папки каталога. Клиент может подсоединиться к этому серверу. Некоторые серверы объединены в цепи, то есть отдельный сервер связывается с другим сервером и возвращает результат клиенту.

Операции

Клиент предоставляет каждому запросу положительный идентификатор сообщения, и ответ сервера имеет тот же идентификатор сообщения. Ответ включает в себя результирующий числовой код, который может быть успешным, указывать на ошибки или предоставлять другие данные. Перед ответом сервер может отправить другие сообщения с другими результирующими данными — например, в этом сообщении могут быть отправлены все записи, найденные во время операции поиска.

Протокол LDAP определён в следующих RFC:

  • RFC 4510 — Lightweight Directory Access Protocol (LDAP) Technical Specification Roadmap (заменяет RFC 3377)
  • RFC 4511 — Lightweight Directory Access Protocol (LDAP): The Protocol
  • RFC 4512 — Lightweight Directory Access Protocol (LDAP): Directory Information Models
  • RFC 4513 — Lightweight Directory Access Protocol (LDAP): Authentication Methods and Security Mechanisms
  • RFC 4514 — Lightweight Directory Access Protocol (LDAP): String Representation of Distinguished Names
  • RFC 4515 — Lightweight Directory Access Protocol (LDAP): String Representation of Search Filters
  • RFC 4516 — Lightweight Directory Access Protocol (LDAP): Uniform Resource Locator
  • RFC 4517 — Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules
  • RFC 4518 — Lightweight Directory Access Protocol (LDAP): Internationalized String Preparation
  • RFC 4519 — Lightweight Directory Access Protocol (LDAP): Schema for User Applications
  • RFC 4520 (aka BCP 64) — Internet Assigned Numbers Authority (IANA) Considerations for the Lightweight Directory Access Protocol (LDAP) (заменяет RFC 3383)
  • RFC 4521 (aka BCP 118) — Considerations for Lightweight Directory Access Protocol (LDAP) Extension

Серверная часть

LDAP является одним из самых распространённых стандартов доступа к службам каталогов. Из свободно распространяемых открытых реализаций наиболее популярен сервер OpenLDAP, из платных служб каталогов, которые поддерживают протокол, можно выделить Active Directory от компании Microsoft, предназначенной для централизации управления сетями Windows. Свои реализации служб каталогов, поддерживающие LDAP как протокол доступа, предлагают и другие крупные компании, например, Novell и Sun.

Клиентская часть

В качестве клиентов LDAP выступают как адресные книги почтовых клиентов, так и back-end’ы различных сетевых служб (серверы DNS, SMTP, Samba, UTS и т. д.). LDAP также получила широкую поддержку со стороны таких компаний, как:

  • Apache (на основе сервера каталогов Apache)
  • Apple (на основе Open Directory / OpenLDAP)
  • AT & T
  • Banyan
  • HP
  • IBM / Lotus
  • ISODE (через М-Vault-сервер)
  • Microsoft (с помощью Active Directory)
  • Netscape (в настоящее время в продуктах от Sun Microsystems и Red Hat)
  • Novell (через eDirectory)
  • OctetString (через сервер VDE)
  • Oracle (на основе Oracle Internet Directory)
  • Radiant Logic (через RadiantOne Virtual Directory Server)
  • Red Hat (через сервер каталоговRed Hat)
  • SiemensAG (через DirX сервер)
  • SGI
  • Sun (через сервер каталогов iPlanet и Sun ONE)
  • Symlabs (через каталог Extender)

А также в реализациях с открытым исходным кодом и в бесплатном программном обеспечении, таком, как OpenLDAP и Fedora сервер каталог. Apache HTTP Server, используемый в качестве прокси-сервера (с модулем mod_proxy) также поддерживает LDAP.

LDAP Linux HOWTO

В этом документе представлена информация об установке, настройке, запуске и обслуживании LDAP (Lightweight Directory Access Protocol) сервера на Linux. Также приводятся детали создания LDAP баз данных, способов обновления и удаления информации из базы данных, путей реализации роуминга и способов использования Netscape Address Book. В основном этот документ основывается на информационных страницах о LDAP Мичиганского Университета (University of Michigan) и OpenLDAP Administrator’s Guide.

Введение

Что такое LDAP?

Что такое служба каталогов?

Как работает LDAP?

Механизмы баз данных LDAP, объекты и атрибуты

Новые версии этого документа

Домашняя страница перевода http://mvd.h1.ru/tr/

Мнения и предложения

Также дайте мне знать, если у вас есть комментарии и/или предложения!

История издания

v1.04: 28 Февраля 2001, исправления опечаток и обновления в следующих секциях:

Аутентификация с помощью LDAP

v1.05: 22 Июня 2001, исправления длинных строк, которые вызывали несовместимость с PDF версией этого документа.

Благодарности

Авторские права и отречение

Установка LDAP сервера

Требуемые пакеты

Службы аутентификации Kerberos

Клиенты и сервера OpenLDAP поддерживают службы аутентификации на основе Kerberos. В частности, OpenLDAP поддерживает механизм аутентификации SASL/GSSAPI, используя либо пакет Heimdal, либо пакет MIT Kerberos V. Если вы захотите использовать основанную на Kerberos SASL/GSSAPI аутентификацию, вы должны установить либо Heimdal, либо MIT Kerberos V. Heimdal Kerberos доступен по http://www.pdc.kth.se/heimdal. MIT Kerberos доступен по http://web.mit.edu/kerberos/www.

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

Cyrus’s Simple Authentication and Security Layer Libraries

Библиотеки Cyrus’s SASL обычно входят в состав системы или являются опциональными программными компонентами. Cyrus SASL доступен по http://asg.web.cmu.edu/sasl/sasl-library.html. Cyrus SASL будет использовать библиотеки OpenSSL и Kerberos/GSSAPI, если они предустановленны.

Программы баз данных

Главный механизм работы баз данных в slapd в OpenLDAP — LDBM, для хранения элементов он требует наличия пакета с совместимой базой данных. LDBM совместим с Sleepycat Software BerkeleyDB (рекомендуется) или с Free Software Foundation’s GNU Database Manager (GDBM). Если на время конфигурирования ни один из этих пакетов не доступен, вы не сможете построить slapd с поддержкой главного механизма работы с базой данных.

Если ваша операционная система не предоставляет ни одного из этих двух пакетов, необходимо получить и установить один из них.

BerkeleyDB доступен со страницы Sleepycat Software http://www.sleepycat.com/download.html. Тут доступно несколько версий. На момент написания, рекомендуется последний выпуск версии 3.1.

GDBM доступен со страницы FSF сайта ftp://ftp.gnu.org/pub/gnu/gdbm. На момент написания последняя версия 1.8.

OpenLDAP предназначен для использования преимущества нитей. OpenLDAP поддерживает POSIX pthreads, Mach CThreads, и множество других разновидностей. Если configure скрипт не найдет подходящей системы нитей, то он будет жаловаться. Если это происходит, проконсультируйтесь с секцией Software — Installation — Platform Hints в OpenLDAP FAQ http://www.openldap.org/faq.

slapd поддерживает TCP wrappers (IP фильтры контроля доступа), если они предустановленны. Для серверов содержащих приватную информацию рекомендуется использование TCP wrappers или других фильтров доступа IP-уровня (таких как предоставляемые IP-firewall).

Загрузка пакета

Если вы хотите получить последнюю версию сервера University of Michigan, сходите по адресу:

Для написания этого документа я использовал версию 2.0.4 пакета OpenLDAP. Моя операционная система- Slackware Linux с ядром 2.2.13.

На сайте OpenLDAP вы всегда можете найти последнюю разрабатываемую и последнюю стабильную версии OpenLDAP сервера. На момент обновления этого документа последняя стабильная версия была openldap-stable-20000704.tgz. Последняя разрабатываемая версия была openldap-2.0.4.tgz.

Распаковка сервера


Настройка программы

Построение сервера

Исполняемый файл OpenLdap 2.0 сервера называется slapd. OpenLdap 2.0 официально был выпущен 30 Августа и охватывал протокол Ldap v3, как определено RFC 2251.

Главные особенности OpenLDAP 2.0 таковы:

Поддержка LDAPv2 и LDAPv3 (RFC2251-2256,2829-2831)

Поддержка взаимодействия с существующими клиентами

поддержка IPv4 и IPv6

Strong Autentication (SASL) (RFC2829)

Start TLS (RFC2830)

Language Tags (RFC2596)

Служба расположения основана на DNS (RFC2247+»locate» I-D)

Усовершенствованный автономный сервер

Named References/ManageDsaIT («nameref» I-D)

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

Поддержка приоритетов нитей

Поддержка множества слушателей

Усовершенствованное определение платформы/подсистемы

Заметка: На Linux Documentation Project (LDP) существует документ называемый LDAP Implementation HOWTO. Этот документ — великолепный ресурс для тех, что хочет исследовать новые свойства OpenLDAP 2.0. Дата его выпуска где-то Декабрь 2000.

В последней версии OpenLDAP пакета, также возможно проверить созданные исполняемые файлы. Пакет поставляется со скриптом, который можно запустить командой:

Если что-то идет не так при выполнении скрипта, вы можете завершить его нажатием Ctrl-C. В моем случае скрипт остановился перед его полным завершением. В любом случае я все еще мог увидеть несколько успешных сообщений о конфигурации моего OpenLDAP.

Настройка LDAP сервера

Формат конфигурационного файла

Глобальные директивы

Общие опции механизмов баз данных

Общие директивы базы данных

Директивы специфичные для LDBM механизма базы данных

Прочие механизмы баз данных

Примеры контроля доступа

Функции контроля доступа представленные в Разд. Глобальные директивы > очень мощные. В этой секции приводятся примеры их использования. Для начала несколько простых примеров:

эта директива дает всем доступ для чтения. Если указана только она, то результат такой же, как и при указании строки defaultaccess.

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

Доступ на чтение (read) назначается элементам в поддереве c=US, за исключением элементов в поддереве «o=University of Michigan, c=US», к которым дается доступ на поиск (search). Если сохранен порядок следования этих директив, U-M-специфичная директива никогда не совпадет, так как все U-M элементы являются также c=US элементами.

Следующий пример снова показывает важность порядка следования, как директив доступа, так и выражений «by». Он также показывает использование селектора атрибута для предоставления доступа к указанным атрибутам и различным селекторам .

Этот пример применяется к элементам поддерева «o=U of M, c=US». Сам элемент имеет доступ на запись ко всем атрибутам, кроме homePhone, другие U-M элементы могут выполнять поиск по ним, все остальные не имеют доступа. Атрибут homePhone доступен на запись самому элементу, для поиска прочим U-M элементам, для чтения клиентам, подключающимся из домена umich.edu, и для сравнения всем остальным.

Иногда полезно разрешить отдельному отличительному имени добавлять или удалять самого себя из атрибута. Например, Если вы хотите создать группу и разрешить людям добавлять или удалять только их собственное отличительное имя в атрибуте member, вы могли бы добиться этого с помощью такой access директивы:

Селектор dnattr говорит, что доступ применяется к элементам, перечисленным в атрибуте member. Селектор доступа selfwrite говорит, что эти члены могут удалять только их собственное отличительное имя из атрибута, но не другие значения. Добавление элемента атрибута необходимо, так как для доступа к любым атрибутам элемента необходим доступ к элементу.

Обратите внимание, что конструкция attr=member в выражении , является сокращением выражения «dn=* attr=member» (т.е., оно соответствует атрибуту member во всех элементах).

Каталоги LDAP и их применение

Несколько лет назад у большинства отделов ИТ отсутствовал определенный взгляд на каталоги LDAP. С тех пор технология LDAP привлекла к себе должное внимание, но возникла она в ландшафте информационных инфраструктур как будто случайно.

Для некоторых специалистов первая встреча с LDAP состоялась при переходе с доменов Windows NT на домены Active Directory или при работе с Novell NDS/eDirectory. В других случаях поддержка LDAP была вторичной по отношению к основной функциональности. Так, у многих знакомство с LDAP произошло при настройке почтовых серверов Exchange 5.5 или Netscape Messaging, создании сайтов Web с требованиями аутентификации, в процессе работы с Web Proxy и т. д. В результате каталоги LDAP стали восприниматься как сугубо утилитарный инструмент для решения той или иной конкретной задачи. Цель настоящей статьи — дать читателям более широкое представление о возможностях применения этой технологии и о внутренней структуре каталогов LDAP.

КАТАЛОГИ LDAP

Каталогом LDAP называют любое хранилище данных с поддержкой протокола LDAP. Наиболее распространенные на сегодняшний день каталоги — Microsoft Active Directory, Sun ONE Directory Server (и более ранние версии того же продукта под марками Netscape и iPlanet) и Novell eDirectory (ранее известный как Novell NDS).

В более общем значении под каталогом (directory) обычно подразумевают хранилище относительно статичных данных, т. е. тех, которые считываются во много раз чаще, нежели изменяются. Основные типы данных, хранящиеся в каталогах LDAP, как раз удовлетворяют условию относительной статичности. К их числу принадлежат:

  • данные, необходимые для аутентификации пользователя (имя пользователя, пароль);
  • данные о правах пользователя, пользовательские профили и настройки;
  • адресные данные о человеке (телефон, адрес электронной почты, должность);
  • данные о группах людей (списки рассылки электронной почты, списки, сотрудников отделов);
  • данные об объектах корпоративной сети (компьютеры, принтеры).

Заметим, что в компьютерном мире уже существует одна масштабная система, являющаяся, по сути, каталогом — это система серверов DNS. Имеющаяся специализированная технология DNS отлично себя зарекомендовала и не требует улучшений (хотя Microsoft и приняла решение реализовать DNS в Windows 2000 Server на основе Active Directory, т. е. по сути на основе технологии LDAP).

ПРИМЕНЕНИЕ КАТАЛОГОВ LDAP

По способу применения большинство каталогов LDAP можно разделить на несколько основных групп.

Каталоги сетевой операционной системы (Network Operating System, NOS). В настоящий момент наиболее часто встречающийся пример такого использования — построение корпоративной сети под управлением Windows на основе Microsoft Active Directory или Novell eDirectory.

Каталоги NOS содержат информацию обо всех объектах в сети: данные о пользователях, группах пользователей, рабочих станциях, серверах, принтерах и т. д. Внедрение такого каталога обеспечивает централизованное администрирование сети и управление аутентификацией и авторизацией при обращении к сетевым ресурсам. Это позволяет отказаться от дублирования учетной информации в разных точках ее использования. (Надо отметить, что функциональность Active Directory и eDirectory неравнозначна — естественным образом Active Directory лучше интегрирована с ОС Windows NT и 2000. Оба решения имеют как сильные, так и слабые стороны, а потому перед принятием решения необходимо тщательно взвесить целый набор факторов.)

Похожим способом может быть устроена аутентификация пользователей в сетях под управлением различных вариантов UNIX; в данном случае используются модуль PAM и любой каталог LDAP.

Каталоги для хранения данных о пользователях приложений. Многие производители корпоративного программного обеспечения решили не изобретать велосипед и не создавать собственную систему хранения данных. Вместо этого пользовательские пароли, права доступа и профили помещаются в каталоги LDAP.

Характерным примером подобного подхода является линейка продуктов Sun ONE, включающая в себя, помимо прочего, сервер электронной почты, Web Proxy, календарный сервер, сервер Web. Эти продукты изначально рассчитаны на работу с Sun ONE Directory Server, причем все приложения могут хранить данные о пользователях в одном и том же сервере каталогов. Аналогично, почтовый сервер Exchange 2000 опирается на Active Directory как на хранилище данных о своих пользователях.

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

Каталоги в качестве адресных книг организаций. В каталоге может располагаться справочная информация о сотрудниках — адрес электронной почты, номер телефона, комнаты, название должности и т. п. В качестве пользовательского интерфейса применяется обычно почтовый клиент наподобие Microsoft Outlook или Netscape Messenger (только для поиска и чтения) или специально создаваемый клиент, как правило, доступный через Web. Адресная книга служит для поиска и просмотра информации, автоматического заполнения адресов электронной почты и хранения сертификатов PKI, необходимых для организации электронного обмена конфиденциальной информацией.

Каталоги внешних пользователей. При построении приложений Web, с которыми работают бизнес-партнеры или клиенты организации, требуется создать механизм аутентификации; для этого традиционно также используются каталоги LDAP.

Важно отметить, что с точки зрения управления информационной средой количество сформированных на предприятии каталогов (и в целом — число хранилищ данных о пользователях) желательно свести к минимуму. Поэтому всегда нелишне рассмотреть возможности по применению одного каталога для различных предназначений. Например, каталог NOS может взять на себя роль адресной книги, а каталог какого-либо конкретного приложения можно предоставить в распоряжение других приложений. Подобный подход (консолидация данных о пользователях) в явном виде предлагается крупнейшими производителями каталогов и использующего их ПО — в первую очередь, речь идет о Microsoft и Sun.

Таким образом, один и тот же каталог LDAP способен выполнять целый ряд задач.

ПРОТОКОЛ LDAP

Упрощенный протокол доступа к каталогам (Lightweight Directory Access Protocol, LDAP) представляет собой протокол прикладного уровня; он поддерживает обмен информацией между клиентом и сервером и работает поверх протокола TCP/IP (по умолчанию LDAP использует TCP-порт 389). Идея создания LDAP возникла в ходе экспериментов с ранними реализациями стандарта X.500 в конце 1980-х — начале 1990-х гг. (эти реализации оказались очень сложны и чересчур требовательны к вычислительным ресурсам с клиентской стороны, что привело к необходимости разработки другого клиентского протокола). Технические спецификации нового протокола (RFC 1487 для LDAP версии 2 и RFC 1777 для повсеместно распространенного ныне LDAP версии 3) увидели свет в 1993 и 1995 гг., соответственно.

Первоначально LDAP использовался в качестве дополнения к основному клиентскому протоколу X.500 — протоколу DAP. Таким образом, информационная модель каталогов LDAP полностью унаследована от X.500. В современных каталогах протоколы X.500 либо не поддерживаются вовсе, либо существуют наравне с LDAP, но информационная модель X.500 все равно реализуется — клиент LDAP просто «не знает», от кого он получает информацию — от шлюза между LDAP и DAP или от независимого сервера LDAP.

Протокол LDAP с самого начала ориентировался на максимальную простоту: например, в нем отсутствует поддержка сложных транзакций. Стандарт определяет девять операций:

  • чтения и поиска — search, compare;
  • редактирования — add, delete, modify, rename;
  • установления и разрыва связи — bind, unbind, abandon.

Названия этих операций в основном говорят сами за себя и пояснения не требуют. Обратим только внимание на отсутствие операции read — ее функции выполняет search. (Далее мы поясним по механизму работы операции search.)

ХРАНЕНИЕ ДАННЫХ

Спецификации протокола не указывают, в каком именно формате должны храниться сами данные, и производители решают эту задачу по-разному. В большинстве серверов каталогов хранилища сконструированы специальным образом с учетом относительной статичности данных каталога. Каталоги, совмещающие поддержку X.500 и LDAP, используют формат хранения, предписываемый X.500. В каталогах Oracle Internet Directory и IBM SecureWay данные хранятся в реляционных СУБД соответствующих производителей (Oracle и DB2). Наконец, в качестве каталогов LDAP могут выступать и системы, для которых эта функциональность вторична, — например, почтовый сервер Exchange или среда Lotus Domino, где данные представлены в «родных» форматах.

Заметим, что при построении системы каталогов LDAP на базе продуктов, в основе которых лежит СУБД, заметная часть функционала этого хранилища останется неиспользованной и может отрицательно влиять на производительность системы. Поэтому достаточно логично, что наибольшее распространение получили каталоги, базирующиеся не на СУБД, а на специализированных хранилищах.

Наконец, продукты, наподобие MaXware Virtual Directory (MVD), представляют собой «виртуальные каталоги». MVD работает в качестве шлюза между любым форматом хранения данных (стандартным или нестандартным — к нему прилагается собственная библиотека API для обработки нестандартных форматов) и LDAP. При помощи MVD практически любое хранилище может быть представлено как каталог LDAP.

ИНФОРМАЦИОННАЯ МОДЕЛЬ

Данные в каталогах LDAP представлены как объекты; информация о каждом объекте хранится в наборе атрибутов (точнее, в виде пар «название атрибута — значение атрибута»). Важным отличием от СУБД является возможность присваивать одному объекту несколько атритубов с общим названием: например, объект, описывающий пользователя, может содержать несколько телефонных номеров или адресов электронной почты.

Набор возможных атрибутов задается для каждого каталога заранее. Стандартный набор при необходимости может быть изменен или расширен. Вместе с названием атрибута фиксируется его синтаксис (строка, число, дата и проч.), а потому, в отличие от мира СУБД, название атрибута почти всегда неизменно от каталога к каталогу. Так, атрибут c (country) повсюду означает название страны, l (locality) — населенного пункта, ou (organizational unit) — подразделения организации, cn (common name) — комбинацию имени и фамилии и т. д. В каталогах Active Directory широко применяется атрибут dc (domain component), обозначающий название сегмента корпоративной сети.

Каждый объект каталога принадлежит к одному или нескольким объектным классам. Объектный класс описывает тип объекта и определяет:

  • какие атрибуты обязаны присутствовать у объекта данного класса;
  • какие атрибуты могут присутствовать у объекта данного класса;
  • какой атрибут может использоваться для именования объектов данного класса

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


К примеру, объект, относящийся к классу person, обязан иметь непустые атрибуты cn и sn (фамилия, surname) и может иметь атрибуты telephonenumber, description и некоторые другие. Объект, принадлежащий подклассу organizationalPerson (подкласс person), должен удовлетворять тем же требованиям и может вдобавок содержать иные атрибуты, среди которых title (должность) и ou.

Наиболее распространенным объектным классом для хранения информации о пользователях является на сегодняшний момент inetOrgPerson (здесь inet используется как сокращение от Internet). Это подкласс класса organizationalPerson, он описан в RFC 2798 (в отличие от классов person и organizationalPerson, которые включены в стандарт X.521). Причина в том, что стандарты X.500 формулировались в 1980-х гг. еще до повсеместного распространения Internet, и в описанных там классах отсутствует, например, стандартное поле для адреса электронной почты.

Объектные классы каталога делятся на основные и дополнительные (auxiliary). Каждый объект обязан принадлежать хотя бы к одному основному классу и может принадлежать к дополнительному классу(-ам). Как правило, атрибуты последнего относятся к конкретному приложению. Например, в случае причисления объекта класса inetOrgPerson к дополнительному классу nsmessagingserveruser он объявляется пользователем почтового сервера Sun ONE Messaging; данный класс позволяет добавить к объекту атрибут nsmsgdisallowaccess, необходимый для работы этого сервера. Таким образом, механизм дополнительных классов позволяет задействовать уже имеющийся каталог в качестве хранилища данных о пользователях нового приложения.

Набор типов атрибутов и объектных классов, определенных для данного каталога, называется его схемой (schema). Схема всех основных каталогов LDAP настраивается администратором, хотя в настоящий момент стандартный способ ее настройки отсутствует, что приводит к определенной степени несовместимости: приложение, которому понадобится каталог LDAP для хранения данных о пользователях, должно поставляться с процедурами адаптации схемы каталога отдельно для каждого (широко используемого) сервера каталогов.

НАИМЕНОВАНИЕ ОБЪЕКТОВ КАТАЛОГА

Объекты каталога организуются в иерархическую логическую структуру — дерево. Его корнем служит пустой корневой объект root; объекты следующего уровня называются суффиксами.

У каждого объекта выделяется один именующий атрибут (Relative Distinguished Name, RDN). Полным идентификатором объекта (Distinguished Name, DN) является строка, полученная конкатенацией всех RDN при перемещении по дереву от данного объекта к корневому (см. пример далее). Заметим, что RDN не обязан быть уникальным в масштабах всего каталога: для обеспечения уникальности DN достаточно, чтобы RDN был уникален среди близлежащих объектов (тех, что расположены непосредственно под объектом, находящимся на один уровень выше).

Иерархия накладывает определенные ограничения на возможности удаления объектов каталога: объект, ниже которого остаются другие объекты, не может быть удален.

ФОРМАТ ОБМЕНА ДАННЫМИ

Формат обмена данными LDAP (LDAP Data Interchange Format, LDIF) — это стандартный способ представления данных каталога в виде текстовых файлов. Благодаря LDIF информация может быть считана из каталога, отредактирована при помощи обыкновенного текстового редактора и экспортирована в тот же или в другой каталог. Файл LDIF может содержать данные о любом количестве объектов каталога.

В качестве примера посмотрим LDIF одного объекта Sun ONE Directory Server:

Abstract
dn: u > cn;lang-ru:: 0JLQsNGB0LjQu9C40Lkg0Kj
QsNCx0LDRgg==
nsmsgdisallowaccess: pop http
preferredlanguage: ru
mailhost: mail.niichavo.ru
maildeliveryoption: mailbox
givenname;lang-ru:: 0JLQsNGB0LjQu9C
40Lk=
mail: vshabat@niichavo.ru
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetorgperson
objectclass: mailrecipient
objectclass: nsmessagingserveruser
cn: Vasily Shabat
uid: vshabat
sn;lang-ru:: 0KjQsNCx0LDRgg==
givenname: Vasily
sn: Shabat
ou: Administrators

Из примера видно, что:

    RDN объекта — «u >При простой аутентификации клиент должен либо объявить себя анонимным, либо представить DN пользователя и пароль в ходе операции подключения (bind). Содержащиеся в каталоге данные о контроле доступа позволяют установить, дано ли ему право на выполнение запрошенной операции.

Операция bind зачастую используется и другими приложениями, когда в работе с данными каталога нет непосредственной необходимости. Например, приложение может запросить имя пользователя и пароль, сформировать из них запрос к каталогу на операцию bind и проверить ее выполнение. Если операция проходит без ошибок, то аутентификация считается успешной. Заметим только, что в большинстве случаев, когда аутентификация проводится конечными пользователями, детали работы с DN не видны: приложение запрашивает имя пользователя и пароль, затем (соединившись с каталогом в соответствии с собственными правами) находит DN объекта с конкретным именем пользователя и только потом пытается выполнить команду bind.

Аутентификация может производиться и более сложными (но и более безопасными) способами, например при помощи ключей PKI.

Методы представления информации о контроле доступа (Access Control Information, ACI) до сих пор не стандартизованы и реализуются в различных серверах LDAP по-разному.

ПОИСК ДАННЫХ В КАТАЛОГЕ

Для выполнения операции поиска (search) в каталоге LDAP клиенту нужны следующие параметры:

  • адрес сервера (имя DNS или адрес IP);
  • номер порта (по умолчанию 389);
  • версия LDAP (2 или 3, по умолчанию 3). В настоящий момент серверы, поддерживающие только версию 2, встречаются редко, и многие клиенты по умолчанию используют версию 3;
  • DN пользователя, пароль — для аутентификации;
  • DN «базового» объекта (Base DN) определяет базу поиска. Поиск будет производиться только в части дерева, лежащей ниже указанного объекта;
  • фильтр поиска, где размещены содержательные требования к значениям атрибутов. Строчные атрибуты могут быть проверены на соответствие заданной строке или на наличие в них заданной подстроки. Для численных атрибутов возможен поиск в виде неравенств. Кроме того, в фильтрах можно также использовать стандартные логические операции (AND, OR, NOT);
  • область поиска (scope). Возможные варианты — subtree, one или base. При поиске по subtree (наиболее распространенном; многие клиенты задают этот параметр по умолчанию) просматривается часть дерева под базовым объектом. При поиске one рассматриваются лишь те объекты, что находятся непосредственно под базовым (т. е. на один уровень ниже). Наконец, при поиске по base анализируется только сам базовый объект (операция search с областью поиска base является, скорее, операцией считывания, нежели поиска, хотя соответствие записи фильтру поиска все равно проверяется);
  • требуемые атрибуты. По умолчанию поиск вернет атрибуты всех найденных записей, а по специальному запросу — значения конкретных атрибутов.

Фильтр поиска может состоять из требования к объектному классу. Например, фильтру «object >

Заметим, что в большинстве серверов предусмотрена зависимость контроля доступа от типа поисковой операции. Например, администратор может задать условие, чтобы объект был виден определенному пользователю исключительно при поиске base, т. е. когда пользователь ищет этот конкретный объект.

В примере, приведенном на Рисунке 1, фильтр поиска составлен как логическая связка AND условий на должность пользователя и его имя.

Рисунок 1. Параметры поиска в каталогах LDAP.

ТИРАЖИРОВАНИЕ, ПЕРЕАДРЕСАЦИЯ И ЭСТАФЕТНЫЕ ЗАПРОСЫ

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

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

Для реализации подобных систем нужен механизм разностного тиражирования данных между отдельными серверами каталогов (по сети передаются только изменения в содержании каталога). Такие механизмы предусмотрены во всех распространенных серверах каталогов, но они все еще не стандартизованы, а значит, организовать тиражирование между серверами различных производителей без привлечения сторонних средств невозможно.

Тиражирование бывает двух видов — с одним или несколькими главными серверами. Первый способ предусматривает, что каждый объект каталога может быть изменен на одном из серверов; его копии на других серверах доступны только для чтения. Второй снимает это ограничение. Полноценная отказоустойчивая система, т. е. система, которая продолжает обрабатывать запросы на редактирование данных после отказа одного из серверов, возможна только во втором случае. Тиражирование с несколькими главными серверами реализовано в каталогах Active Directory, eDirectory и Sun ONE Directory (в последнем случае главных серверов может быть не более двух). Заметим, что подобная схема потенциально опасна: при отсутствии механизма контроля за транзакциями изменения, внесенные на главных серверах, могут конфликтовать друг с другом. Соответствующий механизм решает, какие изменения в итоге осуществятся, а какие — нет (и, как следствие, будут потеряны).

Для реализации отказоустойчивых систем и систем высокой доступности требуются дополнительные средства по распределению нагрузки. Таким инструментом может стать proxy-сервер LDAP, DNS Round Robin или аппаратное решение, наподобие Cisco Local Director.

Несколько серверов можно увязать в единую систему и другими способами. При использовании переадресации (referral) сервер LDAP сообщает, что для обработки запроса клиент должен обратиться к другому серверу LDAP. Переадресация требует, чтобы все принимающие в этом участие клиенты LDAP правильно интерпретировали referral — к сожалению, большинство имеющихся на рынке клиентов этого не делают.

С другой стороны, передача эстафетных запросов (chaining) от клиента LDAP не предполагает никакой дополнительной функциональности: серверы LDAP разделяют дерево каталога между собой и сами пересылают запрос от сервера к серверу. Клиент LDAP в этом случае даже «не знает», что применялся эстафетный запрос. Эстафетные запросы реализованы в серверах каталогов, поддерживающих X.500, — Siemens DirX, Critical Path Directory Server, Nexor. Соответствующий протокол, DSP, является частью стандарта X.500.

АДМИНИСТРИРОВАНИЕ ДАННЫХ КАТАЛОГА

Каждый сервер каталога поставляется с интерфейсом, при помощи которого производится как конфигурация и управление сервером, так и администрирование данных каталога. Однако полностью вопрос администрирования данных этими средствами не решается.

Начнем с того, что некоторые из интерфейсов для работы с данными каталога просто неудобны при регулярном обращении к ним; например, структура конкретного дерева каталога может быть такова, что для редактирования одного атрибута одного пользователя нужно около десяти раз щелкнуть мышью. В подобных интерфейсах не предусмотрена возможность автоматизации или упрощения часто исполняемых задач.

С другой стороны, на рынке отсутствуют продукты, применение которых дало бы возможность полностью отказаться от средств администрирования любого из каталогов LDAP. Проблема в том, что такое средство должно позволять не только редактировать данные, но и управлять правами доступа и изменениями в схеме каталога, а подобные функции реализуются в разных серверах по-разному. Тем не менее в последнее время большую популярность приобрели такие инструменты, как Softerra LDAP Administrator и бесплатное средство для управления данными каталога LDAP Browser. Функционирование и того и другого ограничивается управлением данными каталога.

Вообще говоря, управление данными каталога совершенно не обязательно должно осуществляться системными администраторами. Разумным с точки зрения распределения обязанностей является делегирование прав администрирования — набор механизмов и соглашений, при котором за ввод данных каталога отвечают пользователи вне отдела ИТ. Например, общее управление информацией о персонале поручается отделу кадров, а некоторые атрибуты, например телефонный номер, могут редактировать сами сотрудники.

Наконец, различные хранилища пользовательских данных можно объединить в единую систему каталогов — при этом за синхронизацию между хранилищами отвечают метакаталоги. Так, при помощи метакаталога используемый в корпоративной сети каталог Active Directory можно объединить с Sun ONE Directory Server, используемым приложениями Sun ONE, к примеру Messaging Server, а также с корпоративной системой учета кадров. В результате управление содержимым каталога осуществляется автоматически на основе данных других систем.

Василий Шабат — менеджер отдела развития решений компании «Открытые технологии». С ним можно связаться по адресу: vshabat@ot.ru.

Поделитесь материалом с коллегами и друзьями

Функции ldap

ldap_add — добавляет записи в LDAP каталог

Описание int ldap_add(целочисленный link_identifier, строковое dn, массив записи);

возвращает true при успехе и false при ошибке.

Ф ункция ldap_add() используется для добавления записей в LDAP каталог. DN добавляемой записи выражается посредством dn. Массив записи определяет информацию о записи. Значения записей индексируются посредством индивидуальных атрибутов. В случае множественных значений для атрибута, они индексируются целыми числами начиная с 0.

запись[«атрибут1»] = значение
запись[«атрибут2»][0] = значение1
запись[«атрибут2»][1] = значение2

Пример. Полный прример с идентифицируемой связью

ldap_bind — связь с LDAP каталогом

Описание int ldap_bind(целое link_identifier, строковое bind_rdn, строковое bind_password);

С вязь с LDAP каталогом с определенным RDN и паролем. Возвращает true при успехе и false при ошибке.

ldap_bind() осуществляет операцию связи с каталогом. bind_rdn и bind_password используются факультативно. Если не определено, применяется связь anonymous.

ldap_close — закрывает связь с LDAP сервером

Описание int ldap_close(целое link_identifier);

В озвращает true при успехе, false при ошибке.

ldap_close() закрывает связь с LDAP сервером, которая ассоциировалась с определенным link_identifier.

Э тот вызов внутренне идентичен ldap_unbind(). LDAP API использует вызов ldap_unbind(), поэтому возможно он предпочтительнее вызова ldap_close().

ldap_connect — соединение с LDAP сервером

Описание int ldap_connect(строковое hostname, целое port);

В озвращает положительный LDAP идентификатор связи при успехе, false при ошибке.

ldap_connect() устанавливает соединение с LDAP сервером по определенным hostname и port. Оба аргумента факультативные. Если аргументы не определены, то будет возвращен идентефикатор уже открытого соединения. Если определено только hostname, то по умолчанию используется порт 389.

ldap_count_entries — подсчет количества записей при поиске

Описание int ldap_count_entries(целое link_identifier, целое result_identifier);

В озвращает количество записей в результате или false при ошибке.

ldap_count_entries() возвращает количество записей хранимых в результате от предыдущей операции поиска. result_identifier идентифицирует внутренний ldap результат.

ldap_delete
ldap_delete — удаляет запись из каталога

Описание int ldap_delete(целое link_identifier, строковое dn);

В озвращает true при успехе и false при ошибке.

ldap_delete() удаляет отдельную запись из LDAP каталога, определенную по dn.

ldap_dn2ufn — конвертирует DN в User Friendly Naming формат

Описание string ldap_dn2ufn(строковое dn);

ldap_dn2ufn() преобразует DN в более дружественную для пользователя форму, удаляя имена типа.

ldap_explode_dn — разбивает DN на составные части

Описание array ldap_explode_dn(строковое dn, целое with_attrib);

ldap_explode_dn() разбивает DN возвращаемое по ldap_get_dn() на составные части. Каждая часть известна как Relative Distinguished Name, или RDN. ldap_explode_dn() возвращает массив всех компонентов. with_attrib используется для запроса, возвращать ли RDN толъко со значениями или также с их атрибутами. Чтобы получить RDN-части с атрибутами (т.е. в формате атрибут=значение) установите with_attrib в 1, чтобы получить только значения установите его в 0.

ldap_first_attribute — возвращает первый атрибут

Описание string ldap_first_attribute(целое link_identifier, целое result_entry_identifier, целое ber_identifier);


В озвращает первый атрибут в записи при успехе и false при ошибке.

П одобно чтению записей, атрибуты также читаются один за другим из отдельной записи. ldap_first_attribute() возвращает первый атрибут в записи, отмеченной идентификатором записи. Оставшиеся атрибуты ищутся последовательными вызовами ldap_next_attribute(). ber_identifier является идентификатором указателя положения внутренней памяти. Он передается по ссылке. Аналогичный ber_identifier передается ldap_next_attribute() функции, которая изменяет этот указатель.

ldap_first_entry — возвращает первый идентификатор (id) результата

Описание int ldap_first_entry(целое link_identifier, целое result_identifier);

В озвращает идентификатор записи для первой записи результата при успехе и false при ошибке.

З аписи в LDAP-результате считываются последовательно с использованием функций ldap_first_entry() и ldap_next_entry(). ldap_first_entry() возвращает идентификатор записи для первой записи в результате. Этот идентификатор записи передается затем в процедуру lap_next_entry() для получения последовательных записей из результата.

ldap_free_result — освобождает память результата

Описание int ldap_free_result(целое result_identifier);

В озвращает true при успехе и false при ошибке.

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

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

ldap_get_attributes — получает атрибуты записи в результате от поиска

Описание array ldap_get_attributes(целое link_identifier, целое result_entry_identifier);

В озвращает полную информацию о записи в многоразмерном массиве при успехе и false при ошибке.

ldap_get_attributes() используется для упрощения чтения атрибутов и значений из записи в результате от поиска. Возвращаемым значением функции является многоразмерный массив атрибутов и значений.

Р азместив определенную запись в каталоге, вы можете узнать какая информация хранится для этой записи, используя данный вызов. Вы могли бы использовать этот вызов в приложении которое «просматривает» каталог записей и/или когда вам не известна структура каталога записей. Во многих приложениях вы можете искать определенные атрибуты, такие как email-адрес или фамилия, не озадачиваясь при этом содержимым других данных.

return_value[«count»] = количество атрибутов в записи
return_value[0] = первый атрибут
return_value[n] = n-ый атрибут

return_value[«attribute»][«count»] = количество значений атрибута
return_value[«attribute»][0] = первое значение атрибута
return_value[«attribute»][i] = i-тое значение атрибута

Пример. Показывает список атрибутов отдельной записи каталога

ldap_get_dn — получает DN записи результата

Описание string ldap_get_dn(целое link_identifier, целое result_entry_identifier);

В озвращает DN записи результата или false при ошибке.

ldap_get_dn() используется для нахождения DN записи в результате.

ldap_get_entries — получает все записи результата

Описание array ldap_get_entries(целое link_identifier, целое result_identifier);

В озвращает полную информацию о результате в многомерном массиве при успехе и false при ошибке.

ldap_get_entries() используется для упрощения чтения множества записей из результата и затем чтения атрибутов и множественных значений. Информация о записи возвращается по одиночному вызову функции в многомерном массиве. Структура массива представлена ниже.

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

return_value[«count»] = количество записей в результате
return_value[0] : ссылается на детали первой записи

return_value[i][«dn»] = DN i-той записи в результате

return_value[i][«count»] = количество атрибутов i-той записи
return_value[i][j] = j-тый атрибут i-той записи результата

return_value[i][«attribute»][«count»] = количество значений атрибута в i-той записи
return_value[i][«attribute»][j] = j-тое значение атрибута в i-той записи

ldap_get_values — получение всех значений из записи результата

Описание array ldap_get_values(целое link_identifier, целое result_entry_identifier, строковое attribute);

В озвращает массив значений атрибута при успехе и false при ошибке.

ldap_get_values() используется для чтения всех значений атрибута в записи в данном результате. Запись определяется по result_entry_identifier. Количество значений может быть получено при индексации «счетчика» в результирующем массиве. Отдельные значения доступны по целочисленному индексу в массиве. Первый индекс начинается с 0.

Д ля данного вызова необходим result_entry_identifier, поэтому нужно предварительно сделать один вызов ldap поиска, и один из вызовов для получения отдельной записи.

В аше приложение или может быть жестко настроено на поиск определенных атрибутов (таких как «фамилия» или «почта») или вы должны использовать вызов ldap_get_attributes() для получения информации о том, какие атрибуты существуют для данной записи.

В LDAP может быть более одной записи для атрибута, поэтому можно, например, хранить несколько адресов email в записи каталога для одной персоны, при этом все записи будут отмечены с атрибутом «mail»

return_value[«count»] = количество значений для атрибута
return_value[0] = первое значение атрибута
return_value[i] = i-тое значение атрибута

Пример. Список значений атрибута «mail» для записи каталога

ldap_list — одноуровневый поиск

Описание int ldap_list(целое link_identifier, строковое base_dn, строковое filter);

В озвращает идентификатор результата поиска или false при ошибке.

ldap_list() выполняет поиск с определенным фильтром по каталогу с областью LDAP_SCOPE_ONELEVEL.

LDAP_SCOPE_ONELEVEL означает что такой поиск может вернуть только информацию, находящуюся на уровне непосредственно ниже базового dn, заданного в вызове. (Эквивалентно вводу «ls» и получению списка файлов и папок в текущем рабочем каталоге).

Э тот вызов берет факультативно четвертый параметр который является массивом требуемых атрибутов. См. примечание к ldap_search().

Пример. Составление списка всех подразделений организации

ldap_modify — изменение записи LDAP

Описание int ldap_modify(целое link_identifier, строковое dn, массив entry);

В озвращает true при успехе и false при ошибке.

ldap_modify() используется для изменения существующих записей в каталоге LDAP. Структура записи такая же как и в ldap_add().

ldap_next_attribute — получает следующий атрибут в результате

Описание string ldap_next_attribute(целое link_identifier, целое result_entry_identifier, целое ber_identifier);

В озвращает следующий атрибут в записи или false при ошибке.

ldap_next_attribute() вызывается для поиска атрибутов в записи. Внутреннее положение указателя устанавливается по ber_identifier. Он посылается в данную функцию по ссылке. Первый вызов ldap_next_attribute С м. также ldap_get_attributes()

ldap_next_entry — получает следующую запись в результате

Описание int ldap_next_entry(целое link_identifier, целое result_entry_identifier);

В озвращает идентефикатор записи для следующей записи в результате, записи которого начинали считываться функцией ldap_first_entry(). Если больше нет записей в результате, то возвращается false.

ldap_next_entry() используется для поиска записей, хранящихся в результате. Последовательные вызовы ldap_next_entry() возвращают записи одну за другой пока не закончатся все записи. Первое обращение к ldap_next_entry() осуществляется после вызова ldap_first_entry() с параметром result_identifier, который возвращается от ldap_first_entry().

ldap_read — чтение записи

Описание int ldap_read(целое link_identifier, строка base_dn, строка filter, массив [attributes]);

В озвращает идентификатор результата поиска или false при ошибке.

ldap_read() выполняет поиск при определенном фильтре по каталогу с областью LDAP_SCOPE_BASE. Таким образом, это эквивалентно чтению записи из каталога.

П устой фильтр не допустим. Если вы хотите получить абсолютно всю информацию для данной записи, используйте фильтр «object .

Э тот вызов берет факультативно четвертый параметр который является массивом требуемых атрибутов. См. примечание ldap_search().

ldap_search — поиск по дереву LDAP

Описание int ldap_search(целое link_identifier, строковое base_dn, строковое filter, массив [attributes]);

В озвращает идентификатор результата поиска или false при ошибке.

ldap_search() осуществляет поиск для определенного фильтра по каталогу с областью LDAP_SCOPE_SUBTREE. Это эквивалентно поиску по всему каталогу. base_dn определяет базовый DN для данного каталога.

И меется факультативный четвертый параметр, который может быть добавлен для ограничения атрибутов и значений возвращаемых сервером, если это требуется. Это значительно эффективнее чем действие по умолчанию (которое возвращает все атрибуты и их соответствующие значения). Использование четвертого параметра может поэтому рассматриваться как хорошая практика.

Ч етвертый параметр является стандартным строковым массивом PHP с требуемыми атрибутами, т.е. array(«mail»,»sn»,»cn»). Заметим, что «dn» требуется всегда, независимо от того, какие типы атрибутов запрашиваются.

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

П оисковый фильтр может быть простым или расширенным, использующим булевы операторы в формате описанном в документации LDAP (См. Netscape Directory SDK для дополнения информации по фильтрам).

П риведенный ниже пример отыскивает the отдел организации, фамилию, данное имя и адрес email для всех людей в «My Company» где фамилия или данное имя содержат подстроку $person. Этот пример использует логический фильтр для указания серверу на поиск информации более чем в одном атрибуте.

Пример. LDAP поиск


// $ds допустимый идентификатор связи сервера каталога

// $person вся часть имени персоны, т.е. «Jo»

$dn = «o=My Company, c=US»;
$filter=»(|(sn=$person*)(givenname=$person*))»;
$justthese = array( «ou», «sn», «givenname», «mail»);

$sr=ldap_search($ds, $dn, $filter, $justthese);

$info = ldap_get_entries($ds, $sr);

print $info[«count»].» записей возвращено»;

К огда вы выполняете поиск, и слишком много данных возвращается (много записей) вы получите предупреждение, и ldap_get_entries() выдаст сбой. Рассматриваемый здесь прием должен выключить это предупреждение, потом проверить полученную запись.

В ы можете попробовать сузить эту область, добавив особый фильтр, т.е. (cn=a*), но было бы лучше иметь возможность захватить результаты в битах (т.е. 1-100, 101-200. ).

ldap_unbind — прекращение связи из каталога LDAP

Описание int ldap_unbind(целое link_identifier);

В озвращает true при успехе и false при ошибке.

ldap_unbind() прекращает связь из каталога LDAP.

Функции ldap

Протокол LDAP определён в следующих RFC:

  • RFC 4510 — Lightweight Directory Access Protocol (LDAP): Technical Specification Roadmap (заменяет RFC 3377)
  • RFC 4511 — Lightweight Directory Access Protocol (LDAP): The Protocol
  • RFC 4512 — Lightweight Directory Access Protocol (LDAP): Directory Information Models
  • RFC 4513 — Lightweight Directory Access Protocol (LDAP): Authentication Methods and Security Mechanisms
  • RFC 4514 — Lightweight Directory Access Protocol (LDAP): String Representation of Distinguished Names
  • RFC 4515 — Lightweight Directory Access Protocol (LDAP): String Representation of Search Filters
  • RFC 4516 — Lightweight Directory Access Protocol (LDAP): Uniform Resource Locator
  • RFC 4517 — Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules
  • RFC 4518 — Lightweight Directory Access Protocol (LDAP): Internationalized String Preparation
  • RFC 4519 — Lightweight Directory Access Protocol (LDAP): Schema for User Applications
  • RFC 4520 (aka BCP 64) — Internet Assigned Numbers Authority (IANA) Cons >Функциональное описание протокола

В протоколе LDAP определены следующие операции для работы с Каталогом:

  • Операции подключения/отключения
    • Подключение (bind) — позволяет ассоциировать клиента с определённым объектом Каталога (фактическим или виртуальным) для осуществления контроля доступа для всех прочих операций чтения/записи. Для того, чтобы работать с Каталогом, клиент обязан пройти аутентификацию как объект, отличительное имя (Distinguished Name) находится в пространстве имён, описываемом Каталогом. В запросе операции bind клиент может не указывать отличительное имя, в таком случае будет осуществлено подключение под специальным псевдонимом anonymous (обычно это что-то наподобие гостевой учетной записи с минимальными правами)
    • Отключение (unbind) — позволяет клиенту в рамках сеанса соединения с LDAP-сервером переключиться на аутентификацию с новым отличительным именем. Команда unbind возможна только после аутентификации на сервере с использованием bind, в противном случае вызов unbind возвращает ошибку
  • Поиск (search) — чтение данных из Каталога. Операция сложная, на вход принимает множество параметров, среди которых основными являются:
    • База поиска (baseDN) — ветка DIT, от которой начинается поиск данных
    • Глубина поиска (scope) — может иметь значения (в порядке увеличения охватываемой области): base, one, sub
      • base — поиск непосредственно в узле — базе поиска
      • one — поиск по всем узлам, являющимся прямыми потомками базового в иерархии, то есть лежащим на один уровень ниже него
      • sub — поиск по всей области, нижележащей относительно базы поиска (baseDN)
    • Фильтр поиска (searchFilter) — это выражение, определяющее критерии отбора объектов каталога, попадающих в область поиска, задаваемую параметром scope. Выражение фильтра поиска записывается в польской (префиксной) нотации, состоящей из логических (булевых) операторов и операндов, в свою очередь являющихся внутренними операторами сопоставления значений атрибутов LDAP (в левой части) с выражениями (в правой части) с использованием знака равенства.

Логические операторы представлены стандартным «набором»: & (логическое «И»), | (логическое «ИЛИ») и ! (логическое «НЕ»).

Пример фильтра поиска:

(&(!(entryDN:dnSubtreeMatch:=dc=Piter,dc=Russia,ou=People,dc=example,dc=com))(object > (|(sn=Lazar*)(u >

  • Операции модификации — позволяют изменять данные в Каталоге, при этом в понятие модификации входит как добавление, удаление и перемещение записей целиком, так и редактирование записей на уровне их атрибутов. Подтипы модификации:
    • Добавление (add) — добавление новой записи
    • Удаление (delete) — удаление записи
    • Модификация RDN (modrdn) — перемещение/копирование записи
    • Модификация записи (modify) — позволяет редактировать запись на уровне её атрибутов,
      • добавляя новый атрибут или новое значение многозначного атрибута (add)
      • удаляя атрибут со всеми его значениями (delete)
      • заменяя одно значение атрибута на другое (replace)
      • а также увеличивая (уменьшая) значение атрибута в рамках атомарной операции (increment)
  • Операция сравнения (compare) — позволяет для определённого отличительного имени сравнить выбранный атрибут с заданным значением

Операция запроса возможностей

В стандарте LDAP определена специальная операция, позволяющая клиентам получать информацию о поддерживаемых сервером версиях протокола и возможностях LDAP-сервера. Эта команда является надстройкой (расширением) для операции search и выполняется при следующем сочетании параметров последней:

  • BIND анонимный
  • База поиска baseDN указана как "" (пустая строка)
  • Глубина поиска scope указана как base
  • Фильтр поиска: (object >Например, при использовании LDAP-клиента из поставки OpenLDAP команда запроса возможностей может выглядеть как:

ldapsearch -x -H ldap://host:port -LLL -b "" -s base '(object >

Операция запроса схемы

Для запроса информации о действующей схеме LDAP-каталога прежде необходимо выполнить Операцию запроса возможностей, получив значение атрибута subschemaSubentry.

ldapsearch -x -H ldap://host:port -LLL -s base -b "" '(object >

Полученное значение используется в качестве Отличительного имени базы поиска (baseDN) в Операции запроса схемы, которую можно описать так:

  • BIND анонимный, либо полный. Большинство серверов каталогов поддерживают запрос схемы без предварительного BIND, но, есть исключения (например, Active Directory);
  • База поиска baseDN равна значению атрибута subschemaSubentry, возвращаемого Операцией запроса возможностей;
  • Глубина поиска scope указана как base;
  • Фильтр поиска: (object >Например, при использовании LDAP-клиента из поставки OpenLDAP Операция запроса схемы может выглядеть так:

ldapsearch -x -H ldap://host:port -LLL -s base -b "cn=Subschema" '(object >

Реализации

Серверная часть

LDAP является широко используемым стандартом доступа к службам каталогов. Из свободно распространяемых открытых реализаций наиболее известен сервер OpenLDAP, из проприетарных — поддержка протокола имеется в Active Directory — службе каталогов от компании Microsoft, предназначенной для централизации управления сетями Windows. Сервер IBM Lotus Domino в своем составе также имеет службу LDAP. [2] [3] Свои реализации служб каталогов, поддерживающие LDAP как протокол доступа, предлагают и другие крупные компании, например, Novell и Sun — OpenDS [4] и, впоследствии, OpenDJ.

Клиентская часть

В качестве клиентов LDAP выступают как адресные книги почтовых клиентов, так и back-end’ы различных сетевых служб (серверы DNS, SMTP, Samba, UTS и т. д.).

См. также

Примечания

Ссылки

Ресурсы

  • Руководство администратора OpenLDAP (рус.), содержит ответы на вопросы общего характера, оригинальный текст (англ.) на сайте www.openldap.org
  • Книга «LDAP for Rocket Scientists» (рус.), учебник по теме LDAP оригинальный текст (англ.) на сайте www.zytrax.com
  • LDAP: архитектура, реализации и тенденции
  • Understanding LDAP — Design and Implementation — redbook от IBM

Серверы

  • Домашняя страница проекта OpenLDAP
  • Apple Open Directory — сервер каталогов и API-framework в Mac OS X Server
  • OpenDS — открытый проект, создан на базе кода Sun Enterprise Java System Directory Server
  • 389 Directory Server — бывший Fedora Project Directory Server, проект с открытым исходным кодом, на основе которого создаётся коммерческий продукт — RedHat Directory Server
  • The Apache Directory Project — сервер каталогов, создаваемый фондом Apache
  • Windows Server 2003 Active Directory — официальный сайт Active Directory
  • IBM Lotus Domino — Google поиск по LDAP в Lotus Domino
  • Mandriva Directory Server

Клиенты

  • LdapAdmin — Открытая (GPL) программа под Windows, для управления LDAP данными
  • JXplorer — OpenSource утилита для администрирования каталога LDAP на языке Java.
  • PHP LDAP admin — развитый клиент LDAP с веб-интерфейсом

Программные интерфейсы (API)

  • Perl-LDAP — объектно-ориентированный модуль Perl для работы с LDAP
  • ldap и ldaptor — модули для работы с LDAP для Python
  • Java LDAP — Java-библиотека для работы с LDAP
  • PHP LDAP — PHP функции для работы по протоколу LDAP
Языки запросов
Стандарты The Open Group
Схемы URI
Официальные aaa: • aaas: • acap: • cap: • c >ldap: • mailto: • mid: • news: • nfs: • nntp: • pop: • pres: • rtsp: • sip: • sips: • snmp: • tel: • telnet: • urn: • wais: • xmpp:
Неофициальные about: • aim: • bolo: • btc: • bzr: • callto: • chrome: • cvs: • daap: • ed2k: • ed2kftp: • feed: • fish: • git: • gizmoproject: • iax2: • irc: • ircs: • lastfm: • ldaps: • magnet: • mms: • msnim: • psyc: • rsync: • secondlife: • skype: • ssh: • svn: • sftp: • smb: • sms: • soldat: • steam: • unreal: • ut2004: • view-source: • vzochat: • webcal: • xfire: • ymsgr:
В этой статье не хватает ссылок на источники информации.

Wikimedia Foundation . 2010 .

Смотреть что такое "LDAP" в других словарях:

LDAP — im TCP/IP‑Protokollstapel: Anwendung LDAP Transport UDP TCP Internet IP (IPv4, IPv6) Netzzugang … Deutsch Wikipedia

Ldap — im TCP/IP‑Protokollstapel: Anwendung LDAP Transport UDP TCP Internet IP (IPv4, IPv6) Netzzugang … Deutsch Wikipedia

LDAP — son las siglas de Lightweight Directory Access Protocol (en español Protocolo Ligero de Acceso a Directorios) que hacen referencia a un protocolo a nivel de aplicación el cual permite el acceso a un servicio de directorio ordenado y distribu >Wikipedia Español

LDAP — (Lighweight Directory Access Protocol) en sí es un servicio de directorio ordenado y distribu >Enciclopedia Universal

LDAP — protokolas statusas T sritis informatika apibrėžtis Supaprastintos kreipties į katalogus ↑protokolas, skirtas prieiti prie katalogų paslaugų, pavyzdžiui, prie bendrovės adresų knygų, iš skirtingų operacinių sistemų. LDAP yra supaprastinta… … Enciklopedinis kompiuterijos žodynas

LDAP — Lightweight Directory Access Protocol Lightweight Directory Access Protocol (LDAP) est à l origine un protocole permettant l interrogation et la modification des services d annuaire. Ce protocole repose sur TCP/IP. Il a cependant évolué pour… … Wikipédia en Français

Ldap — Lightweight Directory Access Protocol Lightweight Directory Access Protocol (LDAP) est à l origine un protocole permettant l interrogation et la modification des services d annuaire. Ce protocole repose sur TCP/IP. Il a cependant évolué pour… … Wikipédia en Français

LDAP — Lightweight Directory Access Protocol (Computing » Telecom) Lightweight Directory Access Protocol (Computing » Software) Lightweight Directory Access Protocol (Computing » Security) Lightweight Directory Access Protocol (Computing » General)… … Abbreviations dictionary

LDAP — Lightweight Directory Access Protocol, definiert in RFC1487 um OSI Ballast abgespecktes X.500 Zugriffsprotokoll … Acronyms

LDAP — ● ►en sg. m. ►PROT Lightweight Directory Access Protocol. protocole de gestion d annuaires de réseau, conçu à l Université du Michigan, et reconnu par la plupart des grosses sociétés du secteur. C est une adaptation allégée du standard X500. C… … Dictionnaire d'informatique francophone

Функции ldap

LDAP (Lightweight Directory Access Protocol - облегчённый протокол доступа к каталогам) - это сетевой протокол для доступа к службе каталогов. По сути это базы данных, хранящие в себе информацию о пользователях, узлах и объектах сети. Цель их создания - упростить администрирование. LDAP - простой протокол, использующий TCP/IP. Он позволяет компоновать (bind), искать (search) и сравнивать (compare) записи, а также производить операции добавления, изменения или удаления. Обычно LDAP-сервер принимает входящие соединения на порт 389 по протоколам TCP или UDP. Для LDAP-сеансов, инкапсулированных в SSL, обычно используется порт 636.

Содержание

Обзор протокола

Сессия LDAP начинается с того, что клиент подсоединяется к LDAP-серверу - по умолчанию это ТСР порт 389. клиент отправляет запрос на операцию, после чего получает ответ с сервера. В большинстве случаев клиент не должен ждать ответ перед отправкой следующего запроса, сервер же посылает ответы в произвольном порядке.

Запрос на операции

  • Старт TLS (Transport Layer Security) используя расширение LDAPv3 для обеспечения надёжного соединения.
  • Аутентификация и указание версии протокола LDAP.
  • Поиск записей в каталоге.
  • Сравнение содержит ли запись искомый атрибут.
  • Добавление новой записи.
  • Удаление записи.
  • Модификация записи.
  • Модификация отличительного имени (Distinguished Name, DN) - перемещение или переименование записи
  • Отмена предыдущего запроса.
  • Расширенные операции
  • Закрытие соединения.

Кроме того, сервер может послать не запрошенное уведомление, которое не является ответом на запрос. Например, прежде чем разорвать соединение.

Структура

Протокол доступа к каталогам LDAP соответствует модели X.500, принятой в качестве стандарта в 1993 году:

  • Каталог представляет собой дерево каталогов записей.
  • Запись состоит из набора атрибутов.
  • Атрибут имеет имя (атрибут типа или атрибут описания) и одно или несколько значений.
  • Каждая запись имеет уникальный идентификатор - отличительное имя (Distinguished Name, DN). Которое состоит из относительного отличительного имени (Relative Distinguished Name, RDN) составленное из атрибута(ов) записи, за которым следует родительская запись отличительного имени. То есть DN является полным именем файла, а RDN относительное имя в папке.

Имейте ввиду, что DN может меняться в течение существования записи. На пример, когда запись перемещается внутри дерева каталога. Чтобы надёжно и однозначно определить позиции записи в набор её оперативных атрибутов может быть включён UUID.

В LDAP запись может выглядеть примерно так:

dn: cn=Иван Иванов,dc=example,dc=com cn: Иван Иванов givenName: Иван sn: Иванов telephoneNumber: +1 888 555 6789 telephoneNumber: +1 888 555 1232 mail: ivan@example.com manager: cn=Ася Александрова, dc=example,dc=com objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person objectClass: top

Здесь: dn - это имя записи, которое не является не атрибутом, не частью записи. "cn=Иван Иванов" - это RDN записи, a "dc=example,dc=com" - DN родительской записи, в которой dc обозначает доменный компонент. В остальных строках показаны атрибуты записи.

Сервер хранит подкаталог (subtree) начиная с конкретной записи, например, "dc=example,dc=com" и её расширения. На сервере также могут храниться ссылки на другие серверы, таким образом, попытка найти "ou=department,dc=example,dc=com" может вернуть предложение или постоянную ссылку на сервер, который хранит эту часть папки каталога. Клиент может подсоединиться к этому серверу. Некоторые серверы объединены в цепи, то есть отдельный сервер связывается с другим сервером и возвращает результат клиенту.

Операции

Клиент предоставляет каждому запросу положительный идентификатор сообщения, и ответ сервера имеет тот же идентификатор сообщения. Ответ включает в себя результирующий числовой код, который может быть успешным, указывать на ошибки или предоставлять другие данные. Перед ответом сервер может отправить другие сообщения с другими результирующими данными - например, в этом сообщении могут быть отправлены все записи, найденные во время операции поиска.

Протокол LDAP определён в следующих RFC:

  • RFC 4510 — Lightweight Directory Access Protocol (LDAP) Technical Specification Roadmap (заменяет RFC 3377)
  • RFC 4511 — Lightweight Directory Access Protocol (LDAP): The Protocol
  • RFC 4512 — Lightweight Directory Access Protocol (LDAP): Directory Information Models
  • RFC 4513 — Lightweight Directory Access Protocol (LDAP): Authentication Methods and Security Mechanisms
  • RFC 4514 — Lightweight Directory Access Protocol (LDAP): String Representation of Distinguished Names
  • RFC 4515 — Lightweight Directory Access Protocol (LDAP): String Representation of Search Filters
  • RFC 4516 — Lightweight Directory Access Protocol (LDAP): Uniform Resource Locator
  • RFC 4517 — Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules
  • RFC 4518 — Lightweight Directory Access Protocol (LDAP): Internationalized String Preparation
  • RFC 4519 — Lightweight Directory Access Protocol (LDAP): Schema for User Applications
  • RFC 4520 (aka BCP 64) — Internet Assigned Numbers Authority (IANA) Considerations for the Lightweight Directory Access Protocol (LDAP) (заменяет RFC 3383)
  • RFC 4521 (aka BCP 118) — Considerations for Lightweight Directory Access Protocol (LDAP) Extension

Серверная часть

LDAP является одним из самых распространённых стандартов доступа к службам каталогов. Из свободно распространяемых открытых реализаций наиболее популярен сервер OpenLDAP, из платных служб каталогов, которые поддерживают протокол, можно выделить Active Directory от компании Microsoft, предназначенной для централизации управления сетями Windows. Свои реализации служб каталогов, поддерживающие LDAP как протокол доступа, предлагают и другие крупные компании, например, Novell и Sun.

Клиентская часть

В качестве клиентов LDAP выступают как адресные книги почтовых клиентов, так и back-end'ы различных сетевых служб (серверы DNS, SMTP, Samba, UTS и т. д.). LDAP также получила широкую поддержку со стороны таких компаний, как:

  • Apache (на основе сервера каталогов Apache)
  • Apple (на основе Open Directory / OpenLDAP)
  • AT & T
  • Banyan
  • HP
  • IBM / Lotus
  • ISODE (через М-Vault-сервер)
  • Microsoft (с помощью Active Directory)
  • Netscape (в настоящее время в продуктах от Sun Microsystems и Red Hat)
  • Novell (через eDirectory)
  • OctetString (через сервер VDE)
  • Oracle (на основе Oracle Internet Directory)
  • Radiant Logic (через RadiantOne Virtual Directory Server)
  • Red Hat (через сервер каталоговRed Hat)
  • SiemensAG (через DirX сервер)
  • SGI
  • Sun (через сервер каталогов iPlanet и Sun ONE)
  • Symlabs (через каталог Extender)

А также в реализациях с открытым исходным кодом и в бесплатном программном обеспечении, таком, как OpenLDAP и Fedora сервер каталог. Apache HTTP Server, используемый в качестве прокси-сервера (с модулем mod_proxy) также поддерживает LDAP.

Илон Маск рекомендует:  Как "оживить" perlcgi скрипт
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL