Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consider defining a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' in your configuration

I am using spring oAuthClient version 5.2.4.RELEASE By following the document link of spring security https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2Client-authorized-manager-provider

    import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

@AllArgsConstructor
@Configuration
@Slf4j
public class WebClientConfig {

    @Bean("AuthProvider")
    WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations,
                authorizedClients);
        oauth.setDefaultOAuth2AuthorizedClient(true);
        oauth.setDefaultClientRegistrationId("AuthProvider");
        return WebClient.builder()
                .filter(oauth)
                .filter(this.logRequest())
                .build();
    }


    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("Request: [{}] {}", clientRequest.method(), clientRequest.url());
            log.debug("Payload: {}", clientRequest.body());
            return Mono.just(clientRequest);
        });
    }

application.yaml

   security:
    oauth2:
      client:
        provider:
          AuthProvider:
            token-uri: ${tokenpath<read from environment variable>}
        registration:
          AuthProvider:
            authorization-grant-type: client_credentials
            client-id: ${<read from environment variable>}
            client-secret: ${<read from environment variable>}

Getting the following error

    ***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method webClient in com.sample.config.WebClientConfig required a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' in your configuration.

Let me know, if I missed any configuration as didnot get any specific help from other questions of stackoverflow

like image 838
raj03 Avatar asked Jun 18 '20 09:06

raj03


People also ask

What is ReactiveClientRegistrationRepository?

Interface ReactiveClientRegistrationRepository Therefore, this repository provides the capability to store a sub-set copy of the primary client registration information externally from the Authorization Server.

What is OAuth2 client in spring boot?

The OAuth 2.0 Client features provide support for the Client role as defined in the OAuth 2.0 Authorization Framework. At a high-level, the core features available are: Authorization Grant support. Authorization Code. Refresh Token.

What is Spring Security OAuth2?

It serves as an open authorization protocol for enabling a third party application to get limited access to an HTTP service on behalf of the resource owner. It can do so while not revealing the identity or the long-term credentials of the user. A third-party application itself can also use it on its behalf.

What is the response client Bean in Spring Boot?

And here's the response client bean: This configuration is the same as the default one and is using the Spring implementation which is based on exchanging an authorization code with the provider. Of course, we could also substitute a custom response client.

Is it possible to inject directly the authenticationmanager Bean in Spring Boot?

<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> We can’t inject directly the AuthenticationManager bean anymore in Spring-Boot 2.0, but it still is required by Spring Security. Therefore, we need to implement a small hack in order to gain access to this object:

How to configure Spring Boot OAuth2 using new stack?

6. Spring Boot OAuth2 Auto-Configuration (Using New Stack) To use the new stack, we need to add dependencies based on what we want to configure — an authorization server, a resource server, or a client application. Let's look at them one by one. 6.1.

What is the default configuration for authentication in Spring Security?

These default configurations provide all the necessary information for authentication, which is what allows us to only enter the client credentials. If we want to use a different authentication provider not configured in Spring Security, we'll need to define the full configuration, with information such as authorization URI and token URI.


4 Answers

I am using spring boot 2.3.1.RELEASE I had the same problem, my pom.xml contained both these dependencies in my pom.xml

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

I removed the following dependency and that did the trick for me :

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

Not saying this will resolve your hassle but this might also be a dependency conflict issue for you.

This other post put me on track : Reactive OAuth2 with Spring Security 5.3.2 ReactiveClientRegistrationRepository bean could not be found

like image 158
Pierre CARUYER Avatar answered Oct 26 '22 20:10

Pierre CARUYER


Your spring-boot configuration is perfect.


Root cause of the issue: The problem is in application.yaml. Either the configuration is wrong or not picked from the environment.

So, the problem is not the OAuth2 version but the configuration in application.yaml.

Note : ReactiveClientRegistrationRepository bean is created only when you configure the client with the OAuth2 application owner details.


I created a new project from start.spring.io and used your configuration in that.

And after running the project with your configuration, I was facing the same issue.

Error log :

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method webClient in com.example.sampleoauth2.WebClientConfig required a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' that could not be found.

The following candidates were found but could not be injected:
    - Bean method 'clientRegistrationRepository' in 'ReactiveOAuth2ClientConfigurations.ReactiveClientRegistrationRepositoryConfiguration' not loaded because OAuth2 Clients Configured Condition registered clients is not available


Action:

Consider revisiting the entries above or defining a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' in your configuration.

Then, I saw that I didn't configure properties in application.yml file.

I read Spring Boot and OAuth2.0 Docs about how to get client-id and client-secret from github (Example) as you register your spring-boot app as OAuth app in that.

As soon as, I configured my application started to work.


I'm using spring-boot 2.3.1.RELEASE and OAuth2Client version 5.3.3.

My pom.xml :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sampleOauth2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sampleOauth2</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectreactor</groupId>
            <artifactId>reactor-spring</artifactId>
            <version>1.0.1.RELEASE</version>
        </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>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

My client github registration properties for application.yml:

spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: 22a7100de41c7308d346
            client-secret: 05910ab890be29579e9c183443d92e756c450aaf

Your updated WebClientConfig @Configuration class :

package com.example.sampleoauth2;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;

import reactor.core.publisher.Mono;

@Configuration
public class WebClientConfig {

    public static Logger log = LogManager.getLogger();

    @Bean
    public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations,
            ServerOAuth2AuthorizedClientRepository authorizedClients) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        oauth.setDefaultOAuth2AuthorizedClient(true);
        return WebClient.builder().filter(oauth).filter(this.logRequest()).build();
    }

    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("Request: [{}] {}", clientRequest.method(), clientRequest.url());
            log.debug("Payload: {}", clientRequest.body());
            return Mono.just(clientRequest);
        });
    }
}

Success Log :

   .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.1.RELEASE)

2020-06-26 20:36:08.380  INFO 15956 --- [           main] c.e.s.SampleOauth2Application            : Starting SampleOauth2Application on Anishs-MacBook-Pro.local with PID 15956 (/Users/anish/Downloads/sampleOauth2/target/classes started by anish in /Users/anish/Downloads/sampleOauth2)
2020-06-26 20:36:08.381  INFO 15956 --- [           main] c.e.s.SampleOauth2Application            : No active profile set, falling back to default profiles: default
2020-06-26 20:36:08.935  INFO 15956 --- [           main] ctiveUserDetailsServiceAutoConfiguration : 

Using generated security password: 7c63302f-f913-4aa1-852d-cb8445719acb

2020-06-26 20:36:09.132  INFO 15956 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2020-06-26 20:36:09.138  INFO 15956 --- [           main] c.e.s.SampleOauth2Application            : Started SampleOauth2Application in 0.978 seconds (JVM running for 1.313)
like image 33
Anish B. Avatar answered Oct 26 '22 19:10

Anish B.


I used the configurations that @AnishB. suggested as answer but still got the error:

Parameter 0 of method webClient in com.example.sampleoauth2.WebClientConfig required a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' that could not be found.

So, i had to use these dependencies with spring 2.3.1.RELEASE:

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

And this the WebClientConfig class:

@Configuration
public class WebClientConfig {

    private static final Logger log = LoggerFactory.getLogger(WebClientConfig.class);

    @Bean("cr")
    ReactiveClientRegistrationRepository getRegistration(
            @Value("${spring.security.oauth2.client.provider.keycloak.token-uri}") String tokenUri,
            @Value("${spring.security.oauth2.client.registration.keycloak.client-id}") String clientId,
            @Value("${spring.security.oauth2.client.registration.keycloak.client-secret}") String clientSecret
    ) {
        ClientRegistration registration = ClientRegistration
                .withRegistrationId("keycloak")
                .tokenUri(tokenUri)
                .clientId(clientId)
                .clientSecret(clientSecret)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .build();
        return new InMemoryReactiveClientRegistrationRepository(registration);
    }

    @Bean(name = "keycloak")
    WebClient webClient(@Qualifier("cr") ReactiveClientRegistrationRepository clientRegistrations) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
        oauth.setDefaultClientRegistrationId("keycloak");
        return WebClient.builder()
                .filter(oauth)
                .filter(logRequest())
                .build();
    }

    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("Request: [{}] {}", clientRequest.method(), clientRequest.url());
            log.debug("Payload: {}", clientRequest.body());

            return Mono.just(clientRequest);
        });
    }
}

and everything works fine, but it is question for me that why the solution of @AnishB. didn't worked for me?!

like image 22
Rasool Ghafari Avatar answered Oct 26 '22 18:10

Rasool Ghafari


ReactiveClientRegistrationRepository is come with Reactive stack (netty), not with Servlet stack (tomcat)

In case your pom.xml include spring-boot-starter-web, Spring understand that you use Servlet stack, it will load ClientRegistrationRepository instead of ReactiveClientRegistrationRepository

To create bean of WebClient, two solution you can use:

Solution 1:

Remove spring-boot-starter-web from pom.xml so Spring understand you are in Reactive stack

@Bean
WebClient webClient(
    ReactiveClientRegistrationRepository clientRegistrationRepository,
    ReactiveOAuth2AuthorizedClientService authorizedClientService
) {
    var oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
            new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
                clientRegistrationRepository, authorizedClientService
            )
        );

    oauth.setDefaultClientRegistrationId("AuthProvider");
    return WebClient.builder()
        .filter(oauth)
        .build();
}

Solution 2:

Keep spring-boot-starter-web in pom.xml

@Bean // with spring-boot-starter-web
WebClient webClient(
    ClientRegistrationRepository clientRegistrationRepository,
    OAuth2AuthorizedClientService authorizedClientService
) {
    var oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
        new AuthorizedClientServiceOAuth2AuthorizedClientManager(
            clientRegistrationRepository, authorizedClientService
        )
    );
    oauth.setDefaultClientRegistrationId("AuthProvider");
    return WebClient.builder()
      .apply(oauth.oauth2Configuration())
      .build();
}
like image 36
KevinBui Avatar answered Oct 26 '22 20:10

KevinBui