Как принудительно обновить oAuth-токен (access-token + refresh token) с помощью адаптера Keycloak Spring boot + Spring Security.? - PullRequest
2 голосов
/ 11 октября 2019

У меня есть мультитенантное приложение (адаптер keyboak для Springboot + защита от Spring), защищенное keycloak. Учитывая мультитенатную природу проекта, я написал многоклиентный коннектор, который прекрасно работает.

На официальном документе Keaycloak рекомендуется (для мультитенантных приложений) моделировать каждый теннант как новую область, но для меня этолучше работает, когда несколько клиентов находятся в одной и той же области. Это обусловлено следующими преимуществами:

  • Области клиента, группы и другие конфигурации могут быть общими
  • Пользователям не нужно дублировать данные в N различных сферах
  • Вход в систему единого входа прекрасно работает в одних и тех же клиентах области (с использованием служб переноса + CORS)

Итак, все работает отлично, за исключением 1 вещи, моего начального единого входа для доступа (который затем используется всеми службами только переноса)с помощью CORS) довольно большой (он показывает все ресурсы - tennants - и их роли в каждом ресурсе / tennant).

Я бы хотел ограничить размер access_token с помощью использования"scopes", чтобы ограничить роли access_token теми, которые значат для tennat, где я вошел в то время. Для этого я вручную запускаю запрос к серверу авторизации (за пределами стандартной функциональности, предоставляемой springboot / spring security) с целью ручной перезаписи того, есть ли токен доступа в моем приложении, с новым, сгенерированным моим дополнительнымrequest.

Мой «новый» запрос токена выглядит примерно так:

    SimpleKeycloakAccount currentUserAccount = (SimpleKeycloakAccount) auth.getDetails();
            String authServerUrl = currentUserAccount.getKeycloakSecurityContext().getDeployment().getAuthServerBaseUrl();
            String realm = currentUserAccount.getKeycloakSecurityContext().getDeployment().getRealm();
            String resource =  currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceName();
            String refreshToken = currentUserAccount.getKeycloakSecurityContext().getRefreshToken();
            String token = currentUserAccount.getKeycloakSecurityContext().getTokenString();


            Http http = new Http( new Configuration(authServerUrl, realm, resource,
                            currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceCredentials()
                           , null), 
                       (params, headers) -> {});

            String url = authServerUrl + "/realms/" + realm + "/protocol/openid-connect/token";

            AccessTokenResponse response = http.<AccessTokenResponse>post(url)
                .authentication()
                    .client()
                .form()
                    .param("grant_type", "refresh_token")
                    .param("refresh_token", refreshToken)
                    .param("client_id", resource)
                    .param("client_secret", "SOME_SECRET")
                    .param("scope", "SOME_SCOPE_TO_RESTRICT_ROLES")
                .response()
                    .json(AccessTokenResponse.class)
                .execute();

// :) -  response.getToken() and response.getRefreshToken(), contain new successfully generated tokens

Мой вопрос состоит в том, как заставить мое приложение изменить / сбросить стандартный токен доступа и refresh_tokenполученные обычными средствами, с этими "созданными на заказ" токенами? или это вообще возможно?

Спасибо за любой отзыв!

Дополнительная информация

Чтобы прояснить подробнее, давайте проанализируем поведение типичного проекта безопасности Springboot / Spring, интегрированного с keycloack:

  • Вы защищаете свои конечные точки с помощью «ролей» через конфигурации (либо в application.properties, либо в SecurityContext)
  • Вы знаете, что это приложение Spring взаимодействует в обратном каналес сервером авторизации keycloak вот так вы становитесь access_token (но все это черный ящик для разработчика, вы только знаете, что был создан принципал, контекст безопасности, учетные данные и т. д. - все происходит за кулисами)

Учитывая эти 2 пункта выше, представьте, что вы используете библиотеку Http для запроса нового токена к конечной точке токена сервера аутентификации, как в приведенном выше коде (да, отфильтрованные по областям и тому подобное). Таким образом, теперь ситуация такова, что, хотя вы создали действительный acces_token (и refresh_token);поскольку они были созданы «вручную» путем отправки запроса к конечной точке токена, этот новый токен не был «включен» в приложение, поскольку не было создано никакого нового принципала, не был создан новый контекст безопасности и т. д. Другими словамиДля приложения Springboot этот новый токен не существует.

Что я пытаюсь сделать, это сказать sprinboot / spring security: «Эй, приятель, я знаю, что ты сам не генерировал этот токен, но, пожалуйста, прими его и веди себя так, как если бы ты его создал».

Надеюсь, это прояснит смысл моего вопроса.

Ответы [ 2 ]

0 голосов
/ 11 октября 2019

В случае, если каждый клиент является отдельным клиентом, вы можете просто использовать сопоставление «Scope» keycloak на каждом клиенте. Просто отключите Full Scope Allowed , и ваши токены будут содержать роли пользователя только для этого конкретного клиента (арендатора).

«Назначение области» - неинтуитивный способ сказать «Определите, какие ролидолжен входить в токен доступа ": -)

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

Reducing scope mapping of a client

0 голосов
/ 11 октября 2019

Вы можете отозвать токен, используя метод org.springframework.security.oauth2.provider.token.ConsumerTokenServices#revokeToken.

На сервере авторизации:

@Resource(name="tokenServices")
ConsumerTokenServices tokenServices;

@RequestMapping(method = RequestMethod.POST, value = "/tokens/revoke/{tokenId:.*}")
@ResponseBody
public String revokeToken(@PathVariable String tokenId) {
    tokenServices.revokeToken(tokenId);
    return tokenId;
}

Конечно, вам придется обезопасить этот метод, так как он очень чувствителенодин.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...