Изменения

Перейти к: навигация, поиск

Кратко об SSO через OAuth2

2469 байтов добавлено, 13:40, 27 августа 2020
м
Нет описания правки
== Устройство SSO ==
Как устроено SSO? Принцип всегда один — один — всегда есть кто-то, кто авторизует первым — первым — это провайдер.
Дальше все сервисы получают от провайдера какой-то вид ключа (токен). Точнее в OAuth2 пара токенов — токенов — access и refresh, но не суть. С токеном ты идёшь в API провайдера и спрашиваешь — спрашиваешь — это кто? Провайдер говорит — говорит — ну типа вот, это юзер такой-то. Вот и всё SSO. Второй вариант — ты сам извлекаешь детали пользователя из токена и сам его валидируешь с помощью сертификата, например, так можно сделать с JWT (JSON Web Token). И, на самом деле, похожим образом устроен даже Kerberos.
При кроссдоменном SSO способа передачи токена через браузер я знаю два:
# Двойной редирект: пришли к вам, вы не знаете кто это, cookie у вас нет, вы редиректите его на провайдера, а в провайдере у него cookie уже есть. Провайдер достаёт токен из куки и редиректит обратно, но уже с токеном. Либо куки ещё нет — нет — тогда провайдер показывает страничку входа, и после входа так же редиректит обратно.
# Подключение js с другого домена: провайдер выставляет у себя URL, по которому, в случае если сессия пользователя уже активна, отдаётся js, делающий программно путём js вызов/редирект, передающий токен в ваше приложение.
А дальше всё то же самое — самое — берёте токен и идёте по нему в API провайдера, спрашиваете что за юзер, сохраняете себе токен на время жизни сессии.
Во всех протоколах — протоколах — что OpenID, что OAuth2, что CAS обычно в итоге используется 1-й способ в итоге, но для публичных сайтов 2-й на самом деле прикольней, так как:
* с ним не бывает проблемы бесконечного цикла редиректов (юзера нет -> редирект -> произошла ошибка -> редирект обратно с косым кодом/без кода/короче что-то не сработало -> упс опять юзера нет -> редирект…)
* для публичных сайтов позволяет НЕ создавать по сессии на каждого пришедшего юзера и НЕ делать лишних редиректов для анонимусов = экономия места в хранилище сессий и удовлетворение поисковиков
По идее передача токена через браузер (через обратный редирект с Authorization URL’а) предусмотрена непосредственно в самом OAuth2 стандарте, так что плагины должны её поддерживать. Только стандарт требует HTTPS, а то токены голые по сети летают.
Еще есть такой протокол как CAS — CAS — но реализации всего две, https://github.com/rubycas/rubycas-server и https://wiki.jasig.org/display/CAS/Home, обе в виде отдельных серверов, один из которых на Ruby. Смысла это использовать, наверное, нет. OpenID — OpenID — тоже, так как устарел и вообще больше склонен к ошибкам взаимодействия. Принцип везде по сути тот же (да если и самому написать — написать — он останется тот же), а так как OAuth2 более популярен (много готовых плагинов под разные CMS и языки) и решает более широкий спектр задач, лучше брать его, либо OpenID Connect, который является его надмножеством (с OpenID Connect-сервером можно работать как с OAuth2 сервером). Разве что для публичного сайта следует задуматься о реализации механизма (2), описанного выше.
Для SSO между разными приложениями применение OAuth2 вполне нормальное. Однако, если у вас одно приложение, поделённое на микросервисы — микросервисы — то вот для шаринга сессий между микросервисами OAuth2 юзать реально странно. так Так как по идее , наверное , просто должен быть отдельный «сервис сессий» или «сервис юзеров», логически являющий собой разделяемое между всеми компонентами приложения хранилище сессийи инкапсулирующее всю логику работы с пользователями (бизнес/не бизнес — всю), и все остальные компоненты должны в него ходить просто, без всяких Authorization URL, рефреш-токенов, консьюмеров и ти т. пп.
== Режимы OAuth2 ==
По поводу режимов OAuth2 — OAuth2 — SSO соответствует Authorization Code Flow, https://tools.ietf.org/html/rfc6749#section-1.3.1
Другие Flow:
* Client Credentials — Credentials — в приложение зашивается client id и client secret, автоматом авторизует по ним приложение без ввода пользовательских данных* Implicit — Implicit — то же самое, но без client id и client secret (типа приложение сделано на js, secret сунуть некуда, так как он всем будет виден), доступ проверяется только по обратному redirect URL’у (то . То есть типа , работает на стороне браузера и только для приложения с известным адресом).* Resource Owner Password Credentials — Credentials — это когда пароль вводится на твоём сайте, и ты прямо логин-пароль передаёшь серверу авторизации (соответственно видишь его сам)
Ну и refresh token ещё есть, но это общий принцип для упрощения проверок доступа — доступа — OAuth2 сервер всегда даёт пару токенов, access token и refresh token. В теории, если сервер сделан нормально, то прямо в самом access токене зашиты выданные привилегии («scopes») и время жизни, и ты можешь их прямо руками оттуда выдрать и проверить. Вот потом, когда время жизни токена кончается, ты должен взять refresh token и пойти к серверу, чтобы он тебе снова выдал (или не выдал) новый access token. Таким образом снимается нагрузка на сервер — сервер — клиенту больше не нужно спрашивать привилегии «на каждый чих».
В Authorization Code Flow всё просто, нужны 3 урла:
* Authorization URL — URL — на него юзера перекидываешь для авторизации;* Access Token URL — URL — там рефреш токен рефрешишь и получаешь новый access токен, когда он протух;* User Details URL — URL — там по токену получаешь параметры юзера. Вообще говоря, в OAuth2 является необязательным, но практически всегда присутствует (userinfo нужно всем!); в OpenID Connect — обязателен. Если в OAuth2 сервере отсутствует данный URL/endpoint, для проверки Token’а можно использовать Token Introspection Endpoint.
Сам клиент занимает строчек 400 на php: https://github.com/vitalif/oauth2-client/tree/master/src (достаточно AccessToken.php, AbstractProvider.php и GenericProvider.php).
 
=== Про использование Implicit в обычных приложениях ===
 
У вас есть сервер, но вы почему-то решили сделать так, что OAuth2 токены у вас получает не сервер (бэкенд), а JS фронтенд. Тот же самый JS фронтенд сохраняет токен в LocalStorage и потом вручную подставляет его во все запросы к серверу в заголовок «Authorization: Bearer …».
 
Моё мнение по данному вопросу? Вкратце — это наркомания и источник багов. Никто в здравом уме и трезвой памяти так не делает и никогда не делал.
== Keycloak ==
Дополнение. Есть такой Identity-сервер, как Keycloak. Лучше стараться его НЕ использовать, так как он достаточно кривой, сложный в отладке и плохо документированный. Пример — Пример — мы, работая с ним, прямо сейчас обнаружили баг: после протухания ОНЛАЙН-сессии юзера по ОФФЛАЙН токену keycloak перестаёт отдавать userinfo. А как токен-то валидировать? И главное не понятно, это баг keycloak или мы что-то не так делаем — документация Документация по этому поводу ничего не объясняет (, да и в целом довольно скудна). Но да; по-видимому, это всё-таки баг keycloak, т.к. token introspection endpoint в своём коде оно в userinfo пытается найти СЕССИЮ пользователя (онлайнэтом случае по оффлайн-сессию)токену тоже отдаёт неуспех. Зачем — хзДа и логически каждому активному токену должна соответствовать активная сессия — например, чтобы можно было из UI администрирования её принудительно завершить, отозвав tokenВ общем, если вам где-то требуется OAuth2, лучше постараться ограничиться более легковесными реализациями вроде плагинов к каким-либо системам/фреймворкам. [[Категория:Разработка]]

Навигация