Spring Security 5 Calling OAuth2 Secured API in Application Runner results in IllegalArgumentException

你说的曾经没有我的故事 提交于 2019-12-23 08:11:30

问题


Given the following code, is it possible to call a Client Credentials secured API in an application runner?

@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);
            }
        };
    }

The code fails due to,

java.lang.IllegalArgumentException: request cannot be null

Full stack,

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]

With the failing method looking like,

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);
}

Which makes sense as there is not HttpServletRequest for it to use, its being called on start-up of the application.

Is there any workarounds other than make my own no-op OAuth2AuthorizedClientRepository?

//Edit,

This is not a fully reactive stack. It is a Spring Web stack with the WebClient being used with in it.

I am well aware of the ServerOAuth2AuthorizedClientExchangeFilterFunction which applies to a fully reactive stack and requires ReactiveClientRegistrationRepository and ReactiveOauth2AuthorizedClient which are not available due to this being in an application built on top of Servlet stack, not reactive.


回答1:


I ended up asking this to the Spring Security team,

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

Unfortunately if you are on the servlet stack and calling to OAuth2 resources with pure Spring Security 5 APIs in a background thread there isn't a OAuth2AuthorizedClientRepository available.

Realistically there's two options,

  1. Implement a completely no-op version,
 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) {

                            }
                        });
  1. Implement a Servlet Version of UnAuthenticatedServerOAuth2AuthorizedClientRepository. UnAuthenticatedServerOAuth2AuthorizedClientRepository GitHub Source which has some basic functionality than a pure no-op.

Providing feedback on the GitHub issue might help the Spring Security team to evaluate accepting a PR and maintaining a Servlet version of the UnAuthenticatedServerOAuth2AuthorizedClientRepository

I reached out the the Spring Security Team Spring Security Issue 6683 and on the back of that a Servlet version of the ServerOAuth2AuthorizedClientExchangeFilterFunction will be added in Spring Security 5.2 for usage on non-http threads.



来源:https://stackoverflow.com/questions/55308918/spring-security-5-calling-oauth2-secured-api-in-application-runner-results-in-il

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!