Spring Security 5 При вызове защищенного API OAuth2 в Application Runner возникает исключение IllegalArgumentException - PullRequest
7 голосов
/ 23 марта 2019

Учитывая приведенный ниже код, возможно ли вызвать защищенный API Client Credentials в приложении-исполнителе?

@Bean
public ApplicationRunner test(
    WebClient.Builder builder,
    ClientRegistrationRepository clientRegistrationRepo, 
    OAuth2AuthorizedClientRepository authorizedClient) {
        return args -> {
            try {
                var oauth2 =
                    new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                        clientRegistrationRepo,
                        authorizedClient);
                oauth2.setDefaultClientRegistrationId("test");
                var response = builder
                    .apply(oauth2.oauth2Configuration())
                    .build()
                    .get()
                    .uri("test")
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();
                log.info("Response - {}", response);
            } catch (Exception e) {
                log.error("Failed to call test.", e);
            }
        };
    }

Код не выполняется из-за:

java.lang.IllegalArgumentException: request cannot be null

Полный стек,

java.lang.IllegalArgumentException: request cannot be null
    at org.springframework.util.Assert.notNull(Assert.java:198) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository.loadAuthorizedClient(HttpSessionOAuth2AuthorizedClientRepository.java:47) ~[spring-security-oauth2-client-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.populateDefaultOAuth2AuthorizedClient(ServletOAuth2AuthorizedClientExchangeFilterFunction.java:364) ~[spring-security-oauth2-client-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.lambda$null$2(ServletOAuth2AuthorizedClientExchangeFilterFunction.java:209) ~[spring-security-oauth2-client-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.attributes(DefaultWebClient.java:234) ~[spring-webflux-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.attributes(DefaultWebClient.java:153) ~[spring-webflux-5.1.5.RELEASE.jar:5.1.5.RELEASE]

С методом сбоя, похожим на

public <T extends OAuth2AuthorizedClient> T loadAuthorizedClient(
    String clientRegistrationId,  Authentication principal, HttpServletRequest request){

    Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty");
    Assert.notNull(request, "request cannot be null");
    return (OAuth2AuthorizedClient)this
        .getAuthorizedClients(request)
        .get(clientRegistrationId);
}

Это имеет смысл, поскольку для него не существует HttpServletRequest, который вызывается при запуске приложения..

Есть ли какие-либо обходные пути, кроме как сделать мой собственный неоперативный OAuth2AuthorizedClientRepository?

// Правка,

Это не полностью реактивный стек.Это стек Spring Web, в котором используется WebClient.

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

1 Ответ

1 голос
/ 01 апреля 2019

В итоге я спросил об этом команду Spring Security,

https://github.com/spring-projects/spring-security/issues/6683

К сожалению, если вы находитесь в стеке сервлетов и обращаетесь к ресурсам OAuth2 с помощью чистого Spring Security 5API в фоновом потоке недоступны OAuth2AuthorizedClientRepository.

Реально есть два варианта:

  1. Реализация полностью неоперационной версии,
 var oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepo,
                        new OAuth2AuthorizedClientRepository() {
                            @Override
                            public <T extends OAuth2AuthorizedClient> T loadAuthorizedClient(String s,
                                    Authentication authentication, HttpServletRequest httpServletRequest) {
                                return null;
                            }

                            @Override
                            public void saveAuthorizedClient(OAuth2AuthorizedClient oAuth2AuthorizedClient,
                                    Authentication authentication, HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse) {

                            }

                            @Override
                            public void removeAuthorizedClient(String s, Authentication authentication,
                                    HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {

                            }
                        });
Реализация версии сервлета UnAuthenticatedServerOAuth2AuthorizedClientRepository. UnAuthenticatedServerOAuth2AuthorizedClientRepository GitHub Source , который имеет некоторые базовые функциональные возможности, чем чистый no-op.

Предоставление обратной связи по проблеме GitHub может помочь команде Spring Security оценить принятие PR и поддержку версии сервлета для UnAuthenticatedServerOAuth2AuthorizedClientRepository

Я обратился кSpring Security Team Spring Security Issue 6683 , а в конце этого версия Springt ServerOAuth2AuthorizedClientExchangeFilterFunction будет добавлена ​​в Spring Security 5.2 для использования в потоках, отличных от http.

...