Аутентификация =============== .. contents:: :depth: 3 Терминология ------------ * **IdP** (Identity provider) - Провайдер аутентификации, который отвечает за аутентификацию пользователей и внешних систем. В Citeck в качестве протокола для аутентификации используется OpenID Connect. В качестве стандартного IdP используется `Keycloak `_. * `OIDC (OpenID Connect) `_ - Открытый стандарт децентрализованной системы аутентификации. * **Access Token** - Токен доступа. Используется при доступе к защищенным ресурсам. Как правило имеет малое время жизни (порядка пяти минут) и регулярно обновляется с помощью токена обновления (Refresh Token). * **Refresh Token** - Токен обновления. Используется OIDC клиентом при обращении к IdP для получения нового токена доступа (Access Token). * **IdP Realm** - независимое пространство со своими настройками аутентификации для конкретного сервера. Если проводить аналогию с базами данных, то IdP - СУБД, а реалм - БД. Общая информация ---------------- В Citeck поддерживается два способа аутентификации: 1. Аутентификация через встроенный OIDC клиент 2. Аутентификация через внешний OIDC клиент Аутентификация через встроенный OIDC клиент ------------------------------------------- Логика аутентификации находится в приложении ecos-proxy-app и реализована через модуль `lua-resty-openidc `_ Настройка модуля выполняется через переменные среды контейнера ecos-proxy-app: .. list-table:: * - **Переменная** - **Значение** - **Описание** * - EIS_TARGET - | Строка вида ``host[:port]`` - | Внутренний хост IdP. Используется, чтобы определить куда нужно направить запросы | с ``http://{{SERVER_HOST}}/ecos-idp/auth/``. Этот параметр нужен только тогда, когда IdP | разворачивается в комплекте с Citeck. Для использования внешнего IdP эту настройку | следует опустить. * - ENABLE_OIDC_FULL_ACCESS - | ``true`` или ``false`` - | Включить интеграцию с IdP. Как правило здесь всегда должно стоять ``true``. * - CLIENT_ID - | Строка - | Идентификатор клиента для работы с IdP. По умолчанию ``nginx``. * - CLIENT_SECRET - | Строка - | Секрет для аутентификации OIDC клиента (ecos-proxy-app) на IdP. * - EIS_SCHEME - | ``http`` или ``https`` - | Схема для запросов от OIDC клиента (ecos-proxy-app) к IdP. По умолчанию ``https``. * - EIS_ID - | Строка вида ``host[:port]`` - | Хост для доступа к IdP от OIDC клиента и от браузера пользователя. * - EIS_LOCATION - | Строка - | Локация, по которой доступен IdP на хосте EIS_ID. По умолчанию ``auth`` * - REALM_ID - | Строка - | Идентификатор реалма, в рамках которого выполняется интеграция с IdP. * - REDIRECT_LOGOUT_URI - | URI строка - | URI для переадресации после успешного входа, который произошел после логаута. * - ENABLE_LOGGING - | ``debug`` или ``warn`` - | Включение дебага для ecos-proxy-app. При значении ``debug`` в логах пишутся все шаги | взаимодействия с IdP. Если этот параметр не задан, то все логи отправляются в ``/dev/null`` При включенной интеграции с IdP ecos-proxy-app отправляет GET запрос за информацией для работы протокола OIDC по адресу: ``EIS_SCHEME://EIS_ID/EIS_LOCATION/realms/REALM_ID/.well-known/openid-configuration`` В ответе IdP возвращает параметры, которые нужны нашему клиенту для работы по протоколу OIDC. Например: 1. Адреса для получения и обновления токенов; 2. Адрес для проверки токена пользователя; 3. Адрес для логаута; 4. Поддерживаемые алгоритмы шифрования; 5. и т.д. Алгоритм аутентификация через встроенный OIDC клиент ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. image:: _static/authentication/auth-ecos-proxy-app.png :width: 800 :align: center 1. Приходит запрос от пользователя на защищенный ресурс; 2. ecos-proxy-app создает сессию для пользователя и сохраняет там исходный запрос из п.1; 3. ecos-proxy-app отправляет ответ пользователю с установкой куки с идентификатором сессии и редиректом на IdP для входа; 4. Пользователь проходит аутентификацию на IdP через ввод логина/пароля или используя альтернативные способы для входа; 5. IdP после успешного входа редиректит пользователя на URI, который был указан в параметре redirect_uri при редиректе на п.3 и при этом добавляет в этот URI параметр с кодом, по которому ecos-proxy-app сможет запросить токены пользователя у IdP; 6. Пользователь открывает URI, который является колбэком для аутентификации (по дефолту в Citeck это ``/v2``) и попадает на ecos-proxy-app; 7. ecos-proxy-app получает код от пользователя и отправляет с ним запрос на IdP для получения Access и Refresh токенов для пользователя; 8. ecos-proxy-app получает токены пользователя от IdP; 9. ecos-proxy-app сохраняет у себя токены пользователя в его сессии; 10. ecos-proxy-app отправляет пользователю редирект на исходный URI, который он запрашивал в п.1; 11. Пользователь отправляет запрос на исходный URI из п.1; 12. ecos-proxy-app достает Access токен пользователя из сессии и отправляет запрос в IdP на проверку валидности; 13. IdP отвечает ecos-proxy-app, что токен валидный; 14. ecos-proxy-app предоставляет доступ пользователю к защищенному ресурсу и при этом добавляет в запрос хидер ``X-ECOS-User``, который равен имени пользователя; 15. Пользователь получает ожидаемый ответ от защищенного ресурса. Во всем процессе аутентификации от пользователя требуется только действия на шаге 4 (аутентификация на IdP). Все остальные пункты проходят прозрачно и незаметно для пользователя. Шаги 11-15 выполняются при каждом последующем запросе с поправкой на то, что результат проверки токена на валидность кэшируется. Время хранения кэша зависит от настоек IdP и как правило равно времени жизни токена доступа (Access Token). Аутентификация через внешний OIDC клиент ---------------------------------------- .. image:: _static/authentication/auth-ext-client.png :width: 800 :align: center 1. Клиент получает базовую конфигурацию для работы с IdP (realmId, eisId, logoutUrl) отправив GET запрос на ``{{SERVER_HOST}}/eis.json``; 2. Клиент предлагает пользователю пройти аутентификацию на IdP; 3. Клиент получает Access и Refresh токены от IdP; 4. Клиент отправляет запрос на защищенный ресурс с Access Token; 5. ecos-proxy-app валидирует Access токен отправляя запрос на IdP; 6. IdP отвечает, что токен валидный; 7. ecos-proxy-app отправляет запрос на защищенный ресурс, который нужен клиенту добавив в запрос хидер ``X-ECOS-User`` с именем пользователя; 8. Клиент получает ответ от защищенного ресурса. Во всем процессе аутентификации от пользователя требуется только действия на шаге 2 (аутентификация на IdP). Все остальные пункты проходят прозрачно и незаметно для пользователя. Клиент может отправлять токен при запросах в следующем виде: 1. В хидере Authentication в формате ``Bearer {{TOKEN}}``. 2. В куке PA Настройки /eis.json заполняются значениями из переменных среды ecos-proxy-app - REALM_ID и EIS_ID Настройка времени жизни сессий на Keycloak ------------------------------------------ Настройки на уровне реалма (действуют для всех клиентов в этом реалме по умолчанию): ``Realm Settings -> Tokens`` Настройки на уровне клиента (переопределяют настройки реалма): ``Clients -> CLIENT_ID -> Settings -> Advanced Settings`` .. list-table:: * - **Параметр** - **Описание** * - SSO Session Idle - | Время жизни сессии пользователя при неактивности. Если от пользователя | нет никакой активности в течении этого времени, то сессия прерывается. * - SSO Session Max - | Максимальное время жизни сессии пользователя. Сессия прерывается если | с момента аутентификации прошло указанное время вне зависимости от активности пользователя. * - Client Session Idle - | Время жизни сессии OIDC клиента при неактивности. Если от OIDC клиента | нет никакой активности в течении этого времени, то сессия клиента прерывается. | Если значение не задано, то по умолчанию берется значение SSO Session Idle. * - Client Session Max - | Максимальное время жизни сессии клиента. Сессия прерывается если | с момента аутентификации клиента прошло указанное время вне зависимости от активности клиента. | Если значение не задано, то по умолчанию берется значение SSO Session Max. * - Access Token Lifespan - | Время жизни Access токена. Это время жизни должно быть | небольшим (по умолчанию 5 минут) из соображений безопасности. | Токены доступа меняются автоматически и прозрачно для пользователя. Примечания: 1. Если сессия пользователя прерывается, то выданные в этой сессии Access и Refresh токены отзываются. 2. Если сессия OIDC клиента прерывается, то выданные в этой сессии Access и Refresh токены для всех пользователей отзываются. Если пользователь работает с сервером через встроенный OIDC клиент в ecos-proxy-app, то следует учитывать, что OIDC клиент кэширует результат запросов к IdP и не каждый запрос приводит к обновлению условного "таймера активности" на IdP. Активность обновляется как минимум при обновлении Access Token'а. Из особенности работы OIDC клиента с кэшем так же следует, что если мы прерываем сессию в IdP, то это не гарантирует, что пользователь сразу же потеряет доступ к серверу. Пользователь сможет отправлять запросы и получать данные от сервера до тех пор пока действует его Access Token. Touch запросы ------------- Для того, чтобы сессия пользователя неожиданно не прерывалась без явных действий пользователя, которые приводят к запросам на сервер, в ecos-ui добавлена логика с периодическй отправкой touch запроса. Задача этого запроса в проходе через механизм проверки токена пользователя и обновления условного таймера неактивности в IdP. Touch запросы отправляются периодически до тех пор пока пользователь что-то делает в системе (двигает мышкой, нажимает клавиши и т.д.). Тайминги touch запросов для версии ecos-ui 2.9.0+: * Период отправки touch запросов: 30с. * Время неактивности после которого перестают отправляться touch запросы: 1ч. В журнале конфигурации Citeck можно настроить поведение touch запросов: * Scope: **app/gateway** * Id: **touch** Содержимое настройки:: { "enabled": Boolean //включить или отключить touch запросы "uri": String // URI для touch запросов } Интеграция с внешними IdP ------------------------- Для организации аутентификации в Citeck с использованием IdP отличных от Keycloak или c Keycloak, который не поставляется вместе с Citeck мы рекомендуем использовать архитектуру: ``[Citeck <-> Keycloak] <-> External IdP`` Citeck продолжает использовать свой Keycloak для аутентификации, а внешний IdP прозрачно подключается с использованием обширных возможностей Keycloak по интеграции с внешними IdP. Такая архитектура проверена временем и является оптимальной для использования. Маппинг имени пользователя -------------------------- Если имя пользователя, которое предоставляет IdP нужно как-то модифицировать перед тем как использовать внутри Citeck, то можно использовать следующую Spring конфигурацию для микросервиса gateway:: ecos: gateway: userNameExtractors: - matcher: '^(.+?)@.*$' regexGroup: 1 В этом примере в систему попадает имя пользователя в виде email и мы используя Regexp берем только часть до символа @. Если username не попадает под matcher, то преобразование не будет выполнено.