Book
- Apache - DNS settings
- Apache - SSL certificates
- Apache - Configuration files
- Apache - Virtual host template
- Apache - Authorization
- Apache - Localized error pages
- Apache - Single sign-on
- Apache - Automatic proxy configuration
- Apache - Installing SSL certificate in browsers
- Apache - Web applications
- Apache - User wiki
- Apache - Intrusion protection
- Apache - External resources
- Apache - Optimization
- Squid setup
SSO - PubCookie
Существует множество решений, позволяющих в том или ином виде реализовать технологию единого входа (Single Sign On). Под единым входом понимается ситуация, когда авторизовавшись один раз на некотором выделенном сервере авторизации (или просто на своей машине), вы получаете доступ ко всем доступным сетевым ресурсам без дополнительной авторизации. Технологии SSO, как правило, достаточно непростые, однако если ограничиться задачей единого входа только для набора веб-приложений, существует относительно несложное решение, позволяющее реализовать такую возможность, не меняя, или незначительно меняя код приложения. Это решение называется Pubcookie, о нем и пойдет речь.
Если мы используем Pubcookie, то при заходе на защищенный ресурс нас автоматически редиректят на специальный выделенный логин-сервер, на котором мы авторизуемся и автоматически возвращаемся назад. При этом нам не нужно ничего менять в защищаемом приложении, оно как и раньше получает имя текущего пользователя из REMOTE_USER.
В этой статье рассматривается, как этот механизм можно настроить, и как он работает в связке с веб-сервером Apache. Для пользователей Nginx есть отдельная статья.
Схема работы
В процессе аутентификации задействованы следующие компоненты:
- Клиентский браузер;
- Сервер приложений, на котором развернуто приложение, требующее аутентификации, в нашем случае это Apache с модулем Pubсookie и, собственно, защищаемым приложением;
- Логин-сервер, в нашем случае это опять же Apache со стандартным приложением аутентификации и нашими настройками этого приложения;
- Собственно, сервис аутентификации.
Аутентификация производится следующим образом:
- Пользовательский браузер запрашивает определенный ресурс с сервера приложений, сконфигурированного для использования Pubcookie.
-
Модуль Pubcookie, установленный на сервере приложений, перехватывает запрос и проверяет, что он не связан с валидной текущей сессией и не содержит информацию от логин-сервера (т.н. granting cookie) для создания новой сессии.
В случае успешной проверки модуль генерирует отклик, содержащий редирект и две куки: presession cookie для приложения и granting request cookie для логин-сервера Обе куки содержат, помимо прочей информации, случайное число, сгенерированное модулем. Все куки передаются в зашифрованном виде. - Клиентский броузер выполняет редирект (granting request) к логин-серверу с передачей ему granting request cookie. Данные запроса позволяют серверу доступа определить сервер приложений, для которого запрашивается аутентификация, URL оригинального запроса, тип авторизации и т.д.
- Логин-сервер декодирует granting request cookie и интерпретирует содержимое. Сервер генерирует форму входа и отсылает ее клиенту.
- Пользователь вводит свои логин и пароль в форму и отсылает ее на логин-сервер;
- Логин-сервер получает логин и пароль и отсылает их используемому сервису аутентификации для проверки.
- Логин-сервер получает результат проверки от сервиса аутентификации.
- Если проверка прошла успешно, логин-сервер формирует отклик, содержащий редирект и две новых куки. Первая, granting cookie, предназначена для сервера приложений и содержит проверенное имя пользователя и дополнительную информацию, включая случайное число, сгенерированное в пункте 2, подписана приватным ключем сервера доступа и зашифрована симметричным ключем, используемым на сервере приложений и сервере доступа. Вторая, login cookie, предназначена для логин-сервера и используется в случае последующих заходов пользователя на него.
- Пользовательский браузер повторно запрашивает защищенный ресурс с сервера приложений. Запрос содержит granting cookie и presession cookie.
- Модуль pubcookie на сервере приложений перехватывает запрос, расшифровывает granting cookie, проверяет подпись и сравнивает случайное число в granting cookie с аналогичным числом в presession cookie. Если все сходится, имя пользователя передается приложению и выполняется обработка запроса приложением. При этом также генерируется session cookie, для последующих обращений к защищенным ресурсам. Отклик, сгенерированный приложением, отсылается пользователю.
В случае, если на шаге 4 granting request содержит также валидную login cookie (установленную на шаге 8), шаги 5, 6 и 7 пропускаются и логин-сервер переходит сразу к шагу 8, генерируя granting cookie использyя имя пользователя, полученное из login cookie. Таким образом, мы получаем элемент технологии Single Sign On для набора веб-приложений: не нужно авторизоваться для каждого веб-приложения, достаточно указать свои логин и пароль один раз.
Сборка
Мы рассмотрим для Ubuntu, под FreeBSD тоже не вызывает проблем:
Скачиваем дистрибутив с www.pubcookie.org. Перед сборкой делаем два патча:
1. Патчим configure на предмет проблемы с APXS:
3783c3783 < APACHE_PREFIX=`$APXS -q PREFIX` --- > APACHE_PREFIX="/usr/share/apache2"
Тут методом удара молотком, можно и правильнее, наверное, сделать.
2. Патчим src/index.cgi.c на предмет UTF-8 кодировки:
461c461 < print_header (p, "Content-Type: text/html; charset=ISO-8859-1\n"); --- > print_header (p, "Content-Type: text/html; charset=utf-8\n");
При конфигурировании указызываем сборку модуля и cgi-приложения для входа:
$./configure --enable-apache --with-apxs=/usr/bin/apxs2 --enable-login
Потом собираем, желательно в deb-пакет.
Генерация ключей и сертификатов
Для работы с защищенными ресурсами используется https. Ну, на то они и защищенные.
Генерируем две пары ключей. Первая — SSL key pair, используется апачем для SSL и сервером ключей (о нем ниже):
$ openssl req -new -x509 -out server.crt -newkey rsa:1024 -nodes -keyout server.key
Вторая — granting key pair, для подписи и проверки granting cookies:
$ openssl req -new -x509 -out granting.crt -newkey rsa:1024 -nodes -keyout granting.key
Пример чисто демонстрационный, мы используем self-signed сертификаты, в реальности все сложнее. Соответственно генерируем игрушечный CA bundle:
$ cp server.crt ca-bundle.crt
В результате получаем файлы: server.crt, server.key, granting.crt, granting.key, ca-bundle.crt.
Настройка логин-сервера
Пусть сервер называется access.techart.intranet
На сервере доступа выполняются сервер ключей и приложение аутентификации под управлением веб-сервера.
Сервер ключей распространяет симметричные ключи, использующиеся для шифрования содержимого кук. Он запускается под xinetd, соответственно, прописываем его туда:
service keyserver
{
type = UNLISTED
protocol = tcp
port = 2222
disable = no
socket_type = stream
wait = no
user = root
group = tty
server = /usr/local/pubcookie/keyserver
}
После перезапуска xinetd сервер доступен на порту 2222.
Приложение аутентификации — это обычное CGI-приложение, которое должно быть доступно по https. Соответственно, для него необходимо настроить virtual host:
<VirtualHost *:443>
ServerName login.techart.intranet
DocumentRoot /usr/local/pubcookie/login
DirectoryIndex index.cgi
AddHandler cgi-script cgi
<Directory />
Options FoolowSymLinks
Options +ExecCGI
AllowOverride None
</Directory>
SSLEngine on
SSLCertificateFile /usr/local/pubcookie/keys/server.crt
SSLCertificateKeyFile /usr/local/pubcookie/keys/server.key
</VirtualHost>
Осталось сконфигурировать pubcookie. Правим файл /usr/local/pubcookie/config:
# Уровень детализации логов logging_level: 1 # Используемый сервис аутентификации. # В нашем примере мы используем пользовательский скрипт auth.php, # который обращается к базе данных. basic_verifier: verify_fork verify_exe: /usr/local/pubcookie/auth.php # Пара ключей SSL ssl_key_file: /usr/local/pubcookie/keys/server.key ssl_cert_file: /usr/local/pubcookie/keys/server.crt # Пара granting ключей granting_key_file: /usr/local/pubcookie/keys/granting.key granting_cert_file: /usr/local/pubcookie/keys/granting.crt # Логин-сервер (CGI) login_uri: https://access.techart.intranet/ login_host: access.techart.intranet enterprise_domain: .techart.intranet logout_prog: /logout/index.cgi # Сервер ключей keymgt_uri: localhost:2222 ssl_ca_file: /usr/local/pubcookie/keys/ca-bundle.crt # Срок жизни сессии default_l_expire: 8h # Параметры шаблонов логин-сервера, в частности, сообщение о закрытии сессии. app_logout_string-app1.techart.intranet-app1: Разлогинились из app1
В этом примере мы используем режим verify_fork, когда в качестве сервиса аутентификации используется произвольная внешняя программа, возвращающая нормальный или ошибочный код завершения в зависимости от того, был ли опознан пользователь. При этом имя пользователя и пароль программа читает из stdin.
В нашем случае это php-скрипт, который может, например, обратиться в базе данных или текстовому файлу, вместе с тем, поддерживаются и другие режимы, например, работа с LDAP и Kerberos.
Теперь генерируем ключ, позволяющий логин-серверу соединиться с сервером ключей:
sudo keyclient -P access.techart.intranet
Сгенерированный ключ будет записан в keys/access.techart.intranet. Эту операцию необходимо выполнить для каждого хоста, использующего Pubcookie.
После выполнения всех этих манипуляций по адресу access.techart.intranet/ мы должны увидеть форму логина.
Настройка сервера приложений.
На сервере приложения настраиваем конфигурационный файл pubcookie так же, как и на сервере доступа. Помимо этого, необходимо подключить к Апачу модуль mod_pubcookie.
Для этого создаем файл /etc/apache2/mods-available/pubcookie.conf:
PubcookieGrantingCertFile /usr/local/pubcookie/keys/granting.crt PubcookieSessionKeyFile /usr/local/pubcookie/keys/server.key PubcookieSessionCertFile /usr/local/pubcookie/keys/server.crt PubcookieKeyDir /usr/local/pubcookie/keys/ PubcookieLogin https://access.techart.intranet/ PubcookieLoginMethod POST PubcookieDomain .techart.intranet PubcookieEncryption AES PubcookieAuthTypeNames EGNetID
Дальше все как обычно:
/etc/apache2/mods-available/pubcookie.load: LoadModule pubcookie_module /usr/lib/apache2/modules/mod_pubcookie.so $ sudo a2enmod pubcookie $ sudo service restart apache2
Теперь настраиваем собственно приложение:
<VirtualHost *:443>
ServerName app1.techart.intranet
<Directory /srv/http/app1>
AuthType EGNetID
require valid-user
PubcookieAppID app1
Options Indexes FollowSymLinks MultiViews
AllowOverride None
AllowOverride AuthConfig
Order allow,deny
allow from all
</Directory>
SSLEngine on
SSLCertificateFile /usr/local/pubcookie/keys/server.cert
SSLCertificateKeyFile /usr/local/pubcookie/keys/server.key
</VirtualHost>
В данном случае мы закрыли доступ ко всему приложению, однако мы могли бы прописать опции аутентификации для конкретного подкаталога, вынести их в .htaccess и т.д.
Установка опции AllowOverride AuthConfig позволяет приложению получить имя текущего пользователя из REMOTE_USER.
Перезапускаем Apache, и если все прошло нормально, то при заходе на https://app1.techart.intranet/ нас должно отредиректить на https://login.techart.intranet/, где мы авторизуемся и автоматически возвращаемся обратно.
Виртуальные хосты
Все вышеописанное работает для виртуальных хостов, привязанных к выделенному IP. Для работы с name-based virtual hosts необходима поддержка SNI в OpenSSL, (с версии 0.9.8j) и в Apache (с 2.2.12). Кроме того, SNI не поддерживается IE версий ниже 7.
Для такой конфигурации поле Common Name должно содержать список используемых хостов. Правим openssl.cnf и заново генерируем набор ключей.
[req_distinguished_name] 0.commonName = Common Name (eg, YOUR name) 0.commonName_default = app1.techart.intranet 0.commonName_max = 64 1.commonName = Common Name (eg, YOUR name) 1.commonName_default = app2.techart.intranet 1.commonName_max = 64 ...
В описание виртуального хоста в Apache прописываем:
SLCipherSuite HIGH SSLProtocol all -SSLv2
и перезапускаем apache.
Настройка пользовательского интерфейса сервера доступа
Внешний вид формы логина и служебных страниц логин-сервера можно настроить с помощью шаблонов, которые лежат в каталоге login_templates. Для использования UTF-8 нужно пропатчить index.cgi.c.
Настройка logout
Закрытие сессии может быть выполнено как в отдельном приложении, так и на логин-сервере. Самые простой способ сделать это на логин-сервере — создать подкаталог logout с .htaccess, содержащим единственную директиву:
PubcookieEndSession redirect
Итого
В целом механизм достаточно простой, основная сложность в настройке связана не столько с Pubcookie, сколько с OpenSSL. Соответственно, в случае внедрения самое важное — правильно настроить базовую инфраструктуру управления ключами/сертификатами. В то же время, в ситуации, когда в интранет-сети есть достаточно много legacy-приложений, использование Pubcookie позволяет с минимальными усилиями реализовать для них централизованный контроль доступа.
Related Links
- Еще одна статья про pubcookie, "Single sign-on with PubCookie"
- Конфигурация pubcookie (case.edu)
- Модуль авторизации Pubcookie для Nginx (vitki.net)
- Сайт проекта pubcookie
- Старая, но все еще актуальная статья по pubcookie, "Installing PubCookie 3.3 on Ubuntu 7.10 with Apache2"
- Статья про pubcookie на хабре
Attachments

- Visit Еще одна статья про pubcookie, "Single sign-on with PubCookie"
- Visit Конфигурация pubcookie (case.edu)
- Visit Модуль авторизации Pubcookie для Nginx (vitki.net)
- Visit Сайт проекта pubcookie
- Visit Старая, но все еще актуальная статья по pubcookie, "Installing PubCookie 3.3 on Ubuntu 7.10 with Apache2"
- Visit Статья про pubcookie на хабре

Comments
Post new comment