Как стать автором
Обновить

Одновременная межсайтовая аутентификация без велосипеда

Время на прочтение6 мин
Количество просмотров21K
Одновременная межсайтовая аутентификация (SSO), для чего же она нужна? Допустим у нас есть, назовём его анахроничным термином «портал», с блогами, фотками, фейлами (или файлами, кому как), назовём его fail.ru (не путать с одноимённым сервисом почты на букву М), причём всё это усложнено следующими факторами:
— функционал совершенно разный;
— код написан разными людьми, с испольованием разных технологий;
— работает всё это на разных серверах в разных датацентрах и с разными базами данных;
— сервера находятся на разных доменах.

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

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

Далее мы рассмотрим самописные альтернативы, OpenID, OAuth, SAML, и почему всё это в общем случае не слишком хорошее решение, вопросы хранения аутенитификационных данных, а также некоторые вопросы безопасности в которые без хороших знаний самому лезть не стоит, что такое вообще межсайтовая аутентификация, развеем некоторые мифы.

Удачные решения для менее универсальных случаев


В реальной жизни бывает не так всё запущено, как в том случае, который мы рассматриваем, и порой кажется, что можно обойтись решением с выставлением общей cookie, но как только появляется внешний домен, либо пропадает общая БД для хранения сессий, решение отпадает.

Можно испльзовать вариант, описанный здесь, но в комментариях довольно много негатива по поводу iframe, javascript и прочего.

OpenID


В сети есть очень интересная заметка по поводу того, что OpenID решает проблему, которую сам и придумал. OpenID — не нужная прослойка между почтой и тем сайтом, на которым вы хотите аутентифицироваться. Например, есть у вас аккаунт на coolopenid.net, который привязан к вашей почте. При входе на целевой сайт вас отправят на coolopenid.net, там либо посмотрят cookie, если вы уже залогинены, либо спросят емейл и пароль, вы подтвердите свою личность, и далее входите на целевой сайт, как, например, foo1@coolopenid.net. Правда, не намного проще, чем подтвеждение через ссылку на электронную почту?

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

OAuth


OAuth выполняет двойную задачу, аутентификацию на стороннем сайте и авторизацию на сайте-провайдере, давая пользователю возможность использовать возможности стороннего ресурса для расширения возможностей сайта-провайдера, например, заливать ссылки на фотографии в Twitter, добавлять информацию о текущем местонахождении в Facebook. Хорошее объяснение разницы здесь. Это замечательная и полезная вещь, но она призвана объединить сайты разных поставщиков, в то время как у нас всё-таки есть общее центральное хранилище имён пользователей.

SAML


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

CAS


Читатель, наверное, уже смекнул, что я клоню к какой-то одной вещи, пытаясь убедить его в однозначности правильного выбора. И да, и нет. Хотелось описать свои метания, свой выбор и свою практику. Однозначного выбора нет, хотя для моих нужд и с моим багажом знаний CAS самое простое и всеобъемлющее решение.

CAS — это протокол, специально разработанный для одновременной межсайтовой аутентификации. У протокола есть по крайней мере две имплементации, по крайней мере одна из которых активно развивается. Выбор в пользу второй можно подкрепить тем, что нет необходимости для сервера тащить за собой пугающие многих Java зависимостей (в ущерб необходимости тащить за собой пугающие многих Ruby зависимости).

Также из плюсов можно отметить, что CAS может работать в том числе с толстыми клиентами, и даже не требует возможности установки cookies у клиентского агента. Существует достаточное количество клиентов под разные платформы для простой интеграции аутентификации пользователя через CAS.

CAS делает не много. Он не хранит данные о пользователях, он не хранит их роли, и не знает ничего о других участниках. В качестве хранилища пользователей можно использовать:
— базу данных
— LDAP/AD
— SPNEGO
— RADIUS
— сторонний сервис
— … да хоть текстовый файл

Возможно использование и с двухфакторной аутентификацией, и с usb-токенами с использованием X.509 сертификатов.

Критка и мифы

CAS — старый проект, не развивается. Текущая версия сервера — 3.4.8, последняя ревизия протокола — 2005 год.

Последнее обновление — 9 ноября этого года.
Видимо, протокол вполне реализует необходимый для нужд SSO функционал, и дальнейшее развитие не требуется, как, например, протокол HTTP не обновлялся с июня 1999го года.

CAS — непопулярный проект. Несмотря на то, что ему не один год, он так и не получил признания — практически никакого. Тот факт, что используют 120 школ, колледжей и университетов И БОЛЬШЕ НИКТО, говорит о том, что никто другой и не может его использовать.

Не факт, что все, кто используют эту одну из имплементаций, показаны по этой ссылке.

CAS разрабатывается одной фирмой под свою конкретную задачу. Программисты, которые написали CAS занимаются тем, что делают свой образовательный портал.

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

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

Можно сказать то же самое и о других упоминавшихся в обсуждаемом топике решениях. Хотя, возможно, я чего-то не знаю.

Удивительно маленькое коммьюнити. Если мы поищем в сети типичную ошибку общего свойства, то мы найдем всего 100 отзывов.

Ищете правильно. About 3,210,000 results (0.21 seconds). Если поставить в кавычки, то есть искать точное совпадение — 7.5 тысяч.

Удивительно малое число реализаций. Собственно, есть ТОЛЬКО ДВЕ имплементации CAS сервера. А сколько СОТЕН имплементаций OpenID провайдеров написано?

OpenID — не альтернатива, как описано выше. Количество реализаций не говорит о простоте интеграции.

Принцип работы

Первый вход.
1. Пользователь заходит на страницу, доступ к которой есть только у зарегистрированных пользователей.
2. Сайт делает HTTP переадресацию на CAS-сервер.
3. Пользователь вводит логин и пароль.
4. CAS через нужный адаптер определяет правильность логина и пароля.
5. В случае успешной аутентификации CAS-сервер переадресует пользователя на страницу, указанную сайтом как страница успешного входа, прикрепляя в запросе служебный проверочный тикет.
6. Сайт делает внутренний межсайтовый HTTP запрос к CAS-серверу на проверку тикета.
7. Пользователь авторизован, можно связывать его session cookie с логином, полученным от CAS-сервера.

Повторный вход (например, на сайт 2).
1. Пользователь заходит на страницу, доступ к которой есть только у зарегистрированных пользователей.
2. Сайт делает HTTP переадресацию на CAS-сервер.
3. CAS-сервер видит cookie пользователя и переадресует пользователя на страницу, указанную сайтом как страница успешного входа, прикрепляя в запросе служебный проверочный тикет.
4. Сайт делает внутренний межсайтовый HTTP запрос к CAS-серверу на проверку тикета.
5. Пользователь авторизован, можно связывать его session cookie с логином, полученным от CAS-сервера.

Такой способ закрывает достаточное количество дыр в безопасности.

Установка

1. Ruby version manager
bash < <(curl -s raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )
echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] &&. "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile

2. Ruby
rvm install 1.9.2
rvm use --default 1.9.2
gem install bundler

3. rubycas-server
git clone git@github.com:rubycas/rubycas-server.git
cd rubycas-server
bundle install

4. Устанавливаем thin (веб-сервер) и запускаемся
gem install thin
thin start
Это самый простой, но не самый лучший вариант. Стоит рассмотреть запуск под unicorn и nginx.

Использование на клиенте

На примере Ruby/Rack/Sinatra приложения:

Gemfile:

gem 'oa-enterprise', :require => 'omniauth/enterprise'


Приложение:

set :login_page, "/auth/cas"

use OmniAuth::Strategies::CAS, :cas_server => 'https://ruby-cas.mydomain.com'

get '/auth/cas/callback' do
auth = request.env[«omniauth.auth»]
account = Account.first(:email => auth[«uid»]) || Account.first(:email => auth[«uid»], :role => :external)
set_current_account(account)
redirect '/'
end
Теги:
Хабы:
+32
Комментарии32

Публикации