Рубрики
Без рубрики

Создание SPI (плагина) прослушивателя событий для KeyCloak

В этом блоге я расскажу о том, как создать плагин для прослушивания событий (называемый SPI) для KeyCloak S… С пометкой java, keycloak, computer science.

В этом блоге я расскажу о том, как создать плагин прослушивателя событий (называемый SPI) для KeyCloak

Итак, что такое Keycloak ?

Keycloak – это платформа управления идентификацией и доступом с открытым исходным кодом, созданная Red Hat . Он предоставляет множество дополнительных функций, таких как единый вход, социальная аутентификация, поддержка нескольких протоколов аутентификации и т.д. Подробнее читайте здесь: https://www.keycloak.org/

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

Во время моей стажировки этим летом нам нужно было регистрировать все события пользователей (и администраторов), происходящие в KeyCloak, и отправлять их во внешние системы для анализа. Это необходимо во многих ситуациях. (один из примеров – если вы используете внешний SIEM/| для регистрации и анализа инцидентов) .

По умолчанию журналы KeyCloak не содержат событий пользователя/администратора. И даже если мы включим это, было бы трудно создать внешнюю систему, которая отслеживает и анализирует журналы для извлечения необходимых событий. Вместо этого мы можем создать плагин для KeyCloak, чтобы подключаться к системе и делать “что-то” всякий раз, когда происходит событие (В нашем случае, запуск внешних вызовов API)

Итак, давайте построим один из них:)

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

adwait-что они/keycloak-событие-прослушиватель-spi

Пример SPI прослушивателя событий для keycloak

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

Итак, давайте получим pom.xml сначала разобрались.

(Если вы не знакомы с Maven, мы используем pom.xml файл в Maven, чтобы перечислить все детали проекта, включая все зависимости)

(если приведенная выше суть не видна, вы можете найти файл здесь

В pom.xml , мы определяем родительские данные, имя проекта Образец прослушивателя событий ), версию, идентификатор артефакта (здесь sample_event_listener ), зависимости

Следующим шагом является внедрение SPI. Для этого нам нужно реализовать 2 класса. Поставщик и ProviderFactory

итак, давайте создадим наш пакет в src/main/java . Здесь имя пакета com.coderbuddy.sample event listener provider.provider coder dude : потому что мой псевдоним разработчика coderdude:D sampleeventlistenerprovider : Может быть короче, но давайте оставим это как есть provider : Последний поставщик существует, потому что потенциально могут быть другие модули, которые вы используете в своем поставщике.

Теперь этот пакет будет содержать 2 рассмотренных выше класса. Класс Provider содержит фактическую логику плагина. ProviderFactory – это оболочка, которая инициализирует поставщика. Разница важна .

  • Factory инициализируется только при запуске KeyCloak. Новый экземпляр Provider создается Factory каждый раз, когда требуется. (В нашем случае каждый раз, когда происходит событие)
  • Будет существовать только 1 экземпляр Factory . Несколько поставщиков могут существовать одновременно (скажем, 2 события происходят одновременно).
  • Поставщики уничтожаются, как только они выполняют свои задачи. Фабрика существует до тех пор, пока работает KeyCloak.
  • Любая ошибка на заводе приведет к сбою KeyCloak. Ошибка в провайдере просто перейдет в журналы, а остальная часть Keycloak будет функционировать нормально

Итак, давайте начнем с создания Поставщика. Имя класса будет Sample Event Listener Provider , который реализует Поставщик прослушивателя событий интерфейс (Этот интерфейс предоставляется KeyCloak)

package com.coderdude.sampleeventlistenerprovider.provider;

import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.admin.AdminEvent;

import java.util.Map;


public class SampleEventListenerProvider implements EventListenerProvider {

    public SampleEventListenerProvider() {
    }


}

Сохраните эти импортные данные пока. Они нам понадобятся. Итак, здесь мы просто собираемся распечатать все события на консоль. Все события предоставляются 2 классами: org.keycloak.events. Событие и org.keycloak.events.admin. Событие администратора Обычные события происходят всякий раз, когда обычный пользователь что-то делает. События администратора происходят, когда администраторы что-то делают. Нам нужно написать соответствующие методы для преобразования этих объектов класса в читаемые строки. Вот метод построения строки для события

Мы фиксируем все параметры, ошибки и детали. (отсюда и карта, потому что детали – это массив)

private String toString(Event event) {

        StringBuilder sb = new StringBuilder();


        sb.append();

        sb.append(event.getType());

        sb.append(", realmId=");

        sb.append(event.getRealmId());

        sb.append(", clientId=");

        sb.append(event.getClientId());

        sb.append(", userId=");

        sb.append(event.getUserId());

        sb.append(", ipAddress=");

        sb.append(event.getIpAddress());


        if (event.getError() != null) {

            sb.append(", error=");

            sb.append(event.getError());

        }


        if (event.getDetails() != null) {

            for (Map.Entry e : event.getDetails().entrySet()) {

                sb.append(", ");

                sb.append(e.getKey());

                if (e.getValue() == null || e.getValue().indexOf(' ') == -1) {

                    sb.append();

                    sb.append(e.getValue());

                } else {

                    sb.append("='");

                    sb.append(e.getValue());

                    sb.append("'");

                }

            }

        }


        return sb.toString();

    }

Конечно, это очень наивная реализация. Что мы на самом деле сделали, так это определили методы для переноса этих событий в другие объекты и выполнения вызовов API для внешних систем. Но пока это сработает. Мы можем построить аналогичный метод для Событие администратора . Вы найдете его в основном полном коде.

Как только это будет сделано, нам нужно переопределить 2 метода, предоставляемые Поставщиком прослушивателя событий interface. Это onEvent и закрыть . Здесь это

    @Override
    public void onEvent(Event event) {

        System.out.println("Event Occurred:" + toString(event));
    }

    @Override
    public void onEvent(AdminEvent adminEvent, boolean b) {

        System.out.println("Admin Event Occurred:" + toString(adminEvent));
    }

    @Override
    public void close() {

    }

onEvent – это фактический метод, вызываемый всякий раз, когда происходит событие. Нам нужно дважды перегрузить событие, чтобы захватить оба События и Событие администратора . Наконец, метод close вызывается непосредственно перед уничтожением класса. Что-то вроде деструктора. Нам нужно переопределить его, даже если нам не нужно его использовать.

Вы можете найти полный код класса (вместе со строковой реализацией для события администратора) здесь

Следующим шагом будет реализация ProviderFactory Имя класса – Sample Event Listener ProviderFactory , который реализует Event Listener ProviderFactory Вот код:

(если приведенная выше суть не видна, вы можете найти файл здесь

Здесь мы переопределяем несколько методов. Основными из них являются create и getId . Метод create должен инициализировать и возвращать экземпляр provider (в нашем случае Sample Event Listener Provider ). В getId должен возвращать строку с именем плагина

Следующая и последняя задача – предоставить ссылку на наш класс. Для этого нам нужно создать ресурсы. создайте папку с именем ресурсы в src/main (рядом с папкой java ) Теперь создайте следующий файл в resources/META-INF/services/ с именем org.keycloak.events. Прослушиватель событий ProviderFactory . Обратите внимание, что полный путь к файлу – src/main/resources/META-INF/services/org.keycloak.events. Прослушиватель событий ProviderFactory

Этот файл содержит только одну строку с пакетом и именем нашего заводского класса

com.coderdude.sampleeventlistenerprovider.provider.SampleEventListenerProviderFactory

Это оно. Мы написали плагин. Теперь давайте соберем и упакуем его. Я использовал maven для сборки и упаковки

Как только упаковка будет завершена, вы должны увидеть jar и источники в целевом каталоге/| Вот моя окончательная структура каталогов

Нам понадобится только sample-event-listener.jar

— Теперь пришло время развернуть плагин для KeyCloak.

Давайте сначала настроимся с помощью KeyCloak. Руководство по началу работы вы найдете здесь https://www.keycloak.org/docs/latest/getting_started/index.html .

Быстро загрузите и создайте пользователя с правами администратора и войдите в KeyCloak. | Теперь давайте создадим новую область с именем newrealm и добавим пользователя с именем

Давайте также создадим пароль для этого нового пользователя

Пришло время развернуть ваш потрясающий плагин

Процесс развертывания довольно прост. Нам нужно скопировать sample-event-listener.jar в $KEYCLOAK_DIR/standalone/deployments/ где $KEYCLOAK_DIR – это основной каталог KeyCloak (после распаковки)

KeyCloak поддерживает горячую перезагрузку. Итак, как только мы скопируем jar-файл, keycloak должен перезагрузить и развернуть плагин. Но просто чтобы быть уверенным, давайте перезапустим сервер Keycloak.

Вы должны увидеть такую строку, как эта

Deployed "sample-event-listener.jar" (runtime-name : "sample-event-listener.jar")

Теперь нам нужно разрешить этому плагину прослушивать события. Перейти к newrealm->управление->события->конфигурация или этот URL /auth/admin/master/console/#/realms/newrealm/события-настройки

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

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

Давайте проверим это

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

Вы должны увидеть событие, происходящее в консоли

17:03:01,797 INFO  [stdout] (default task-5) Event Occurred:type=LOGIN, realmId=newrealm, clientId=account, userId=efc09972-6166-4ed6-9ca0-15c030e47f54, ipAddress=127.0.0.1, auth_method=openid-connect, auth_type=code, redirect_uri=http://localhost:8180/auth/realms/newrealm/account/login-redirect, consent=no_consent_required, code_id=78db58ed-3c99-4d42-aced-b69873c59f12, username=newuser001

Выход из системы также должен быть зафиксирован

17:03:51,211 INFO  [stdout] (default task-5) Event Occurred:type=LOGOUT, realmId=newrealm, clientId=null, userId=efc09972-6166-4ed6-9ca0-15c030e47f54, ipAddress=127.0.0.1, redirect_uri=http://localhost:8180/auth/realms/newrealm/account/

Попытка входа в систему с неправильным паролем также фиксируется (потому что мы также фиксировали ошибки)

17:04:04,505 WARN  [org.keycloak.events] (default task-5) type=LOGIN_ERROR, realmId=master, clientId=security-admin-console, userId=null, ipAddress=127.0.0.1, error=user_not_found, auth_method=openid-connect, auth_type=code, redirect_uri=http://localhost:8180/auth/admin/master/console/#/realms/newrealm/users, code_id=59a85ee0-a8f6-4fad-8667-f72de2da18fd, username=newuser001

Выглядит так в моей консоли

Вот так! Наш плагин способен фиксировать события

Подведение Итогов:

Еще раз, весь код доступен здесь:

adwait-что они/keycloak-событие-прослушиватель-spi

Пример SPI прослушивателя событий для keycloak

Это очень простой пример. Мы можем сделать гораздо больше. События keycloak предоставляют гораздо больше полезной информации, которую можно захватить. Например, текущая область, ip-адрес человека, пытающегося войти в систему, идентификаторы токенов доступа, если это вход в api, и т.д.

Если вам понравился этот блог, нажмите “Нравится”:)

Пока!

Ожидайте, что они, https://adwait-thattey.github.io/

Оригинал: “https://dev.to/adwaitthattey/building-an-event-listener-spi-plugin-for-keycloak-2044”