From: Дмитрий Музалевский <mage@vanbel.nursat.kz>
Date: Sun, 12 Jan 2004 17:02:14 +0000 (UTC)
Subject: Инструкции по настройке аутентификации с помощью LDAP
Инструкции по настройке аутентификации с помощью LDAP
Автор оригинальной статьи: Simon Ritchie <Simon.Ritchie@net.ntl.com>
Перевод: Дмитрий Музалевский <mage@vanbel.nursat.kz>
Оригинал статьи может быть найден по адресу:
http://www.openldap.org./lists/openldapsoftware/200010/msg0009
Настройка аутентификации с помощью LDAP довольно тяжела, главным
образом по той причине, что информация, которая вам нужна разбросана
во множестве документов и некоторые важные детали не представлены. В
результате я провел неделю в тяжких трудах для того, чтобы
продемонстрировать как добиться необходимого результата.
Я работаю в Red Hat Linux. Результаты, в сравнении с прочими UNIX
системами довольно хороши. Далее некоторая информация, которая может
оказаться полезной для людей использующих MS Windows и другие
операционные системы.
Полезные ссылки: http://www.openldap.org сайт содержит как
описание, так и <свободнораспространяемые> дистрибутивы openLDAP.
Вводные разделы очень хорошо разъясняют принципы LDAP.
OpenLDAP основывается на программной продукции Мичиганского
университета. Университет публикует свое собственное руководство,
которое содержит некоторую жизненно важную информацию, которая может
помочь вам, если вы захотите написать собственную backend software.
Это "The slapd and slurpd administrator`s guide". Ссылка:
http://www.umich.edu/~dirsvcs/ldap/doc/guides/slapd/toc.html
Книга "Implementing LDAP", написанная Mark Wilcox (Wrox publishing)
дает хорошее представление о предмете. Она содержит детализированную
информацию, которую я не смог найти в онлайн - документации, но
недостаточную для желаемых мне действий.
Главные принципы.
Традиционно, аутентификация в UNIX происходит чтением записей в файлах
/etc/passwd, /etc/shadow, /etc/group. Каждая строка в /etc/passwd
описывает одного пользователя и содержит ряд разделенных двоеточиями
значений, например:
- имя пользователя <системное, прим Пер.>
- пароль ("x" означает смотреть в /etc/shadow)
- идентификатор пользователя (user id, uid)
- идентификатор группы (group id, gid)
- персональная информация (как правило, реальное имя пользователя)
- домашняя директория пользователя
- оболочка (shell), предоставляемая по умолчанию при входе пользователя в систему.
По некоторым причинам, поле персональной информации названо "полем GECOS".
Помимо пароля здесь хранится информация вроде последней даты смены
пароля, которая используется системой для регулярных напоминаний
пользователям о необходимости сменить пароль <в случае, если подобная
функция в системе настроена, прим Пер.>
Для входа в систему, Борис вводит свое пользовательское имя (boris) и
свой пароль открытым текстом. Операционная система производит
аутентификацию путем шифрования введенного пароля и сравнения
результата с хранящимся в /etc/shadow. Зашифрованный пароль может быть
расшифрован, но только суперпользователь root может читать файл
/etc/shadow. Многие приложения читают информацию из файла /etc/passwd.
Для примера: файловая система маркирует файл значением
пользовательского идентификатора (uid) владельца, а не его именем.
Команда "ls" выдает информацию о файлах, включая пользовательское имя
владельца <с ключом "-l">. Для того, чтобы сделать это, она читает
файл /etc/passwd и переводит uid в пользовательское имя. Каждый файл
маркирован также идентификатором группы (gid). Это сделано для
возможности коллективного доступа к нему. Файл может быть доступен для
владельца, группы к которой он принадлежит и всех прочих пользователей
<разумеется, с разными уровнями для перечисленных категорий, по
параметрам - чтение, запись, исполнение, прим Пер.>. Если файл
маркирован gid`ом группы "users", то он будет доступен для этой
группы, а также для Бориса <объяснение почему - ниже>. Файл /etc/group
содержит записи наподобие следующей:
users::100:
подразумевается, что группа "users" имеет gid со значением 100. Борис
является членом этой группы, так как gid с этим значением указан в его
идентификационной записи в файле /etc/passwd.
Любая операционная система, производящая аутентификацию наподобие UNIX
нуждается в хранении такого же набора данных - пользовательских имен,
пользовательских идентификаторов, имен групп, идентификаторов групп.
Подобное существует и в Windows NT, но есть разница в структуре
аутентифицирующих данных. Система, которая производит аутентификацию и
для UNIX и для Windows нуждается в хранении всех данных, используемых
обеими системами.
РАМ.
Обычно, каждая составляющая операционной системы, требующая
аутентификации (telnet server, ftp server, web server и т.д. и т.п.)
имеет специальный встроенный код. В нынешнее время мы используем
подключаемые модули аутентификации ("Pluggable Authentication Modules,
PAM"). Для того, чтобы произвести аутентификацию с помощью РАМ -
модуля, операционная система вызывает его посредством системной
библиотеки. В LDAP - окружении, РАМ - модуль используется LDAP -
сервером для аутентификации пользователей. РАМ поддерживается UNIX и
Windows системами и его модули доступны из командной оболочки.
Возможность производить аутентификацию с помощью РАМ имеется в Linux
по умолчанию и существует набор модулей для telnet, ftp, и т.п.
Существует также инструкция пользователя РАМ в HTML формате, но она
хорошо спрятана <это, я сказал бы - для кого как, прим Пер.>. В
дистрибутиве Linux, который я использую, она находится по адресу
/usr/doc/pam - 0.66/html.
РАМ LDAP - модуль не является частью Linux PAM <в последних версиях
Red Hat Linux это не так, прим Пер.>. Он доступен на [58]www.padl.com.
Далее приведен образчик аутентифицирующего модуля РАМ. Для примера
служит команда "su", которая позволяет UNIX пользователю совершать
какие - то действия от имени другого пользователя. Для того, чтобы
использовать такую возможность, вам надо ввести пользовательское имя и
его пароль, затем произойдет аутентификация. Вот РАМ - модуль
/etc/pam.d/su:
(В разных системах этот файл может выглядеть по разному, хотя общее
сходство, конечно останется, прим Пер.)
Этот модуль использует разные уровни. Строки "auth" подразумевают
актуальную аутентификацию. В первой строке предписывается использовать
для аутентификации системную библиотеку pam_ldap.so. Она использует
пользовательское имя и пароль. Если LDAP - сервер доступен, то
проверяется введенный пароль, если нет, то предписание сбрасывается и
в силу вступает модуль указанный во второй строке. Он принимает
пользовательское имя и пароль принятые первым модулем (поскольку
указан аргумент "use_first_pass" и проверяет их в локальном файле
паролей /etc/passwd. Это очень полезный механизм, предохраняющий от
неприятных неожиданностей, которые могут произойти в случае
тестирования нового LDAP - сервера.
Ключевой аргумент "sufficient" во второй строке указывает, что в
случае успешной аутентификации по LDAP - паролю, вызов других модулей
аутентификации не требуется. Если LDAP - сервер отвергает пароль, то
попытка использования команды "su" оканчивается неудачей. РАМ - модуль
задействует локальный файл паролей /etc/passwd лишь в случае
недосягаемости LDAP - сервера. Если вы уберете вторую строку, то
аутентификация будет происходить лишь на LDAP - сервере и в случае,
если он не запущен <или не досягаем по каким - либо другим причинам>,
то вы не сможете использовать команду "su".
Другие строки предписывают реакции на события, которые могут случиться
в другое время: например, когда пользователь пытается сменить свой
пароль.
Вы должны крайне осторожно редактировать такие РАМ - модули, которые
не могут быть сброшены <в пользу других> и оставят вас бессильными.
Оставляйте запасное залогиненное окно <консоль> суперпользователя root
в то время когда совершаете такие действия. Проверьте наверняка, что
вы все еще можете войти в систему как root, прежде чем остановить ее.
В противном случае вы рискуете невозможностью входа в нее, когда в
следующий раз запустите ее. Справочные страницы РАМ объясняют что
предпринять в таком случае, но вы должны предварительно распечатать
их, так как в случае невозможности входа в систему вы не сможете
прочитать их в электронном виде. (В случае использования системы Red
Hat Linux, решение вышеописанной проблемы, как правило легче всего
решить с помощью загрузки операционной системы в однопользовательском
режиме (если такая возможность не заблокирована вами или вашим
системным администратором), заново отредактировать РАМ - модули и
перезагрузиться, прим Пер.)
Когда я проинсталлировал модуль РАМ LDAP, то поначалу он не работал,
поскольку система не могла обнаружить его библиотеки. Система хранит
список путей, по которым ищутся системные библиотеки. Эти пути описаны
в файле /etc/ld.so.conf. Я добавил туда такую строку:
/usr/local/lib
туда проинсталлировались библиотеки моего PAM LDAP, затем выполнил
команду:
/sbin/ldconfig -v
Это <действие по обновлению путей поиска системных библиотек
посредством перечитывания файла /etc/ld.so.conf, прим Пер., прим Пер.>
совершается при каждой перезагрузке, но приятнее обойтись без нее.
Если вы используете другую UNIX систему, отличную от Linux, то
возможно вам понадобятся другие действия. Смотрите справочную
информацию по ldconfig (если такая команда есть в вашей системе).
Теперь вы имеете исходно проинсталлированный РАМ LDAP - модуль, но
использовать его не просто. В последней части данного руководства я
опишу вам созданные мною способы для демонстрации того, как он
работает.
LDAP.
LDAP это обслуживаемая база данных, оптимизированная для использования
в качестве сервера каталогов. Аутентификация - одна из задач для
которой она была разработана <я бы предпочел несколько другие
определения, ну да и ладно, прим Пер.>. LDAP - сервер может
функционировать на системе удаленной от той, в которую вы можете
пытаться войти, возможно даже на другом сайте <всемирной сети, прим
Пер.>, а может быть и на том же компьютере. Сервер получает запросы со
всей сети и отвечает на них.
Для аутентификации UNIX логинов вы можете создать отличный комплекс
данных. Данные импортируются и экспортируются в LDIF формате. Этот
формат подразумевает определенный набор атрибутов и значений.
База данных LDAP иерархична. Каждый набор данных принадлежит домену,
который в свою очередь входит в состав интернет - домена. Мой домен -
"home.sys " существует лишь внутри моей домашней сети.
Атрибуты, поддерживаемые базой данных LDAP описаны в наборе так
называемых схем. Схема для атрибута, определяемая данным форматом это
текст, переменная и т.д. в том же духе. Существует готовый для
употребления набор схем для аутентификации, но они НЕ импортированы по
умолчанию. Если ваш LDIF файл содержит атрибут не описанный в схеме,
которую вы импортировали, данные не будут загружены.
Некоторые схемы ошибочны, как это объяснено ниже.
Конфигурационный файл slapd.conf определяет различные данные, включая
схемы для импортирования, суперпользователя root (для базы данных
LDAP) и пароль пользователя. В реальной версии пароль необходимо
шифровать. В моей изолированной тестируемой системе я использую
открытый текст. Я создал фиктивного пользователя "noris", который
будет суперпользователем root для LDAP - сервера.
В конфигурационном файле строка, начинающаяся с # является
комментарием. Комментарии, помеченные SAR, являются лично моими:
# $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.8.8.4 2000/08/26 17:06:18 kurt Exp $
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/nis.schema
# Define global ACLs to disable default read access.
# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral ldap://root.openldap.org
# I don't know what this next bit is about - I can't find these files in
# my OpenLDAP distribution. SAR 21 Sept 2000.
# Load dynamic backend modules:
# modulepath /usr/local/libexec/openldap
# moduleload back_ldap.la
# moduleload back_ldbm.la
# moduleload back_passwd.la
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw n0risn
# The database directory MUST exist prior to running slapd AND
# should only be accessable by the slapd/tools. Mode 700 recommended.
directory /usr/local/var/openldap-ldbm
# Indices to maintain
index objectClass eq
Далее следует конфигурационный файл ldap.conf <не путать с предыдущим;
если все было проинсталлировано в /usr/local, то будет находиться в
/usr/local/etc>. Обратите внимание на закомментированную строку, в
которой указан зашифрованный пароль:
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
#BASE dc=example, dc=com
#URI ldap://ldap.example.com ldap://ldap-master.example.com:666
#SIZELIMIT 12
#TIMELIMIT 15
#DEREF never
# Не знаю точно, что это дает. Изменение не дало каких - либо результатов. (SAR)
directory /usr/local/var/openldap-ldbm
# Указанные данные должны совпадать с указанными в slapd.conf
suffix "o=home, c=sys"
rootdn "cn=noris, o=home, c=sys"
rootpw n0risn
# rootpw {crypto}$1$.Hl1/zRt$k9a.62WXw7i7GnL.RUbqZ/
index cn, sn, uid, gidnumber pres, eq, approx
index objectclass pres,eq
dbcachesize 500000
index default none
Существует набор утилит на сайте http://www.padl.com , который
сконвертирует данные из файлов /etc/passwd, /etc/shadow, /etc/group в
файлы данных LDIF формата. Затем вы сможете импортировать их в вашу
базу данных. Есть, однако несколько атрибутов, которые вы можете
применить прямо сейчас. Это домен и высокоуровневые классы данных
"Groups" и "People". Я определил их в файле "init.ldif".
# initial attributes for LDAP authentication database
# Specify root value, Group and People. We can then import the
# attributes from /etc/group, /etcpasswd and /etc/shadow.
dn: o=home, c=sys
objectclass: top
objectclass: organization
o: home
dn: ou=Group, o=home, c=sys
objectclass: top
objectclass: organizationalUnit
ou: Group
dn: ou=People, o=home, c=sys
objectclass: top
objectclass: organizationalUnit
ou: People
Теперь мы можем импортировать данные группы. Атрибуты для группы
"users" будут похожи на следующее:
dn: cn=users,ou=Group,o=home,c=sys
objectClass: posixGroup
objectClass: top
cn: users
gidNumber: 100
И вот, в конце концов мы можем импортировать данные о пользователях.
Описание для пользователя boris будет таким:
dn: uid=boris,ou=People,o=home,c=sys
uid: boris
cn: Boris Morris
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword: {crypt}$1$VCBun4.2$CHSPciCw.tkoI1McHIMYo/
shadowLastChange: 11226
shadowMax: 99999
shadowWarning: 7
shadowFlag: 134538484
loginShell: /bin/bash
uidNumber: 1101
gidNumber: 100
homeDirectory: /home/boris
gecos: Boris Morris
Конечно, есть некоторое несоответствие между некоторыми данными и
схемами. В данных для пользователя boris в файле /etc/shadow, значения
shadowExpire и shadowInactive оба установлены как -1, но в схеме
сказано, что они не могут быть отрицательными. Корректное решение
заключается в использовании верной схемы. Как быстрое решение, я
просто убрал эти строки из данных.
Итак, мы включили пользователя boris в группу пользователей в домене
home.sys. У нас может быть более чем один домен и в каждом мы можем
завести такого пользователя с различными атрибутами - один LDAP -
сервер может обслуживать несколько независимых доменов.
Далее я привожу скрипт, с помощью которого я создаю собственно базу
данных LDAP. В целях отладки он помещает данные о группе и пароле в
разные файлы:
#!/bin/bash
# script to build an LDAP authentication database from /etc/group,
# /etc/passwd and /etc/shadow. Must be run as root so that
# migrate-passwd.pl can read /etc/shadow. Server must not already be
# running - caches database, so clearing out the files isn't enough.
# Stop server, clear any existing database and start server.
kill -TERM `cat /usr/local/var/slapd.pid`
rm -fr /usr/local/var/openldap-ldbm/*
/usr/local/libexec/slapd
sleep 10 # server takes a short while to be ready
# Import passwd. (Imports shadow automatically when run by root).
# Remove any shadowInactive attributes with a negative value. The
# schema is faulty and doesn't allow them.
Имея установленную базу данных, я сменил пароль для boris используя
команду passwd. Зашифрованный пароль в /etc/passwd теперь был отличен
от хранящегося в базе LDAP. Я заменил РАМ - модуль, который обслуживал
команду "su" на версию РАМ - LDAP и попытался применить эту команду к
boris, она сработала.
Далее, я ввожу новый пароль - аутентификация неудачна. В конце концов
я остановил сервер LDAP. В этот раз новый пароль работает, а старый не
проходит. Итак: если сервер LDAP запущен, вы можете использовать LDAP
- пароль, если остановлен - можно воспользоваться паролем из
локального файла паролей /etc/passwd.
Таким образом, имея работающую базу LDAP меняйте модули аутентификации
в /etc/pam.d один за другим на версии LDAP, тестируя каждый
запускаемый вами сервис.
Написание бэкэнда.
Основано на информации, базирующейся на документах Мичиганского
Университета.
Бэкэнд позволяет интерпретировать очереди LDAP и сбрасывать данные для
конвертации в ваш собственный код. Эта функция разработана для
предоставления вам возможности создавать другие виды баз данных,
использующих LDAP - сервер в качестве фронт - энда. LDAP - сервер
организует взаимодействие бэкэнда между своими стандартными каналами
ввода и вывода.
Для тестирования этих возможностей я написал набор shell - скриптов
для для использования их как бэкэнд программ. Я добавил очереди в
slapd.conf для вызова их в каждой базе в домене home.sys:
Все скрипты одинаковы (используют символические ссылки на один
скрипт). Все они очень просты и используются лишь для аутентификации
boris не проверяя пароль.
#! /bin/bash
# testbed script to respond to OpenLDAP shell backend requests. Just
# print name and args, then return a result that says we've worked.
# Authentication will work regardless of password and we will see results
# in the log file.
log=/home/simon/ldap/shdb/Log
op=`basename $0`
echo `date`: $0 ${op} $* >>${log}
echo DEBUG: `date`: $0 ${op} $*
case ${op} in
search)
cat >>${log}
echo >>${log}
echo dn: cn=boris,o=home,c=sys >>${log}
echo dn: cn=boris,o=home,c=sys
echo cn: boris >>${log}
echo userPassword: encrypted.string
echo userPassword: encrypted.string >>${log}
echo cn: boris
echo cn: Boris Norris >>${log}
echo cn: Boris Norris
echo sn: boris >>${log}
echo sn: boris
echo uid: boris >>${log}
echo uid: boris
echo >>${log}
echo
echo RESULT >>${log}
echo RESULT
echo code: 0 >>${log}
echo code: 0
exit 0
;;
bind)
cat >>${log}
echo >>${log}
echo RESULT >>${log}
echo RESULT
echo code: 0 >>${log}
echo code: 0
exit 0
;;
unbind)
# don't need to respond to an unbind request
cat >>${log}
exit 0
;;
*)
cat >>${log}
exit 0
;;
esac
exit 0
Запустив такую конфигурацию LDAP, я могу прокрутить все, что делает
РАМ - модуль. Я ввожу "su boris" в командной строке и обеспечиваю в
открытом виде пароль "password for boris". РАМ - модуль сначала
производит поиск подобного пользователя (существует ли он) и выдает
все детали. Результат включает в себя зашифрованный пароль
"encripted.string", но РАМ - модуль игнорирует его. Это выглядит для
процедуры BIND так, как будто этот пользователь ввел пароль в открытом
виде, как я это сделал. LDAP - сервер проверяет пароль перед тем как
разрешить процедуры BIND и если они успешны, то пароль проходит
корректно. Если пользователь хочет сменить свой пароль,
соответствующий РАМ - модуль вызывает процедуру BIND и производит
обновление перед завершением ее работы.
Ниже находится лог аутентификации, снабженный аннотациями (помечены
"<-"):
Wed Oct 4 12:49:47 BST 2000: /home/simon/ldap/shdb/search search
SEARCH
msgid: 2
suffix: o=home,c=sys
base: o=home, c=sys
scope: 2
deref: 0
sizelimit: 1
timelimit: 0
filter: (uid=boris) <- поиск детальной информации по пользователю boris
attrsonly: 0
attrs: all
dn: cn=boris,o=home,c=sys <- backend выдает информацию по boris
cn: boris
userPassword: encrypted.string
cn: Boris Norris
sn: boris
uid: boris
RESULT
code: 0
Wed Oct 4 12:49:47 BST 2000: /home/simon/ldap/shdb/bind bind
BIND
msgid: 3
suffix: o=home,c=sys
dn: cn=boris,o=home,c=sys <- сервер шлет имя пользователя ...
method: 128
credlen: 18
cred: password.for.boris <- ... и пароль
RESULT <- backend шлет результат bind (OK)
code: 0
Wed Oct 4 12:49:48 BST 2000: /home/simon/ldap/shdb/unbind unbind
UNBIND
msgid: 5
suffix: o=home,c=sys
dn:
Запросы, включая запрос BIND происходят с вызовом бэкэнд - скриптов,
как я могу видеть из лога. РАМ - модуль доставляет пароль "password
for boris" LDAP - серверу, затем отправляется BIND - скрипту, BIND -
скрипт возвращает нулевой код, который означает "успех". Этот
результат отправляется LDAP - серверу, тот в свою очередь отправляет
соответствующий ответ РАМ - модулю. Как конечный результат всего
этого, РАМ - модуль позволяет мне получить права boris. <Прошу
прощения за несколько неудобоваримый стиль последних абзацев, но я
старался делать как можно более буквальный перевод, так что оставьте
это на совести автора, прим Пер.>
Для этого простого тестирования я использовал shell - скрипты, но
бэкэнды можно писать на таких языках как Perl, C, Java и тому
подобных. Они лишь читают стандартные потоки ввода - вывода и
реагируют соответственно.
1250 Прочтений • [Инструкции по настройке аутентификации с помощью LDAP (ldap auth linux pam passwd)] [08.05.2012] [Комментариев: 0]