1

I have some problems with the configuration of the Client Credentials flow in my Client app (My Spring Gateway).

My Authorization server is functional and tests with Postman without any problem.

But in my Client application, it seems that the oauth2 configuration is broken without error of compilation.

When I call a protected resource on my server resource, my client application seems to attempt to call an URL in its base and not the authorization server.

See the code My configuration file:

security:
    oauth2:
      client:
        registration:
          apigateway:
            provider: apigateway
            client-id: apigateway
            client-secret: password
            scope: generate_token,read,write
            authorization-grant-type: client_credentials
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
        provider:
          apigateway:
            token-uri: https://localhost:9001/oauth/token

My Client dependency:

<dependencies>
        <!-- ************ SPRING DEPENDENCIES ************ -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-client</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
    </dependencies>

Configuration of my WebClient:

public class WebClientSecurityCustomizer implements WebClientCustomizer {

    private ServerOAuth2AuthorizedClientExchangeFilterFunction securityExchangeFilterFunction;

    public WebClientSecurityCustomizer(
            ServerOAuth2AuthorizedClientExchangeFilterFunction securityExchangeFilterFunction) {
        this.securityExchangeFilterFunction = securityExchangeFilterFunction;
    }

    @Override
    public void customize(WebClient.Builder webClientBuilder) {

        SslProvider sslProvider = SslProvider.builder().sslContext(
                SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
        )
                .defaultConfiguration(SslProvider.DefaultConfigurationType.NONE).build();

        TcpClient tcpClient = TcpClient.create().secure(sslProvider);
        HttpClient httpClient = HttpClient.from(tcpClient);
        ClientHttpConnector httpConnector = new ReactorClientHttpConnector(httpClient);
        webClientBuilder.clientConnector(httpConnector);

        webClientBuilder.filters((filterFunctions) -> {
            if (!filterFunctions.contains(this.securityExchangeFilterFunction)) {
                filterFunctions.add(0, this.securityExchangeFilterFunction);
            }
        });
    }
}

@Configuration
public class WebClientSecurityConfiguration {

    @Bean
    public WebClientSecurityCustomizer webClientSecurityCustomizer(
            ReactiveClientRegistrationRepository clientRegistrations) {

        // Provides support for an unauthenticated user such as an application
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());

        // Build up a new WebClientCustomizer implementation to inject the oauth filter
        // function into the WebClient.Builder instance
        return new WebClientSecurityCustomizer(oauth);
    }

    /**
     * Helper function to include the Spring CLIENT_REGISTRATION_ID_ATTR_NAME in a
     * properties Map
     *
     * @param provider - OAuth2 authorization provider name
     * @return consumer properties Map
     */
    public static Consumer<Map<String, Object>> getExchangeFilterWith(String provider) {
        return ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId(provider);
    }
}

My caller on the resource:

return webClientBuilder.build().get().uri(uri+"{accessToken}", accessToken)
                .attributes(
                        WebClientSecurityConfiguration.getExchangeFilterWith("apigateway"))
               .retrieve()
               .bodyToMono(String.class)
               .flatMap(response -> {
                   ServerHttpRequest request = exchange.getRequest().mutate()
                           .header(jwtHeader, String.format("%s %s", jwtPrefix, response))
                           .build();

                   return chain.filter(exchange.mutate().request(request).build());
               });
    }

And to finish, the error generated in the client application (it seems that Authorization and resource serve don't receive request):

2019-12-02 13:53:50.543 ERROR 11492 --- [ctor-http-nio-2] a.w.r.e.AbstractErrorWebExceptionHandler : [405f3f3c]  500 Server Error for HTTP GET "/oauth2/authorization/apigateway"

java.lang.IllegalArgumentException: Invalid Authorization Grant Type (client_credentials) for Client Registration with Id: apigateway
    at org.springframework.security.oauth2.client.web.server.DefaultServerOAuth2AuthorizationRequestResolver.authorizationRequest(DefaultServerOAuth2AuthorizationRequestResolver.java:156) ~[spring-security-oauth2-client-5.2.1.RELEASE.jar:5.2.1.RELEASE]

Thanks a lot for your help.

Jeremy Caillié
  • 101
  • 2
  • 11
  • Did you get this fixed? I am facing same issue. – Ms. Zia Mar 03 '20 at 09:08
  • Hi Ms. Zia, No, sorry. After this article, we found a blog post from the Spring Security team to explain that they are abandoning the authorization server. So we decided to change to a specific solution. – Jeremy Caillié Mar 03 '20 at 15:37

1 Answers1

-1

Add the below-mentioned class to your spring boot project. Then, it works properly without the above issue. You need to extend "WebSecurityConfigurerAdapter" for any custom security class.

import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/**");

    }

}
Vibhath
  • 44
  • 3