Всем привет. Сегодня мы покажем вам простой пример, как в Keycloak можно добавить кастомный аутентификатор. Как вы все знаете, Keycloak – это система адаптивной аутентификации, позволяющая реализовать фактические любой процесс аутентификации (ограниченный только навыками разработки на Java) и выступать в качестве Identity Provider для клиентов по протоколам OIDC и SAML. В стандартном наборе представлено много типовых аутентификаторов. Но что делать, когда стандартных аутентификаторов недостаточно и необходимо реализовать свою логику? Официальная документация дает ответ: разработать аутентификатор самому. Что мы вместе с нашим системным инженером направления кибербезопасности К2Тех Егором Туркиным в итоге и сделали.  Пример аутентификаторов: Аутентификатор представляет собой jar-файл, разработанный определенным способом (описанным в документации). Его нужно добавить в определенную папку, в моем случае:…/keycloak-21.0.2/providers После чего необходимо выполнить bin/kc.sh build И аутентификатор появится в общем перечне. Если все пройдет нормально. Итак, представим, что нам нужно выполнить запрос по REST API к сторонней системе и получить от нее разрешение на вход пользователя. Собираем вот такой стенд: В качестве целевого веб-сервера используем apache2 с установленным модулем mod_auth_openidc, позволяющим ему выступать в качестве OIDC-клиента: https://github.com/OpenIDC/mod_auth_openidc  Конфигурация Apache2 будет выглядеть так: Тут важно отметить, что мы в целях теста отключили проверку подлинности по SSL с помощью опции OIDCSSLValidateServer Off. В проде, конечно же, делать этого нельзя. В качестве тестового сайта создаем php-файлик: Взяли отсюда: https://docs.openathens.net/providers/apache-openid-connect-example  На самом деле там может быть что угодно, просто этот код предоставляет некоторую отладочную информацию. В качестве сторонней системы удобнее всего использовать OpenResty https://openresty.org/ В качестве входа ожидаем json, содержащий {'username': <собственно, имя пользователя> }, а в ответ отправим просто Allow или Deny. В целях теста просто сделали список пользователей, которым разрешен доступ, разместили их в whitelisted_names. Важно заметить, что парсер достаточно капризный, поэтому для отладки сохраняли тело запроса: access_log  /var/log/nginx/postdata.log  postdata Наконец уговорили его отработать запрос =) Конфигурация будет выглядеть так: Работает =) Создаем клиент Apache2. Client id и Client Secret должны совпадать с тем, что прописано в конфиге Apache2 Создаем новый flow и в разделе Advanced присваиваем его клиенту Проверяем, подключение проходит нормально. Текст аутентификатора неполный – только те методы, которые мы модифицировали. Создается класс TestAuthenticator3 на основе общего класса Authenticator. Основным методом аутентификатора является authenticate. Непосредственно в нём реализуется логика проверки, которую должен пройти пользователь при аутентификации.  В нашем случае проверка основана на проверке наличия имени входящего пользователя в списке доверенных имен, хранимом на удаленном сервере. Для получения объекта пользователя, содержащего в том числе и имя, вызывается функция context.getUser(). Затем из полученного объекта выделяется имя с помощью функции getUsername(). Полученное имя отправляется на удаленный сервер, который проверяет его вхождение в список доверенных, и выдает результат. В случае успешного прохождения проверки метод завершается вызовом функции context.success. Если же пользователь не прошёл проверку, то метод завершается вызовом функции context.failure, в которой дополнительно указывается тип ошибки аутентификации. Подробнее можно посмотреть в официальной документации.  Отладочная информация выводится в консоль. URL дополнительно ИС, к которой выполняется запрос, задан константой. Аутентификатор: AuthenticationFactory предназначен для генерации экземпляра аутентификатора и его взаимодействие с Keycloak. Фактически этот объект нужен, чтобы Keycloak увидел наш новый аутентификатор. В данном классе определяются свойства, с которыми будет создан экземпляр нашего аутентификатора. Подробно о каждом из свойств можно посмотреть в официальной документации: https://www.keycloak.org/docs/latest/server_development/#implementing-an-authenticatorfactory.  Фактори: Строим вот такой flow. Вот что видим на Apache. Успешная попытка: 62.217.191.91 - gimli [14/Jun/2023:16:21:12 +0300] "GET /info2.php HTTP/1.1" 200 2462 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" 62.217.191.91 - - [14/Jun/2023:16:21:26 +0300] "GET / HTTP/1.1" 302 1571 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" 62.217.191.91 - gimli [14/Jun/2023:16:21:32 +0300] "GET /info.php?state=0CQZYZmW5jWpUlb4xbeqk2VcIs4&session_state=e4058c19-9a58-4e98-8d97-fbcb6966d0b8&code=9e76fced-42c9-454f-85d0-6d7a652da3e4.e4058c19-9a58-4e98-8d97-fbcb6966d0b8.098780c7-759e-41a3-96ce-d3837e1790a3 HTTP/1.1" 302 754 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" 62.217.191.91 - gimli [14/Jun/2023:16:21:32 +0300] "GET / HTTP/1.1" 200 5381 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" 62.217.191.91 - gimli [14/Jun/2023:16:21:32 +0300] "GET /index.files/image002.jpg HTTP/1.1" 200 47910 "http://askar.test.local/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" 62.217.191.91 - gimli [14/Jun/2023:16:21:38 +0300] "GET /info2.php HTTP/1.1" 200 2360 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" Неуспешная попытка 2023-06-14 16:33:16,184 WARN  [org.keycloak.events] (executor-thread-98) type=LOGIN_ERROR, realmId=69bd9151-dd74-470a-ba27-1a660799fcf2, clientId=apache2, userId=null, ipAddress=62.217.191.91, error=invalid_user_credentials, auth_method=openid-connect, auth_type=code, redirect_uri=http://askar.test.local/info.php, code_id=729202ce-a308-458c-bfe0-767fd9349d69, username=legolas, authSessionParentId=729202ce-a308-458c-bfe0-767fd9349d69, authSessionTabId=GQPjo8i5d6A Таким образом, мы добавили кастомный аутентификатор в KeyCloak, а также настроили веб‑сервер Apache и стороннюю систему аутентификации, и подружили ее с KeyCloak.