Кастомизация Keycloak с использованием SPI

Кастомизация Keycloak с использованием SPI

1. Введение

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

Особенно hospital системы требуют гораздо более строгих стандартов безопасности, чем обычные услуги.

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

На начальном этапе мы также рассматривали возможность разработки собственной системы аутентификации.

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

Поскольку необходимо было надежно поддерживать современные стандарты аутентификации, такие как OAuth2, OpenID Connect и SSO, было решено использовать проверенное решение для аутентификации.

Выбранным решением в этом процессе стал Keycloak.

Keycloak — это основанное на Red Hat решение для управления учетными записями и доступом (IAM), которое изначально поддерживает такие протоколы, как OAuth2, OpenID Connect и SAML.

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

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

Особенно в проекте существовали сложные требования, а не только простая аутентификация пользователей.

- Структура прав, основанная на многопользовательской архитектуре
- Разделение пользователей по больницам
− детализированный RBAC (контроль доступа на основе ролей)
− валидация пользователей на основе данных внешних больниц
- Процедура проверки личности в реальном времени
- Интеграция бизнес-логики внутренних служб

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

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

Особенно из-за специфики больничного проекта никто не мог зарегистрироваться как пользователь.

Поскольку доступ должен был быть разрешен только подтвержденным пациентам или сотрудникам данной больницы.

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

Для решения этих требований потребовалось расширить саму внутреннюю аутентификационную цепочку Keycloak, и в конечном итоге была внедрена структура кастомизации с использованием SPI (интерфейс поставщика услуг).

Что такое SPI (Интерфейс поставщика услуг)

SPI (Интерфейс поставщика услуг) - это структура интерфейса, разработанная для расширения функциональности фреймворка извне.

Обычно используемый API (интерфейс программирования приложений) близок к интерфейсу, который позволяет разработчику вызывать функции внешних систем.

С другой стороны, SPI имеет противоположную концепцию.

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

Таким образом, SPI можно считать близким к “структуре плагина для расширения”.

Keycloak спроектирован вокруг этой архитектуры на основе SPI.

Таким образом, разработчики могут свободно расширять процесс аутентификации, не изменяя непосредственно исходный код ядра Keycloak.

Например, такие функции можно расширить в форме SPI.

- Хранилище пользователей (User Storage)
- аутентификация (Authentication)
- слушатель событий (Event Listener)
- Протокол сопоставления (Protocol Mapper)
- Политика паролей (Password Policy)
- Поток регистрации пользователей

В проекте особенно использовался Authentication SPI. Метод реализации относительно ясен.

После реализации пользовательского класса в соответствии с интерфейсом, предоставляемым Keycloak, его нужно собрать в виде JAR-файла и развернуть на сервере Keycloak.

После этого, когда сервер Keycloak запускается, он автоматически сканирует реализации SPI и распознает их как новые модули аутентификации.

То есть, логика, созданная разработчиком, будет работать как стандартная функция Keycloak.

Главное преимущество этой структуры заключается в том, что она не требует изменения внутренностей движка.

Итак, даже при обновлении версии Keycloak возможно разделение кода кастомизации и кода движка.

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

Механизм потока аутентификации (Authentication Flow)

Система аутентификации Keycloak работает на основе структурированной последовательности, называемой Authentication Flow.

Когда пользователь выполняет вход в систему или регистрацию, Keycloak последовательно выполняет заранее определенные этапы аутентификации.

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

- Ввод информации пользователя
- Проверка пароля
- OTP аутентификация
- Дополнительная процедура аутентификации
- Выдача токенов

Каждый этап управляется как единица под названием Execution.

В проекте реализована вставка этапа пользовательской проверки в середине данного потока аутентификации.

Сначала был реализован класс аутентификации на основе SPI и собран в формате JAR для развертывания на сервере Keycloak.

После развертывания администраторская консоль распознала эту пользовательскую логику как новое выполнение аутентификации.

Затем я смог напрямую вставить ее в существующий поток аутентификации на экране администратора.

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

Когда фактический пользователь пытается войти в систему или зарегистрироваться, Keycloak выполняет каждый шаг аутентификации в установленном порядке. И когда вызывается пользовательский шаг, передается объект AuthenticationFlowContext. Этот объект был очень важным инструментом, позволяющим контролировать все состояние процесса аутентификации.

В проекте были выполнены следующие действия с использованием AuthenticationFlowContext:

- Получение входных данных пользователя
- Интеграция с базой данных больницы
- Проверка информации о пациенте
- Проверка информации о сотрудниках
- Проверка прав арендатора
- Обработка успеха/неудачи аутентификации

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

При успешной проверке вызывается context.success(), чтобы перейти к следующему этапу аутентификации, а при неудаче возвращается сообщение об ошибке, чтобы остановить аутентификацию.

Такая структура позволила гибко вставлять специализированную бизнес-логику проекта, сохраняя при этом основной поток аутентификации Keycloak.

4. Техническая проблема: Проблема согласованности данных в распределенной среде

Одной из самых сложных проблем в процессе реализации была согласованность данных в распределенной среде.

Особенно необходимо было безопасно хранить значение DI (Duplication Information), используемое в процессе идентификации пользователей больницы, между несколькими этапами аутентификации.

Изначально мы планировали использовать функцию AuthNote, предоставляемую внутри Keycloak.

AuthNote является временным хранилищем для обмена данными между этапами в рамках сеанса аутентификации.

В односерверной среде он работал относительно стабильно. Однако реальная эксплуатационная среда имела многосерверную кластерную структуру.

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

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

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

- Потеря данных AuthNote
- Несоответствие целостности сессии
- Инициализация состояния аутентификации
- Не удалось получить значение DI
- Прерывание аутентификации пользователя

Сначала мы рассматривали способ хранения на основе куки браузера.

Мы также протестировали изменения настроек сессии Keycloak и структуру Sticky Session.

Однако такие методы оказались структурно неполными решениями.

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

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

Для решения этой проблемы мы решили использовать внутреннюю кэш-структуру Keycloak.

5. Решение проблем: Дизайн распределенного кеша на основе Infinispan

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

Infinispan является основанным на Java открытым решением для распределенной in-memory сетки данных (Data Grid).

Интересно, что сам Keycloak уже использует Infinispan внутренне.

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

Это дало преимущество, значительно уменьшающее сложность системы.

В проекте была реализована пользовательская структура доступа к кэшу с использованием KeycloakSession и InfinispanConnectionProvider.

Процесс реализации делится на три основных этапа.

Первый пункт - это получение экземпляра кэша.

Мы создали отдельное кэш-пространство для хранения пользовательских данных, обратившись к Cache Manager, управляемому Keycloak.

Вторым было хранение данных на основе значения состояния (State Key).

При запуске процесса аутентификации было создано уникальное значение состояния (State Key), которое использовалось в качестве ключа.

Итак, мы сохранили необходимые значения DI в качестве Value в процессе сертификации больницы.

Таким образом, в процессе сертификации вместо передачи реальных значений DI передаем только значения состояния (State Key).

Третьим параметром была настройка TTL (время жизни).

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

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

Благодаря этой структуре пользователь смог безопасно восстановить значение DI только с помощью статуса (State Key), когда он вернулся в Keycloak после внешней аутентификации.

Самым важным моментом было то, что данные могли надежно обмениваться даже в распределенной серверной среде.

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

В результате мы смогли обеспечить высокий уровень надежности аутентификации и целостности данных, требуемый в проекте больницы, благодаря архитектуре на основе Infinispan.

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

Настройка Keycloak SPI оказалась опытом, который вышел за рамки разработки простых плагинов.

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

Особенно такие области, как Authentication Flow, AuthenticationFlowContext, структура SPI, архитектура кеша Infinispan, были трудными для понимания только на основе простых настроек.

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

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

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

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

В этом процессе нам удалось глубже задуматься не только о реализации простых функций, но и о системном дизайне, согласованности данных и стабильности аутентификации.

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

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

джошуа

Site footer