Squid+LDAP. Часть 2

Левинца Егор

Обсуждение статьи на форуме проекта Pro-LDAP.ru.

Содержание

2. Аутентификация

В данном разделе мы рассмотрим аутентификацию с помощью ориентированных на LDAP хелперов squid: squid_ldap_auth и digest_ldap_auth, представляющих, соответственно, Basic и Digest-аутентификации HTTP, а также коротко остановимся на других схемах аутентификации squid.

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

При Digest-аутентификации предоставленный пользователем пароль на клиенте соединяется с другимим данными, к этому значению применяется односторонняя хэш-функция MD5 и полученное значение вместе с именем пользователя передаётся на сервер, который на основании этих сведений пытается установить подлинность пользователя. Если злоумышленник перехватит захэшированную строку, получить из неё пароль в открытом виде не получится (в этом и смысл односторонней хэш-функции).

2.1 Basic-аутентификация: basic_ldap_auth (squid_ldap_auth)

Смысл работы хелпера basic_ldap_auth заключается в выполнении операции простого подсоединения (simple bind) к каталогу LDAP. По сути, операция простого подсоединения представляет собой прохождение аутентификации в каталоге от имени той записи каталога, которая описывает пользователя, с предоставлением пароля в открытом виде. Всё предельно просто: если подсоединение к каталогу прошло успешно, значит и аутентификация в squid считается успешно выполненной.

Чтобы выполнить простое подсоединение к каталогу, нужно знать DN записи, от имени которой будет выполняться подсоединение, и пароль. Пароль, как нам известно, предоставляется HTTP-клиентом в открытом виде, так что с этим вопросов нет. А вот DN пользовательской записи должен быть каким-то образом сопоставлен с предоставленным HTTP-клиентом именем пользователя. Хелпер basic_ldap_auth может решать эту задачу двумя разными способами:

  1. Составление DN из значений аргументов комадной строки и переданного имени пользователя. Проще всего показать это на примере:

    Пример 2.1.1. Составление DN. Аутентификация пользователей из ветки Managers
    # basic_ldap_auth -b 'ou=Managers,dc=mycompany,dc=ru' -u 'uid' -d
    vasily vasilyPassword<Enter>
    attempting to authenticate user 'uid=vasily,ou=Managers,dc=mycompany,dc=ru'
    OK
    anton antonPassword<Enter>
    attempting to authenticate user 'uid=anton,ou=Managers,dc=mycompany,dc=ru'
    ERR Success
    

    Примечание: Здесь и далее в примерах жирным шрифтом выделен текст, вводимый пользователем, а в угловых скобках указаны клавиши, на которые необходимо нажать в процессе или после ввода.

    Примечание: Указываемый во всех примерах вызова хелперов из командной строки аргумент -d означает, что хелперы запускаются в режиме отладки, когда на стандартный вывод посылаются диагностические и служебные сообщения. При тестировании это очень удобно, но когда вызов хелпера прописывается в squid.conf, указывать его не следует.

    Как видите, DN записи пользователя составляется из имени атрибута, переданного в качестве значения аргумента -u, имени пользователя и DN базовой записи, переданного в качестве значения аргумента -b. Затем происходит попытка аутентификации в каталоге с использованием полученного DN и переданного пароля.

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

  2. Более комплексный вариант определения DN записи можно сформулировать так: "Поиск в каталоге записей, удовлетворяющих заданным критериям. Затем DN первой из найденных записей используется для простого подсоединения." Таким образом, взаимодействие с каталогом происходит как минимум в два этапа: анонимный поиск записей и попытка выполнить подсоединение. Если же анонимный поиск в каталоге запрещён (как, например, в Microsoft AD), то этапов уже три: подсоединение к каталогу от имени записи с правами поиска (аргументы -D и -w (-W)), поиск записи по указанным критериям и попытка повторного подсоединения от имени найденной записи.

    Ключевым моментом для запуска хелпера в этом режиме является наличие аргумента -f, значением которого является поисковый фильтр LDAP. В этом случае значение аргумента -b рассматривается как база поиска, а диапазон поиска, при необходимости, можно задать аргументом -s (по умолчанию — sub).

    Итак, какие же реальные преимущества мы можем получить взамен дополнительной нагрузки на каталог LDAP? Попробуем разобрать это на примерах.

    Пример 2.1.2. Классический. Аутентификация пользователей из всего каталога

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

    # basic_ldap_auth -b 'dc=mycompany,dc=ru' -f '(uid=%s)' -d
    vasily vasilyPassword<Enter>
    user filter '(uid=vasily)', searchbase 'dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=vasily,ou=Managers,dc=mycompany,dc=ru'
    OK
    anton antonPassword<Enter>
    user filter '(uid=anton)', searchbase 'dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=anton,ou=People,dc=mycompany,dc=ru'
    OK
    petr petrPassword<Enter>
    user filter '(uid=petr)', searchbase 'dc=mycompany,dc=ru'
    Ldap search returned nothing
    ERR Success
    

    На первом этапе осуществляется поиск записей, соответствующих указанным критериям поиска. В данном случае базой поиска (-b) будет базовая запись всего каталога dc=mycompany,dc=ru, диапазон поиска не указан, поэтому берётся значение по умолчанию sub. Таким образом, при поиске будет осуществляться обход всего дерева каталога, в том числе и обоих интересующих нас веток People и Managers. Чтобы отобрать только записи пользователей, мы указываем фильтр -f '(uid=%s)'. Шаблон %s в этой конструкции заменяется на вводимое значение имени пользователя. Как видно в примере, в первом случае в результате был сформирован фильтр (uid=vasily), во втором — (uid=anton), в третьем — (uid=petr), соответственно были найдены записи пользователей из обоих веток uid=vasily,ou=Managers,dc=mycompany,dc=ru и uid=anton,ou=People,dc=mycompany,dc=ru, а в третьем случае поиск не дал результатов, хотя и прошёл успешно, о чём свидетельствует забавный вывод ERR Success.

    Если запись была найдена, осуществляется попытка простого подсоединения к каталогу от имени этой записи с предоставленным паролем. Факт удачного подсоединения к каталогу означает, что basic-аутентификация прошла успешно (OK).

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

    Пример 2.1.3. Дополнительный критерий. Аутентификация только членов определённой группы

    Часто возникает задача предоставить доступ в Интернет не всем пользователям подряд, а лишь определённому подмножеству. Выделить такое подмножество можно, задав определённое значение какого-либо атрибута, к примеру, ou: Inet Users в записях тех пользователей, которым разрешён доступ в Интернет. В этом случае можно было бы использовать фильтр -f '(&(uid=%s)(ou=Inet Users))'. В нашем тестовом каталоге таких атрибутов нет, но мы можем смоделировать ситуацию, когда используя определённые группы и наложение обратного членства в них (memberof), мы получим операционные (скрытые) атрибуты с указанием на членство в группе. Эти атрибуты мы можем использовать при построении фильтра.

    Задача: провести аутентификацию только тех пользователей, которые входят в группу cn=InetUsers,ou=Groups,dc=mycompany,dc=ru, членам которой разрешён доступ в Интернет.

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

    dn: cn=InetUsers,ou=Groups,dc=mycompany,dc=ru
    objectClass: groupOfUniqueNames
    cn: InetUsers
    uniqueMember: uid=vasily,ou=Managers,dc=mycompany,dc=ru
    uniqueMember: uid=vitaly,ou=People,dc=mycompany,dc=ru
    

    Членами нашей группы (значения атрибута uniqueMember) будут пользователи из разных веток, таким образом мы обозначаем, что расположение записей пользователей в каталоге может быть произвольным. Добавим нашу группу с помощью ldapadd и настроим для нашего DIT наложение memberof на использование объектного класса groupOfUniqueNames и атрибута uniqueMember. Проверим, что получилось:

    # ldapsearch -x -LLL -b 'dc=mycompany,dc=ru' 'memberof=cn=InetUsers,ou=Groups,dc=mycompany,dc=ru' memberOf
    dn: uid=vitaly,ou=People,dc=mycompany,dc=ru
    memberOf: cn=InetUsers,ou=Groups,dc=mycompany,dc=ru
    
    dn: uid=vasily,ou=Managers,dc=mycompany,dc=ru
    memberOf: cn=InetUsers,ou=Groups,dc=mycompany,dc=ru
    

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

    # basic_ldap_auth -b 'dc=mycompany,dc=ru' -f '(&(uid=%s)(memberOf=cn=InetUsers,ou=Groups,dc=mycompany,dc=ru))' -d
    vasily vasilyPassword<Enter>
    user filter '(&(uid=vasily)(memberOf=cn=InetUsers,ou=Groups,dc=mycompany,dc=ru))', searchbase 'dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=vasily,ou=Managers,dc=mycompany,dc=ru'
    OK
    vitaly vitalyPassword<Enter>
    user filter '(&(uid=vitaly)(memberOf=cn=InetUsers,ou=Groups,dc=mycompany,dc=ru))', searchbase 'dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=vitaly,ou=People,dc=mycompany,dc=ru'
    OK
    anton antonPassword<Enter>
    user filter '(&(uid=anton)(memberOf=cn=InetUsers,ou=Groups,dc=mycompany,dc=ru))', searchbase 'dc=mycompany,dc=ru'
    Ldap search returned nothing
    ERR Success
    

    В данном случае мы ищем по всему каталогу (база поиска -b 'dc=mycompany,dc=ru', диапазон по умолчанию — sub), вторым критерием в фильтре является соответствие значения атрибута memberOf DN заданной группы. Пользователи vasily и vitaly, являющиеся членами нашей группы, успешно прошли аутентификацию, а пользователь anton — нет. Это чем-то схоже с отбором по группам, но есть существенное отличие: в фильтре можно задавать только конкретные значения групп или других атрибутов (одно или несколько), получается пресловутое "одним — всё, а другим — ничего". Если же нам нужна ситуация, когда "одним — одно, вторым — другое, третьим — третье, а остальным — ничего", то без использования хелпера ext_ldap_group_acl не обойтись.

    Пример 2.1.4. Другой атрибут. Аутентификация только пользователей из определённой ветки, другой вариант

    Бывает так, что значение атрибута, образующего RDN записи пользователя, не соответствует имени учётной записи пользователя. Первое, что приходит в голову, — каталог Microsoft AD, где RDN образовано атрибутом cn (например, cn=Vitaly Fridzon), а в качестве логина чаще всего используется значение атрибута sAMAccountName. Применительно к нашему экспериментальному каталогу можно поставить задачу так: предоставлять доступ в Интернет только руководителям, аутентификацию проходить по фамилии. Решение:

    # basic_ldap_auth -b 'ou=Managers,dc=mycompany,dc=ru' -s one -f '(sn=%s)' -d
    karasev vasilyPassword<Enter>
    user filter '(sn=karasev)', searchbase 'ou=Managers,dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=vasily,ou=Managers,dc=mycompany,dc=ru'
    OK
    

    Ограничив область (-b 'ou=Managers,dc=mycompany,dc=ru') и диапазон (-s one) поиска, мы, во-первых, получили точное соответствие условиям нашей задачи, а во-вторых, снизили нагрузку на сервер. Фильтр -f '(sn=%s)' позволяет нам отобрать записи по значению атрибута sn, не фигурирующего в RDN. В нашем случае в результате преобразования шаблона мы получили фильтр (sn=karasev), по которому была найдена запись uid=vasily,ou=Managers,dc=mycompany,dc=ru и от имени этой записи было выполнено успешное подсоединение к каталогу (OK).

    Пример 2.1.5. Несколько шаблонов. Значения разных атрибутов в качестве имени пользователя

    При построении фильтра в хелпере basic_ldap_auth можно использовать шаблон %s несколько раз (до 16-ти, согласно документации). Это может пригодиться, если записи у Вас в каталоге устроены по разному и логин хранится в разных атрибутах. В нашем каталоге это не так, но мы можем поставить иную задачу: аутентифицировать пользователей по их логину, либо по фамилии. Решение:

    # basic_ldap_auth -b 'dc=mycompany,dc=ru' -f '(|(uid=%s)(sn=%s))' -d
    anton antonPassword<Enter>
    user filter '(|(uid=anton)(sn=anton))', searchbase 'dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=anton,ou=People,dc=mycompany,dc=ru'
    OK
    ponkrashov antonPassword<Enter>
    user filter '(|(uid=ponkrashov)(sn=ponkrashov))', searchbase 'dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=anton,ou=People,dc=mycompany,dc=ru'
    OK
    

    Поиск происходит по всему каталогу (база поиска -b 'dc=mycompany,dc=ru', диапазон по умолчанию — sub). Фильтр -f '(|(uid=%s)(sn=%s))' в первом случае преобразуется в (|(uid=anton)(sn=anton)), во втором — в (|(uid=ponkrashov)(sn=ponkrashov)). В результате обоих поисков найдена одна и та же запись uid=anton,ou=People,dc=mycompany,dc=ru, от имени которой и происходит подсоединение к каталогу.

    Пример 2.1.6. Дурашливый. Аутентификация только пользователей, начинающихся с определённой буквы
    # basic_ldap_auth -b 'dc=mycompany,dc=ru' -f '(&(uid=%s)(uid=v*))' -d
    vasily vasilyPassword<Enter>
    user filter '(&(uid=vasily)(uid=v*))', searchbase 'dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=vasily,ou=Managers,dc=mycompany,dc=ru'
    OK
    vitaly vitalyPassword<Enter>
    user filter '(&(uid=vitaly)(uid=v*))', searchbase 'dc=mycompany,dc=ru'
    attempting to authenticate user 'uid=vitaly,ou=People,dc=mycompany,dc=ru'
    OK
    anton antonPassword<Enter>
    user filter '(&(uid=anton)(uid=v*))', searchbase 'dc=mycompany,dc=ru'
    Ldap search returned nothing
    ERR Success
    

    Ещё один пример поиска с дополнительным критерием. На этот раз в результат поиска попадают только пользователи, значение атрибута uid которых начинается с буквы v.

2.1.1. Настройка вызова хелпера basic_ldap_auth в файле squid.conf

Итак, с тем, как работает хелпер, мы более-менее разобрались. Дело за малым — внедрить его как средство аутентификации в работу сервера squid. Для этого требуется:

  1. определить параметры вызова и работы самого хелпера,
  2. определить ACL аутентификации,
  3. наконец, определить правило доступа, использующее этот ACL.

Нагляднее рассмотреть это на примере. Для начала покажем возможные параметры вызова хелпера и разные варианты определения ACL, затем рассмотрим их подробнее:

### 1. Настройка Basic-аутентификации с помощью хелпера basic_ldap_auth
## Вызов хелпера
auth_param basic program /path/to/basic_ldap_auth -b "dc=mycompany,dc=ru" -f "(uid=%s)" -H ldap://127.0.0.1:389
## Область действия аутентификации
auth_param basic realm Squid Basic Auth
## Количество параллельно запущенных процессов хелпера
auth_param basic children 5
## "Время жизни" пройденной аутентификации
auth_param basic credentialsttl 2 hours
## Ожидание символов UTF-8 в имени пользователя или пароле
# auth_param basic utf8 on
## Учёт регистра символов в имени пользователя
# auth_param basic casesensitive on

### 2. ACL аутентификации
## ACL возвращает TRUE для всех пользователей, прошедших аутентификацию
acl acl_all_authed_users proxy_auth REQUIRED
## Вариант: ACL возвращает TRUE для конкретных пользователей, прошедших аутентификацию
# acl acl_some_authed_users proxy_auth vasily vitaly
## Вариант: ACL возвращает TRUE для пользователей, прошедших аутентификацию, имя которых соответствует регулярному выражению
# acl acl_regex_authed_users proxy_auth_regex -i ^a.*$

### 3. Правила доступа
## Разрешён доступ всем, кто прошёл проверку
http_access allow acl_all_authed_users
## Вариант: Разрешён доступ конкретным пользователям, прошедшим проверку
# http_access allow acl_some_authed_users
## Вариант: Разрешён доступ пользователям, прошедшим проверку, имя которых соответствует регулярному выражению
# http_access allow acl_regex_authed_users
## Остальным доступ запрещён
http_access deny all

В строках 1-13 определяются настройки Basic-аутентификации. Все директивы настройки Basic-аутентификации начинаются с ключевых слов auth_param basic. Строка 3 интересует нас больше всего, поскольку в ней описывается непосредственно вызов хелпера, на что указывает ключевое слово program. Для этой конфигурации мы используем вызов хелпера с "классическим" вариантом поиска записей в каталоге (смотрите пример 2.1.2 выше), Вы же должны указать параметры, соответствующие Вашей задаче. Аргумент -d мы не указываем, поскольку он нужен для вывода отладочной информации и в рабочей системе будет только мешать. Для примера мы указали аргумент -H, значением которого является URL размещения каталога; если, как в нашем случае, каталог обслуживается на том же сервере и на стандартном порту, данный аргумент можно не указывать. Возможно, Вас заинтересуют и другие аргументы подключения к LDAP-серверу (-P, -O, -Z), их назначение смотрите в man-странице basic_ldap_auth. Ещё раз необходимо обратить внимание на то, что значения аргументов хелпера обрамляются двойными кавычками (с одинарными хелпер просто не будет вызываться).

Все остальные директивы auth_param basic являются опциональными. В строке 5 указывается область действия аутентификации (ключевое слово realm). Для Basic-аутентификации принципиального значения этот параметр не несёт, он выводится как подсказка в диалоге запроса аутентификации. Значение по умолчанию — "Squid proxy-caching web server". В строке 7 указывается, сколько одновременных процессов хелпера будет порождать squid (ключевое слово children). Тут, как говорится, чем больше, тем лучше, главное, чтобы памяти хватало. Значение по умолчанию — 5. В строке 9 указывается "время жизни" результатов аутентификации, то есть как часто повторно вызывается хелпер для проверки аутентификации пользователя с тем же именем. Значения по умолчанию тут нет, многое зависит от того, часто ли у Вас меняются пароли.

Существует ещё несколько директив Basic-аутентификации. В нашем случае они не несут смысловой нагрузки, поэтому мы оставили их закомментированными. В строке 11 указана директива с ключевым словом utf8. Имеет смысл включить её, если в имени пользователя или пароле имеются символы, не входящие в набор iso-latin-1, например, кириллические (в нашем случае это не так). Значение по умолчанию — "off". Наконец, в строке 13 указана директива с ключевым словом casesensitive, то есть чувствительность имени пользователя к регистру символов. В LDAP практически все (за редким исключением) строки к регистру нечувствительны, соответственно, включать этот параметр нет смысла — он не будет работать в любом случае. Значение по умолчанию — "off".

Далее, в строках 15-21, определяются списки контроля доступа (ACL) аутентификации. Как и любые директивы списков контроля доступа, они начинаются с ключевого слова acl, затем следует имя списка и его тип, после чего указываются дополнительные параметры для конкретного типа ACL. Мы рассмотрим 3 варианта ACL аутентификации. Первый из них (строка 17) сработает при успешном прохождении аутентификации любым пользователем. Мы назвали его acl_all_authed_users. Этот вариант используется чаще всего, особенно когда дальнейшее разделение пользователей по группам происходит с помощью каких-либо хелперов внешних ACL.

Другие два варианта (закомментированы в строках 19 и 21) позволяют произвести примитивное разбиение пользователей по группам уже на этапе аутентификации без использования дополнительных ACL. В первом из них (мы назвали его acl_some_authed_users) после ключевого слова proxy_auth, указывающего на тип ACL, явно перечисляются те пользователи, при успешной аутентификации которых этот ACL сработает. Такой вариант разбиения по группам приемлем лишь в системах с небольшим количеством пользователей, которые редко меняются. В последнем из рассматриваемых вариантов (acl_regex_authed_users) после ключевого слова proxy_auth_regex, указывающего на тип ACL, и опции -i приводится регулярное выражение. Этот ACL сработает, если имя пользователя, успешно прошедшего аутентификацию, соответствует указанному в нём регулярному выражению (в нашем случае имя пользователя начинается с буквы a). Как видите, такой подход может быть приемлем только в системах со специфичными условиями. Выбирайте тот вариант, который Вам больше подходит.

Опция -i в последнем ACL приводится для примера и означает, что имя пользователя будет рассматриваться как строка, нечувствительная к регистру символов. Эту опцию можно использовать в любом ACL (не только аутентификации).

Наконец, в строках 23-31 с помощью директив http_access определяются правила доступа на основании ранее определённых ACL. Тут всё просто: срабатывает указанный по имени ACL (основной в строке 25 и два других варианта в закомментированных строках 27 и 29) — срабатывает и правило, и доступ в Интернет разрешён (ключевое слово allow), нет — срабатывает последнее правило в строке 31, запрещающее доступ в Интернет (ключевое слово deny и ACL по умолчанию all). Другими словами, аутентификация пройдена — есть доступ, нет — нет.

Мы весьма бегло прошлись по директивам файла squid.conf. Перед составлением рабочей конфигурации не поленитесь прочитать подробнейшие комментарии файла squid.conf.default (название может отличаться), имеющемся в любом дистрибутиве.

2.2. Digest-аутентификация: digest_ldap_auth

Работа хелпера digest_ldap_auth несколько отличается от работы других хелперов squid тем, что именно он возвращает серверу squid. Это связано со спецификой работы Digest-аутентификации: если после обработки входных параметров хелпер принял отрицательное решение, то он возвращает ERR, а если положительное, то так называемое значение H(A1) (в других источниках — HA1). На основании этого значения и других данных сервер squid вычисляет так называемое значение response, и, если оно совпало с аналогичным значением, вычисленным и переданным клиентом, аутентификация считается успешно пройденной.

Что же представляет из себя значение H(A1)? Это MD5-хэш от строки, собранной из имени пользователя, наименования области действия аутентификации (realm) и пароля пользователя, объединённых через двоеточие, то есть:

H(A1) = MD5(username:realm:password)

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

"username":"realm"

Итак, два из трёх значений уже есть. Осталось только обратиться к каталогу LDAP, определить запись-источник данных, получить оттуда недостающие данные и выдать соответствующее этому пользователю и области значение H(A1). Хелпер может сделать это двумя разными способами:

  1. При наличии в каталоге пароля в открытом виде (как в нашем случае) сформировать требуемую строку и получить её MD5-сумму не составляет труда.
  2. Готовое значение H(A1) заранее помещается в запись каталога, а хелперу указывается, в каком атрибуте его можно получить.

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

Пример 2.2.1. Составление параметров определения записи + пароли в открытом виде. Аутентификация пользователей из ветки Managers
# digest_ldap_auth -b ou=Managers,dc=mycompany,dc=ru -u uid -A userPassword -d
anton:Squid Digest Auth<Enter>
ERR
"anton":"Squid Digest Auth"<Enter>
Connected OK
searchbase 'ou=Managers,dc=mycompany,dc=ru'
ERR No such user
"vasily":"Squid Digest Auth"<Enter>
searchbase 'ou=Managers,dc=mycompany,dc=ru'
password: vasilyPassword
67c6aa0de7fcfe7b3240dcc16c56aa41

Как и basic_ldap_auth, при вызове с аргументами -b и -u хелпер digest_ldap_auth работает в режиме составления DN записи из значений этих аргументов и переданного имени пользователя. В аргументе -A указывается атрибут записи пользователя, содержащий пароль для Digest-аутентификации. В данном вызове мы не указали аргумент -e, сообщающий хелперу о том, что в атрибуте (заданном в аргументе -A) содержится уже сформированное значение H(A1), поэтому хелпер считает, что в этом атрибуте содержится пароль в открытом виде. Обратите внимание, что для Digest-аутентификации squid у пользователя может быть отдельный пароль, хранящийся в совершенно другом атрибуте, и указывать, конечно же, требуется нужный атрибут. Просто в нашем случае так совпало, что хелпер получает нужное значение из основного парольного атрибута userPassword.

С аргументами разобрались, теперь перейдём к передаваемым входным параметрам. Как мы уже знаем, это строка, состоящая из взятого в кавычки имени пользователя и взятого в кавычки наименования области действия аутентификации, объединённых через двоеточие. Если эта строка сформирована неправильно, хелпер сразу выдаёт ошибку, как в первом случае. Во втором случае строка сформирована правильно, хелпер извлекает из неё имя пользователя и формирует утверждение uid=anton (название атрибута uid передано в аргументе -u). Тут поведение digest_ldap_auth отличается от basic_ldap_auth, ведь для выполнения подсоединения достаточно иметь DN записи, а для извлечения значения из записи требуется получить саму запись. Поэтому полученное утверждение uid=anton используется не как RND, а как фильтр для выполнения поиска с базой, переданной в аргументе -b. Во втором случае поиск с фильтром uid=anton в ветке ou=Managers,dc=mycompany,dc=ru результатов не даёт и возвращается ошибка ERR No such user. В третьем случае поиск с фильтром uid=vasily в той же ветке возвращает соответствующую запись, из неё извлекается значение атрибута userPassword (передан в аргументе -A), формируется значение H(A1) и выдаётся на стандартный выход. Получив это значение, squid сам принимает решение, прошёл пользователь аутентификацию, или нет. Следует отметить, что если при выполнении поиска запись будет найдена, но в ней не окажется нужного атрибута, хелпер также выдаст ошибку ERR No such user.

Пример 2.2.2. Поиск требуемой записи + готовое значение H(A1). Аутентификация пользователей всего каталога

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

  1. Сформировать значение H(A1).
  2. Определить атрибут записи, в котором хелпер будет искать значение H(A1).
  3. Модифицировать запись пользователя, поместив сформированное значение в выбранный атрибут.

Для нашего примера возьмём пользователя anton, область аутентификации Squid Digest Auth и пароль antonDigestPassword. Сформируем H(A1):

#  echo anton:Squid Digest Auth:antonDigestPassword | md5sum | cut -d ' ' -f 1
1f5f8526da25fce2238f08cdf280fae7

Не будем оригинальничать и в качестве атрибута для хранения H(A1) возьмём, как и в официальном руководстве, атрибут l (location). Разумеется, можно взять и любой другой незанятый атрибут объектного класса inetOrgPerson (в нашем случае). Сформируем файл anton_digest.ldif такого содержания:

dn: uid=anton,ou=People,dc=mycompany,dc=ru
changetype: modify
add: l
l: Squid Digest Auth:1f5f8526da25fce2238f08cdf280fae7

Как видно, в запись пользователя anton добавляется выбранный нами атрибут l со значением, состоящим из названия области аутентификации и сформированного H(A1), разделённых двоеточием (разделитель может быть и иным, тогда его нужно явно указывать в аргументе -l хелпера digest_ldap_auth). Название области аутентификации приводится в этом значении на тот случай, если пользователь проходит Digest-аутентификацию в нескольких разных системах с разными паролями.

Применим наши изменения:

# ldapmodify -x -D cn=manager,dc=mycompany,dc=ru -W -f ./anton_digest.ldif 
Enter LDAP Password: 
modifying entry "uid=anton,ou=People,dc=mycompany,dc=ru"

Посмотрим, что у нас получилось:

# ldapsearch -x -LLL -b 'dc=mycompany,dc=ru' 'uid=anton'
dn: uid=anton,ou=People,dc=mycompany,dc=ru
objectClass: inetOrgPerson
uid: anton
cn: Anton Ponkrashov
sn: Ponkrashov
userPassword:: YW50b25QYXNzd29yZA==
l: Squid Digest Auth:1f5f8526da25fce2238f08cdf280fae7

Осталось протестировать собственно Digest-аутентификацию (напомним, поиск записей пользователей будет вестись по всему каталогу):

# digest_ldap_auth -b dc=mycompany,dc=ru -s sub -F uid=%s -e -A l -d
"vasily":"Squid Digest Auth"<Enter>
Connected OK
user filter 'uid=vasily', searchbase 'dc=mycompany,dc=ru'
No attribute value found
ERR No such user
"anton":"Squid Proxy Auth"<Enter>
user filter 'uid=anton', searchbase 'dc=mycompany,dc=ru'
password: (null)
ERR No such user
"anton":"Squid Digest Auth"<Enter>
user filter 'uid=anton', searchbase 'dc=mycompany,dc=ru'
password: 1f5f8526da25fce2238f08cdf280fae7
1f5f8526da25fce2238f08cdf280fae7

Аргументы -b, -s и -F задают критерии поиска записей в каталоге LDAP: базу поиска, диапазон поиска и фильтр, соответственно. Всё это нам уже знакомо по хелперу basic_ldap_auth, также как и наличие шаблона %s в поисковом фильтре, который заменяется на имя пользователя, получаемое из входной строки. Самые интересные для нас аргументы: -e — говорит о том, что в каталоге в записи пользователя хранится уже сформированное значение H(A1), и -A — указывает атрибут записи, из которого это значение можно извлечь (в данном случае атрибут l).

На вход хелпер принимает уже знакомую нам строку, состоящую из взятого в кавычки имени пользователя и взятого в кавычки наименования области действия аутентификации, объединённых через двоеточие. В первом случае из входной строки сформирован фильтр uid=vasily, в результате поиска с базой dc=mycompany,dc=ru и диапазоном sub была найдена запись uid=vasily,ou=Managers,dc=mycompany,dc=ru, но в ней не оказалось искомого атрибута l, поэтому хелпер вернул ошибку. Во втором случае был указан пользователь anton, в записи которого присутствует искомый атрибут l, но имя области аутентификации указано неверно (не совпадает с именем в атрибуте l). В результате получить значение H(A1) для запрашиваемой области аутентификации не удалось и хелпер вновь вернул ошибку. Наконец, в третьем случае переданные параметры позволили найти запись uid=anton,ou=People,dc=mycompany,dc=ru и извлечь из неё требуемое значение H(A1), которое хелпер вернул на стандартный вывод.

2.2.1. Настройка вызова хелпера digest_ldap_auth в файле squid.conf

Осталось показать, как внедрить хелпер digest_ldap_aut в качестве средства аутентификации сервера squid. Основные постулаты всё те же, что и для хелпера basic_ldap_auth (да и для любого другого механизма аутентификации squid):

  1. определить параметры вызова и работы самого хелпера,
  2. определить ACL аутентификации,
  3. определить правило доступа, использующее этот ACL.

Поскольку всё это уже подробно обсуждалось в примере настройки хелпера basic_ldap_auth, ограничимся лишь коротким примером и необходимыми пояснениями к нему:

### 1. Настройка Digest-аутентификации с помощью хелпера digest_ldap_auth
## Вызов хелпера
auth_param digest program /path/to/digest_ldap_auth -b "dc=mycompany,dc=ru" \
    -F "(&(objectClass=inetOrgPerson)(uid=%s)(l=Squid Digest Auth:*))" \
    -e -A l -H ldap://127.0.0.1:389 -P
## Область действия аутентификации
auth_param digest realm Squid Digest Auth
## Количество параллельно запущенных процессов хелпера
# auth_param digest children 5
## Ожидание символов UTF-8 в имени пользователя или пароле
# auth_param digest utf8 on
## Заплатка для некоторых браузеров, неверно обрабатывающих Digest-аутентификацию при POST-запросах
# auth_param digest post_workaround on
## Настройка параметров метки nonce
# auth_param digest nonce_garbage_interval 5 minutes
# auth_param digest nonce_max_duration 30 minutes
# auth_param digest nonce_max_count 50
# auth_param digest nonce_strictness off
# auth_param digest check_nonce_count on

### 2. ACL аутентификации
## ACL возвращает TRUE для всех пользователей, прошедших аутентификацию
acl acl_all_authed_users proxy_auth REQUIRED

### 3. Правила доступа
## Разрешён доступ всем, кто прошёл проверку
http_access allow acl_all_authed_users
## Остальным доступ запрещён
http_access deny all

В строках 1-19 определяются настройки Digest-аутентификации. Все директивы настройки Digest-аутентификации начинаются с ключевых слов auth_param digest. В строках 3-5 описывается вызов хелпера, на что указывает ключевое слово program. В данном случае мы воспользовались вариантом вызова хелпера из примера 2.2.2, несколько расширив фильтр поискового запроса LDAP для более точного отбора интересующих нас записей каталога. Также мы указали аргумент -H чтобы показать, с какого именного LDAP-сервера мы хотим получать данные, опустили аргумент -d (в рабочей системе вывод отладочной информации излишен) и добавили аргумент -P (установка постоянного соединения с LDAP-сервером, чтобы не тратить время на повторные подключения).

В строке 7 указывается область действия аутентификации (ключевое слово realm). В отличие от Basic-аутентификации, данный параметр для Digest-аутентификации крайне важен, поскольку на его основе строятся различные значения, которыми обмениваются клиент и сервер в процессе аутентификации, в том числе значение H(A1). Здесь обязательно следует указывать именно то имя области аутентификации, которое мы использовали при формировании значения H(A1) для записей пользователей в LDAP-каталоге.

Все остальные директивы auth_param digest являются опциональными. Часть из них мы уже обсуждали при настройке Basic-аутентификации, описание других можно посмотреть в комментариях файла squid.conf.default. Информацию по отметке nonce можно найти в RFC 7616.

Списки контроля доступа (строки 21-23) и настройка разграничения доступа на их основе (строки 25-29) подробно обсуждались в примере по Basic-аутентификации. При успешном прохождении аутентификации пользователь получает доступ, в противном случае — нет.

2.3. Другие схемы аутентификации squid

Кроме двух рассмотренных схем аутентификации, squid поддерживает ещё схемы NTLM и Negotiate. Обе они были разработаны для интеграции squid в концепцию Microsoft SSO (Single Sign On, технология единого входа). Поскольку прямого отношения к LDAP они не имеют, мы рассмотрим их очень кратко, чтобы в дальнейших примерах иметь некоторое представление об их работе.

NTLM-аутентификация для проверки подлинности пользователя использует обмен пакетами NTLMSSP, характерными для доменов Windows NT (samba3). Официальное HOWTO по настройке NTLM-аутентификации. Для нас важно, что после прохождения NTLM-аутентификации в переменную squid %LOGIN помещается конструкция ИМЯ_ДОМЕНА_WINNT+разделитель+имя_пользователя, например, MYCOMPANY\alex.

Negotiate-аутентификация для проверки подлинности пользователя использует протокол Kerberos. Такая аутентификация характерна для доменов Microsoft Active Directory (samba4). Официальное HOWTO по настройке Negotiate-аутентификации. Для нас важно, что после прохождения Negotiate-аутентификации в переменную squid %LOGIN помещается принципал Kerberos в виде имя_пользователя@REAML, например, anton@mycompany.ru.

В squid.conf можно настроить работу сразу нескольких типов аутентификации, последовательно задав директивы сначала для первого типа, затем для второго и т.д. В этом случае будет предпринята попытка поочерёдно выполнить аутентификацию каждого типа в порядке их указания, пока какая-либо из попыток не увенчается успехом, или все завершатся неудачей. Пример настройки нескольких типов аутентификации можно посмотреть в файле squid.conf.default.

Последнее изменение страницы — 13 октября 2016 года.

Содержание   Часть 1   Часть 3

Обсуждение статьи на форуме проекта Pro-LDAP.ru.

Эта страница

Содержание

2. Аутентификация
Squid+LDAP. Часть 2
OpenLDAP 2.4 Руководство

Содержание

Введение в службы каталогов OpenLDAPБыстрое развёртывание и начало работыОбщая картина - варианты конфигурацииСборка и установка OpenLDAPНастройка slapd

 

Конфигурационный файл slapdЗапуск slapdКонтроль доступаОграниченияИнструментыМеханизмы манипуляции даннымиНаложенияСпецификация схемы

 

БезопасностьSASLTLSРаспределённая служба каталоговРепликацияОбслуживаниеМониторингПроизводительностьУстранение неполадок
Перевод официального руководства OpenLDAP 2.4 Admin Guide
Полное содержание здесь
LDAP для учёных-ракетчиков

Содержание

О книгеКонцепции LDAPОбъекты LDAPУстановка LDAPПримерыНастройкаРепликация и отсылкиLDIF и DSMLПротоколLDAP API

 

HOWTOНеполадкиПроизводительностьИнструменты LDAPБезопасностьЗаметкиРесурсы LDAPRFC и X.500ГлоссарийОбъекты
Перевод "LDAP for Rocket Scientists"
Полное содержание здесь
Ресурсы

Книги

Руководство OpenLDAP 2.4LDAP для учёных-ракетчиков

Другие

СтатьиТермины LDAPman-страницы OpenLDAP 2.4Список RFCКлиенты LDAPФайлы наборов схемы
Полезные ресурсы
Форум

 

Разделы форумаНепрочитанные сообщенияПоследние сообщения
Форум проекта
Главная

Pro-LDAP.ru

О проектеНовости проектаУчастникиСтаньте участником!Сообщите об ошибке!Об авторских правахСоглашения проекта
Присоединяйсь!