Продолжаю тему моего коллеги о Keycloak.  Кому не нужна вода, а просто пример кода, прыгайте сразу сюда. Keycloak довольно часто используется в качестве решения для управления идентификацией и доступом для современных приложений в рамках enterprise приложений. Keycloak написан на языке Java, и создатели изначально заложили очень удобную возможность расширять функционал готового решения так называемыми аддонами или официально: extensions. Расширение представляет собой обычный проект на Java, состоящий из классов, расширяющих дефолтные классы/интерфейсы Keycloak с необходим дополнительным функционалом. Причём расширить можно функционал чуть ли не любого класса Keycloak и для любых целей: от минимального изменения текста сообщения о некорректном вводе пользователем пароля, до привязки Discord'а, как Identity provider'а. В данной статье речь пойдёт о расширении дефолтного слушателя событий в Keycloak. Краткая предыстория: была поставлена задача отслеживания события сброса пароля у админа для логирования события и актуализации данных об этом админе в системе. Необходимо создать обычный Java проект и подрубить несколько библиотек. Для удобства был использован сборщик Maven. Необходимые библиотеки представлены в pom.xml файле ниже: Из необязательных зависимостей здесь только Lombok. В моём проекте он нужен для удобного логирования событий в консоли и парочки конструкторов. Теперь необходимо создать реализацию необходимых нам интерфейсов, а именно двух: EventListenerProvider. Дефолтный интерфейс провайдера для перехвата всех событий в системе. Реализация будет содержать саму логику нашего расширения. EventListenerProviderFactory. Интерфейс фабрики для инициализации экземпляров провайдера EventListenerProvider. При каждом новом событии в системе фабрика создаёт новый экземпляр провайдера EventListenerProvider, и как только провайдер выполнит свою работу - удаляется из памяти. Сама же фабрика создаётся одна и работает на протяжении всего жизненного цикла Keycloak. Создадим реализацию EventListenerProvider:   У данного интерфейса необходимо определить три метода: onEvent метод, перехватывающий обычные события в системе, такие как событие неправильного ввода пароля, удачной авторизации, логаута. В аргументе приходит сам экземпляр события со всей необходимой информацией: тип события, id пользователя и сессии, IP пользователя и т. д. onAdminEvent перехватывает "админские" события, например: событие сброса пароля пользователя через админскую консоль Keycloak. close своего рода деструктор, вызывается при удалении текущего провайдера. Перевод объектов событий в текстовый вид я решил вынести в отдельный класс EventUtils, который представлен ниже. Второй и последний обязательный необходимый нам класс имплементирует EventListenerProviderFactory:  Тут уже методов побольше, посмотрим, за что они отвечают: create будет возвращать наш кастомный провайдер CustomEventListenerProvider. Вызывается при каждом новом событии в системе. Сама же фабрика CustomEventListenerProviderFactory создаётся один раз на протяжении работы Keycloak. init срабатывает только один раз при первом создании фабрики. postInit вызывается один раз после инициализации всех фабрик провайдеров в системе. close выполняется при завершении работы Keycloak сервера. getId устанавливает название нашего расширения при создании фабрики. Это все необходимые классы. Добавим ещё один класс, вспомогательный, только для того, чтобы отобразить Event и AdminEvent в текстовом виде со всеми их полями в консоли: Осталось указать только путь к нашей фабрике CustomEventListenerProviderFactory для Keycloak. Для этого необходимо создать файл с названием org.keycloak.events.EventListenerProviderFactory по пути src/main/resources/META-INF/services/. Отсутствующие в проекте директории необходимо создать. И в данный файл поместить строку: То есть указываем полный путь до класса нашей кастомной фабрики. Только так Keycloak сможет заменить дефолтную фабрику с дефолтным обработчиком событий на нашу. На этом с кодом всё. Теперь необходимо собрать получившееся расширение в JAR файл. Если вы используете Maven, то после сборки, в папке target появится два JAR файла. Нам нужен тот, что без -sources. В нашем случае это keycloak-logging-plugin.jar. Собрать его можно с помощью команды: Установку и запуск Keycloak я здесь рассматривать не буду, на эту тему есть исчерпывающие статьи. Например, на официальном сайте. Будем считать, что у нас уже стоит работающий keycloak. Собранный JAR файл keycloak-logging-plugin.jar необходимо поместить в папку с Keycloak по пути <ДИРЕКТОРИЯ_KEYCLOAK>/standalone/deployments/, причём нет необходимости перезапускать Keycloak после деплоя. Да, keycloak поддерживает hot swap или замену файлов "на ходу". Как только наш JAR файл окажется в директории, keycloak его задеплоит и будет готов к работе. Даже если вы потом будете заменять уже находящийся там файл точно таким же, он всё равно задеплоится заново. Сообщения о начале, а затем и об успешном деплое в консоли Keycloak выглядят примерно так: А в директории рядом с нашим JAR файлом появился такой же с приставкой .deployed. Но это ещё не всё. Теперь нам необходимо определить наш плагин как слушатель событий в конфиге Keycloak. Это делается в админской консоли на вкладке Events → Config: Необходимо выбрать наш плагин и нажать Save. Попробуем залогинится каким-нибудь пользователем. В консоли появляется следующая запись: Разлогинимся этим же пользователем: Попробуем залогиниться с некорректным паролем:  Сбросим пароль пользователю через админскую консоль (AdminEvent): В данной статье описано только минимальное расширение для отлавливания событий в Keycloak, вы же можете делать с ними всё, что вам необходимо. В моём случае необходимо было отлавливать только события сброса пароля юзеру через админскую консоль, и отправлять логин этого юзера в микросервис через REST запрос. С рабочими исходниками этого проекта можете ознакомиться тут. Кстати, у меня так же была задача на отслеживание события в Keycloak о том, что пользователь сделал максимальное количество неверных попыток ввода пароля, и его временно заблокировали (Keycloak предлагает такой функционал из коробки, называется brute force detection). Но, либо из соображений безопасности, либо просто из-за того, что фича никому не нужна, такое событие в Keycloak в принципе отсутствует. Только если вручную считать для каждого пользователя количество событий неправильного ввода пароля за промежуток времени, указанные в конфигурации Keycloak, можно такое событие отследить. Но есть подозрения, что из-за отличной гибкости расширений, можно написать свою кастомную реализацию интерфейса BruteForceProtector, дефолтная реализация которого отвечает за временную блокировку при неправильных попытках ввода пароля, и добавить такое событие. Пока все попытки не увенчались успехом, но автор не опускает руки, так что, возможно, скоро будут новости по этому поводу. java developer