keycloak realm что это

Краткое руководство по использованию Keycloak с пружинным загрузчиком

Узнайте, как настроить сервер блокировки ключей и использовать его с приложением Spring Boot.

1. Обзор

Дальнейшее чтение:

Весенняя безопасность и OpenID подключаются

Простой единый вход с помощью Spring Security OAuth2

CAS SSO С пружинной защитой

2. Что Такое Keycloak?

Keycloak-это решение для управления идентификацией и доступом с открытым исходным кодом, предназначенное для современных приложений и служб.

В нашем уроке мы будем использовать консоль администратора Keycloak для настройки, а затем подключения к Spring Boot с помощью клиентского адаптера Keycloak.

3. Настройка сервера блокировки ключей

3.1. Загрузка и установка Keycloak

Есть несколько дистрибутивов на выбор.

Однако в этом уроке мы будем использовать автономную версию.

Давайте скачаем дистрибутив Keycloak-11.0.2 Автономный сервер из официального источника.

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

Теперь давайте откроем браузер и посетим http://localhost:8180 . Мы будем перенаправлены на http://localhost:8180/auth для создания административного входа:

Теперь мы можем перейти к административной консоли. На странице входа в систему мы введем первоначальные учетные данные администратора:

3.2. Создание области

Успешный вход в систему приведет нас к консоли и откроет для нас область Master по умолчанию.

Здесь мы сосредоточимся на создании пользовательской области.

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

На следующем экране давайте добавим новую область под названием SpringBootKeycloak :

3.3. Создание клиента

Теперь мы перейдем на страницу клиентов. Как мы можем видеть на изображении ниже, Keycloak поставляется с клиентами, которые уже встроены :

На следующем экране для этого урока мы оставим все значения по умолчанию, кроме | Допустимых URI перенаправления поля. Это поле должно содержать URL-адреса приложений, которые будут использовать этот клиент для аутентификации :

Позже мы создадим приложение Spring Boot, работающее на порту 8081, которое будет использовать этот клиент. Поэтому мы использовали URL-адрес перенаправления http://localhost:8081/ * выше.

3.4. Создание роли и Пользователя

Доступ на основе ролей пользователя с ключом. Поэтому у каждого пользователя должна быть своя роль.

Для этого нам нужно перейти на страницу Роли :

Затем мы добавим пользователя роль:

Теперь у нас есть роль, которую можно назначить пользователям, но пользователей пока нет. Итак, давайте перейдем на страницу Пользователи и добавим одну:

Мы добавим пользователя с именем user1:

Как только пользователь будет создан, отобразится страница с его подробными сведениями:

4. Генерация токенов доступа с помощью API Keycloak

Keycloak предоставляет API REST для создания и обновления токенов доступа. Мы можем легко использовать этот API для создания вашей собственной страницы входа в систему.

Во-первых, нам нужно получить маркер доступа от Keycloak, отправив запрос POST на этот URL:

Запрос должен содержать это тело в формате x-www-форма-url-кодированный :

Маркер доступа следует использовать в каждом запросе к ресурсу, защищенному паролем, просто поместив его в заголовок Авторизация :

Как только срок действия маркера доступа истечет, мы можем обновить его, отправив запрос POST по тому же URL-адресу, что и выше, но содержащий маркер обновления вместо имени пользователя и пароля:

Keycloak ответит на это новым access_token и refresh_token.

5. Создание приложения для загрузки Spring

5.1. Зависимости

В XML-элементе зависимостей нам нужно следующее, чтобы запустить Keycloak с помощью Spring Boot:

После XML-элемента зависимостей нам нужно указать управление зависимостями для ключевого ключа:

Теперь поддерживаются следующие встроенные контейнеры, которые не требуют никаких дополнительных зависимостей при использовании Spring Boot Keycloak Starter:

5.2. Веб-страницы Thymeleaf

Мы используем Thymeleaf для наших веб-страниц.

У нас есть три страницы:

5.3. Контроллер

Веб-контроллер сопоставляет внутренние и внешние URL-адреса с соответствующими шаблонами Thymeleaf:

Обратите внимание, что мы используем клиента здесь только в качестве исходных данных для отображения, и ничего больше.

5.4. Конфигурация блокировки ключей

Вот базовая, обязательная конфигурация :

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

5.5. Демонстрация

Теперь мы готовы протестировать наше приложение. Чтобы запустить приложение Spring Boot, мы можем легко запустить его через среду разработки, такую как Spring Tool Suite (STS), или выполнить эту команду в терминале:

Мы видим, что нас перенаправили для аутентификации с помощью ключа, чтобы узнать, имеем ли мы право просматривать этот контент:

Теперь мы закончили настройку подключения Spring Boot к Keycloak и продемонстрировали, как это работает.

Как мы видим, весь процесс вызова сервера авторизации Keycloak был легко обработан Spring Boot для нас. Нам не нужно было вызывать API Keycloak, чтобы самостоятельно генерировать маркер доступа, или даже отправлять заголовок авторизации явно в нашем запросе на защищенные ресурсы.

Далее мы рассмотрим, как использовать Spring Security в сочетании с нашим существующим приложением.

6. Весенняя Безопасность

6.1. Зависимость

Чтобы использовать Spring Security с Spring Boot, мы должны добавить эту зависимость:

6.2. Класс конфигурации

Брелок обеспечивает Адаптер_конфигурации ключей безопасности в качестве удобного базового класса для создания WebSecurityConfigurer пример.

Это полезно, поскольку для любого приложения, защищенного Spring Security, требуется класс конфигурации, расширяющий WebSecurityConfigurerAdapter:

Другой метод, распознаватель конфигурации keycloak определяет, что мы хотим использовать поддержку файла свойств загрузки Spring вместо keycloak.json по умолчанию.

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

Теперь, после аутентификации, мы сможем получить доступ к странице внутренних клиентов, как и раньше.

7. Заключение

В этом руководстве мы настроили сервер блокировки ключей и использовали его с приложением Spring Boot.

Источник

Расширение Keycloak для перехвата и обработки событий в системе

Продолжаю тему моего коллеги о Keycloak.

Кому не нужна вода, а просто пример кода, прыгайте сразу сюда.

Читайте также:  digital crown в apple watch что значит повернуть

Keycloak довольно часто используется в качестве решения для управления идентификацией и доступом для современных приложений в рамках enterprise приложений.

Keycloak написан на языке Java, и создатели изначально заложили очень удобную возможность расширять функционал готового решения так называемыми аддонами или официально: extensions.

Расширение представляет собой обычный проект на Java, состоящий из классов, расширяющих дефолтные классы/интерфейсы Keycloak с необходим дополнительным функционалом. Причём расширить можно функционал чуть ли не любого класса Keycloak и для любых целей: от минимального изменения текста сообщения о некорректном вводе пользователем пароля, до привязки Discord‘а, как Identity provider‘а.

В данной статье речь пойдёт о расширении дефолтного слушателя событий в Keycloak.

Краткая предыстория: была поставлена задача отслеживания события сброса пароля у админа для логирования события и актуализации данных об этом админе в системе.

Исходный код

Необходимо создать обычный Java проект и подрубить несколько библиотек. Для удобства был использован сборщик Maven. Необходимые библиотеки представлены в pom.xml файле ниже:

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

Теперь необходимо создать реализацию необходимых нам интерфейсов, а именно двух:

EventListenerProvider . Дефолтный интерфейс провайдера для перехвата всех событий в системе. Реализация будет содержать саму логику нашего расширения.

EventListenerProvider

Создадим реализацию EventListenerProvider :

У данного интерфейса необходимо определить три метода:

onEvent метод, перехватывающий обычные события в системе, такие как событие неправильного ввода пароля, удачной авторизации, логаута. В аргументе приходит сам экземпляр события со всей необходимой информацией: тип события, id пользователя и сессии, IP пользователя и т. д.

onAdminEvent перехватывает «админские» события, например: событие сброса пароля пользователя через админскую консоль Keycloak.

close своего рода деструктор, вызывается при удалении текущего провайдера.

EventListenerProviderFactory

Второй и последний обязательный необходимый нам класс имплементирует EventListenerProviderFactory :

Тут уже методов побольше, посмотрим, за что они отвечают:

init срабатывает только один раз при первом создании фабрики.

postInit вызывается один раз после инициализации всех фабрик провайдеров в системе.

close выполняется при завершении работы Keycloak сервера.

getId устанавливает название нашего расширения при создании фабрики.

Это все необходимые классы. Добавим ещё один класс, вспомогательный, только для того, чтобы отобразить Event и AdminEvent в текстовом виде со всеми их полями в консоли:

Осталось указать только путь к нашей фабрике CustomEventListenerProviderFactory для Keycloak.

И в данный файл поместить строку:

То есть указываем полный путь до класса нашей кастомной фабрики. Только так Keycloak сможет заменить дефолтную фабрику с дефолтным обработчиком событий на нашу. На этом с кодом всё.

Сборка проекта

Так выглядит полный проект

Запуск расширения

Установку и запуск Keycloak я здесь рассматривать не буду, на эту тему есть исчерпывающие статьи. Например, на официальном сайте. Будем считать, что у нас уже стоит работающий keycloak.

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

Сообщения о начале, а затем и об успешном деплое в консоли Keycloak выглядят примерно так:

Но это ещё не всё. Теперь нам необходимо определить наш плагин как слушатель событий в конфиге Keycloak. Это делается в админской консоли на вкладке Events → Config:

Если деплой расширения произошёл успешно, в выпадающем меню поля Event Listeners появится наш плагин.

Необходимо выбрать наш плагин и нажать Save.

Проверка работы

Попробуем залогинится каким-нибудь пользователем. В консоли появляется следующая запись:

Разлогинимся этим же пользователем:

Попробуем залогиниться с некорректным паролем:

Сбросим пароль пользователю через админскую консоль ( AdminEvent ):

Заключение

В данной статье описано только минимальное расширение для отлавливания событий в Keycloak, вы же можете делать с ними всё, что вам необходимо. В моём случае необходимо было отлавливать только события сброса пароля юзеру через админскую консоль, и отправлять логин этого юзера в микросервис через REST запрос. С рабочими исходниками этого проекта можете ознакомиться тут.

Кстати, у меня так же была задача на отслеживание события в Keycloak о том, что пользователь сделал максимальное количество неверных попыток ввода пароля, и его временно заблокировали (Keycloak предлагает такой функционал из коробки, называется brute force detection).

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

Источник

тут блог

Общественные обязательства интроверта.
Сообщения на ИТ тематику, но не обязательно.

О Keycloak

Есть такая штука. Называется Keycloak. Это не то, что вы подумали, а плащ или мантия, типа для ключей, или «ключевая мантия». Это сервер для Single-Sing-On (SSO), и для хранения учётных записей, и для всего такого, связанного с аутентификацией и авторизацией. Это — часть JBoss, который, оказывается, теперь называется WildFly, сервера приложений (Java EE) от RedHat. Кажется, это самый популярный среди свободных сервер SSO. Потому что на нас одновременно свалилось аж два с половиной проекта, где для авторизации юзеров используется именно Keycloak.

Keycloak умеет OpenID Connect (aka OIDC) и SAML (aka Security Assertion Markup Language).

SAML — это привет из начала двухтысячных на считающимся ныне монструозным XML. Близкий друг действительно монструозного SOAP. Но теперь строить API на XML не модно. Поэтому забудем про SAML.

OpenID Connect будет поинтереснее. Он не имеет ничего общего с протоколами OpenID версий 1.1 и 2.0. Точнее, если верить Википедии, это следующая версия OpenID. И построено оно поверх OAuth 2.0.

OpenID Connect — это конкретный протокол аутентификации, построенный поверх фреймворка авторизации OAuth 2.0.

Помните, OAuth 2.0 — это лишь фреймворк. Там не прописано чётко, какими должны быть токены, как именно их получать, и прочие мелкие детали. Вот OpenID Connect эти детали конкретизирует. И у нас даже есть конкретная реализация: Keycloak.

Читайте также:  психосоматика какая часть тела за что отвечает

Keycloak сервер — весь такой multitenancy. На нём положено создавать Realms — независимые пространства со своими юзерами, группами, ролями, ключами, страницами авторизации и клиентами. Клиентами (clients) в смысле OAuth, со своим ClientID и Redirect URI.

Если у нас есть Realm и мы знаем, где находится Keycloak, можно попробовать поавторизоваться. Есть у нас чётко определённый набор Endpointов, с которых можно начать. И их список тоже можно получить.

Как положено в OAuth, попробуем получить токен.

В ответ нам выдадут форму логина, которая ставит кучку куки. В общем, логично.

В ответ будет подобная же форма логина.

Ну типа почти обычный OAuth 2.0. Только нам точно известно, куда ходить за логином, где получать токен, где спрашивать сведения о пользователе.

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

В OpenID Connect, как положено, имеется Access Token, который нужно включать в заголовок Authorization, чтобы получить те же сведения о пользователе, и Refresh Token, который нужен для обновления Access Token. А ещё есть ID Token.

Именно ID Token является JWT токеном, который можно проверить публичным RSA ключом. И именно там содержатся некоторые сведения о пользователе. Можно не делать дополнительных запросов на Keycloak, а сразу извлечь всё, что надо, из ID Token.

На самом деле, все эти curlы вам не понадобятся. Ибо политикой Keycloak является использование адаптеров. То есть библиотек для ваших любимых языков программирования или middleware для ваших любимых веб фреймворков. Берёте нужный адаптер, настраиваете его JSON файлом, который можно скачать прямо в настройках клиента в админке Keycloak, и пользуетесь.

Если адаптера для Keycloak не нашлось, вполне может сгодиться адаптер для просто OpenID Connect. Их много, для разных языков (например, для Go).

Если у вас, допустим, есть какой-то UI на React, то вам достаточно подключить адаптер, и позаботиться о логине в нужный момент, и обновлении токенов, например, по таймеру.

Потом этот токен из Keycloak можно вставлять в заголовки запросов к API. А API уже будет проверять валидность этого токена.

Если взять адаптер для Spring Boot, то достаточно его подключить:

И всё. Эта магия работает.

Не нравится мне, когда такие довольно сложные для понимания штуки, как всякие токены, где, чтобы разобраться во всём, нужно нарисовать не одну диаграмму последовательностей, полностью закрываются очень простым фасадом. А если что-нибудь сломается, как выяснять, в чём проблема?

Источник

Прикручиваем ActiveDirectory авторизацию к Kubernetes c помощью Keycloak

Данная статья написана с целью расширить уже существующую, но рассказывает про особенности связки именно с Microsoft ActiveDirectory, а так же дополняет ее.

В этой статье я расскажу как установить и настроить:

Как работают права в Kubernetes.

Управлять правами пользователя/групп мы можем с помощью RBAC, об этом создано уже кучу статей, не буду подробно на этом останавливаться. Проблема в том что вы можете используя RBAC для того что бы ограничить права пользователя, но Kubernetes не чего не знает о пользователях. Получается что нужен механизм доставки пользователя в Kubernetes. Для этого мы добавим в Kubernetes OpenID провайдера который и будет говорить о том что такой пользователь действительно существует, а права ему уже выдаст сам Kubernetes.

После того как вы получите/выпишите сертификаты, клиентский надо добавить в Kubernetes, для этого создаем для него secret:

Далее мы будет его использовать для нашего Ingress контроллера

Установка Keycloak

Я решил что проще всего использовать готовые решения для этого, а именно helm chart-ы.

Устанавливаем репозиторий и обновляем его:

Создаем файл keycloak.yml cо следующим содержимым:

Настройка федерации

Далее заходим в веб интерфейс keycloak.example.org

В левом углу нажимаем Add realm

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


Если все хорошо, то после нажатия кнопки Synchronize all users вы увидите сообщение об успешном импорте пользователей.

Далее надо замапить наши группы

Настройка клиента

Надо создать клиента, в понятиях Keycloak это приложение которое будет у него авторизовываться. Важные пункты выделю на скриншоте красным.

Создадим scope для групп:

И настроим mapper для них:

Добавляем маппинг наших групп в Default Client Scopes:

Получаем secret(и записываем его куда нить) который мы будем использовать для авторизации в Keycloak:

Настройка Kubernetes

Нам надо указать где лежит наш корневой сертификат от сайта, и где находиться провайдер OIDC.
Для этого редактируем файл /etc/kubernetes/manifests/kube-apiserver.yaml

Обновляем kubeadm конфиг в кластере:

Настройка auth-proxy

Для защиты вашего веб приложение можно использовать keycloak gatekeeper. Помимо того что данный реверс прокси будет авторизировать пользователя перед тем как показать страницу, дак еще и передавать конечному приложению информацию о вас в заголовках. Тем самым если ваше приложение поддерживает OpenID, то пользователь сразу авторизуется. Рассмотрим на примере Kubernetes Dashboard

Установка Kubernetes Dashboard

Настройка прав доступа:

Создадим ClusterRoleBinding который будет давать права админа кластера(стандартная ClusterRole cluster-admin) для пользователей состоящих в группе DataOPS.

Установка keycloak gatekeeper:

После этого при попытке зайти на kubernetes-dashboard.example.org, произойдет перенаправление на Keycloak и в случае удачной авторизации мы попадем в Dashboard уже залогиненным.

Установка gangway

Для удобства можно добавить gangway который будет генерировать файл конфига для kubectl, с помощью которого мы уже под нашим пользователем попадем в Kubernetes.

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

Источник

Настраиваем отказоустойчивый Keycloak с Infinispan в Kubernetes

В этой статье мы поделимся опытом развертывания в кластере Kubernetes устойчивой и масштабируемой инсталляции популярного решения для обеспечения «единого входа» (SSO) — Keycloak в связке с Infinispan (для кэширования пользовательских метаданных).

Читайте также:  isotonic что это такое

Keycloak и область применения

Keycloak – проект с открытым исходным кодом компании Red Hat, предназначенный для управления аутентификацией и авторизацией в приложениях, функционирующих на серверах приложений WildFly, JBoss EAP, JBoss AS и прочих web-серверах. Keycloak упрощает реализацию защиты приложений, предоставляя им бэкенд авторизации практически без дополнительного кода. За подробной информацией о том, как это осуществляется, можно обратиться к этому руководству.

Как правило, Keycloak устанавливается на отдельный виртуальный или выделенный сервер приложений WildFly. Пользователи однократно аутентифицируются с помощью Keycloak для всех приложений, интегрированных с данным решением. Таким образом, после входа в Keycloak пользователям не нужно снова входить в систему для доступа к другому приложению. Аналогично происходит и с выходом.

Для хранения своих данных Keycloak поддерживает работу с рядом наиболее популярных реляционных систем управления базами данных (РСУБД): Oracle, MS SQL, MySQL, PostgreSQL. В нашем случае использовалась CockroachDB — современная распределенная СУБД (изначально Open Source, а впоследствии — под BSL), которая обеспечивает согласованность данных, масштабируемость и устойчивость к авариям. Одной из её приятных особенностей является совместимость с PostgreSQL на уровне протокола.

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

Infinispan

Infinispan — это масштабируемая, высокодоступная платформа для хранения данных типа ключ-значение, написанная на Java и распространяемая под свободной лицензией (Apache License 2.0). Основная область применения Infinispan — распределенный кэш, но также её применяют как KV-хранилище в базах данных типа NoSQL.

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

KC в конфигурации по умолчанию использует встроенный кэш Infinispan. Он позволяет настраивать распределенные кэши, чтобы репликация и перекаты данных осуществлялись без простоя. Таким образом, даже если мы полностью отключим сам KC, а потом поднимем его обратно, авторизованных пользователей это не затронет.

Сам IS хранит всё в памяти, а на случай переполнения (или полного отключения IS) можно настроить сбрасывание его данных в БД. В нашем случае эту функцию выполняет CockroachDB.

Постановка задачи

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

Обеспечить надежность/устойчивость к авариям, высокую доступность.

Сохранить пользовательские данные (сессии, токены) при потенциальном переполнении памяти.

Описание инфраструктуры и архитектуры решения

Изначально KC был запущен в 1 реплике и настройками кэширования по умолчанию, т.е. использовался встроенный Infinispan, который все держал в памяти. Источником данных был кластер CockroachDB.

Для обеспечения надежности потребовалось развернуть несколько реплик KC. Keycloak позволяет это сделать, используя несколько механизмов автообнаружения. В первой итерации мы сделали 3 реплики KC, использующих IS в качестве модуля/плагина:

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

Поэтому на следующей итерации мы развернули отдельный кластер Infinispan и отключили встроенный модуль IS в настройках Keycloak:

Решение было развернуто в кластере Kubernetes. Keycloak и Infinispan запущены в одном namespace по 3 реплики. За основу для такой инсталляции был взят этот Helm-чарт. CockroachDB разворачивалась в отдельном пространстве имен и использовалась совместно с другими компонентами клиентского приложения.

Практическая реализация

Полные примеры Helm-шаблонов доступны в нашем репозитории flant/examples.

1. Keycloak

КС поддерживает несколько режимов запуска: standalone, standalone-ha, domain cluster, DC replication. Режим standalone-ha является идеальным вариантом для запуска в Kubernetes, потому что легко добавлять/удалять реплики, общий конфиг-файл хранится в ConfigMap, правильно выбранная стратегия развертывания обеспечивает доступность узлов при обновлении ПО.

Для настройки KC используются:

переменные окружения, которые задают режимы работы KC (standalone, standalone-ha и т.д.);

По умолчанию KC запускается со standalone.xml — этот конфиг сильно отличается от HA-версии. Для получения нужной нам конфигурации добавим в values.yaml :

После получения файла переменные JGROUPS_DISCOVERY_PROTOCOL и JGROUPS_DISCOVERY_PROPERTIES можно переименовать или удалить, чтобы KC не пытался создавать этот файл при каждом повторном деплое.

Для корректной работы DNS_PING указываем:

Настройки JGROUPS и DNS_PING :

Наконец, подключаем внешний Infinispan:

2. Infinispan

Настройка Infinispan гораздо легче, чем KC, поскольку шаги с генерацией нужного конфиг-файла отсутствуют.

… и добавляем секцию jgroups в XML-конфиг:

Для корректной работы Infinispan c CockroachDB нам пришлось пересобрать образ Infinispan, добавив в него новую версию SQL-драйвера PostgreSQL. Для сборки использовалась утилита werf с таким простым werf.yaml :

Добавим в XML-конфиг секцию :

В Infinispan мы должны описать те кэши, которые в KC были созданы с типом distributed-cache. Например, offlineSessions :

Таким же образом настраиваем и остальные кэши.

Подключение XML-конфига происходит аналогично тому, что мы рассматривали Keycloak.

На этом настройка Keycloak и Infinispan закончена. Повторюсь, что полные листинги доступны на GitHub: flant/examples.

Заключение

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

С момента сдачи данной работы клиенту прошло 2 месяца. Каких-либо жалоб и недостатков за этот период не выявлено. Поэтому можно считать, что поставленные цели достигнуты: мы получили устойчивое, масштабируемое решение для обеспечения SSO.

Источник

Сказочный портал