I am unable to get the value I am expecting, An exception is thrown at this line #Value("${message:this-is-class-value}").
SERVER SIDE
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
src/main/resources/application.properties
server.port=8888
spring.application.name=config-service
spring.cloud.config.server.git.uri=file:///C:/config
management.endpoints.web.exposure.include=*
spring.security.user.name=root
spring.security.user.password=abc123
Application class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
#SpringBootApplication
#EnableConfigServer
public class ConfigServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServiceApplication.class, args);
}
}
Local git folder
Configurations files with the same property but the different value to detect
c:/config/application.properties
c:/config/api-gateway.properties
c:/config/api-gateway-PROD.properties
output while server startup
Completed initialization in 5 ms
WARN : Could not merge remote for master remote: null
INFO : o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/C:/config/application.properties
if I access this url
http://localhost:8888/api-gateway/PROD
console output is as follows
WARN : Could not merge remote for master remote: null
INFO : o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/C:/config/api-gateway-PROD.properties
INFO : o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/C:/config/api-gateway.properties
INFO : o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/C:/config/application.properties
CLIENT SIDE (Separate Project)
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
Application class
#SpringBootApplication
#EnableZuulProxy
#EnableDiscoveryClient
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
Controller
#RestController
public class SettingsController {
#Value("${message:this-is-class-value}")
String name = "World";
#RequestMapping("/")
public String home() {
return "Hello " + name;
}
}
resources/application.yml
server:
port: 8282
spring:
application:
name: api-gateway
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
resources/bootstrap.yml
spring:
profiles:
active: PROD
cloud:
config:
name: api-gateway
uri: http://localhost:8888/
username: root
password: abc123
management:
endpoints:
web:
exposure:
include: refresh
Console output
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'settingsController': Injection of autowired dependencies failed; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.util.LinkedHashMap<?, ?>] to type [java.lang.String]
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.util.LinkedHashMap<?, ?>] to type [java.lang.String]
Please do let me know if anything else is required.
add message=Hello from property file1 in src/main/resources/application.properties. Or if you want to read this property from c:/config/application.properties or c:/config/config-service.properties you need to configure external configuration file by using #ConfigurationProperties annotation.
Looks, you are trying to use the #Value annotation on controller class which resides in your Cloud config server application. While the concept is like cloud config server application will be the provider to other applications and it can provide the properties from git or local file system (configuration) to requester client application. Other applications will connect to your config server application by providing it's URL, application name and profile for which it want to get the properties. You can check below URL for cloud config server and client application.
https://www.thetechnojournals.com/2019/10/spring-cloud-config.html
Your cloud config server has security configuration as below.
spring.security.user.name=root
spring.security.user.password=abc123
You client configuration doesn't provide any security configuration which is causing 401 error in your logs.
To solve this issue please do below changes to your client configuration.
Client configuration:
spring:
profiles:
active: PROD
cloud:
config:
name: api-gateway
uri: http://localhost:8888/
username: root
password: abc123
Related
Spring cloud-config server started with application.properties :
server.port:8888
spring.application.name=test-config-server
spring.cloud.config.server.git.uri=https://gitlab.com/pearsontechnology/gpt/sms/sms-micro-services/config-server.git
spring.cloud.config.server.git.default-label=develop
#Private repo. access credentials
spring.cloud.config.server.git.username=xxx
spring.cloud.config.server.git.password=xxxx
spring.cloud.config.server.git.clone-on-start=true
spring.cloud.config.profile=dev
On starting the config-client,
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
My version of spring boot, spring-cloud and dependencies are as follows from pom.xml :
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<java.version>17</java.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
application.prop of config-client :
spring.application.name=systems-lookup-service
spring.cloud.config.profile=dev
spring.config.import=optional:configserver:
server.port=8081
Properties related to Datasource like url etc. need to be taken from
systems-lookup-service-dev.properties hosted on Git.
custom.url=jdbc:oracle:thin:#localhost:1998/smscert
custom.username=smscert
custom.password=go#salt
custom.driverClassName=
And the DAO class in config-client accessing the db :
public class XXDaoImpl implements XXDao {
private JdbcTemplate jdbcTemplate;
#Autowired(required=false)
private DataSourceConfig config;
#Autowired
public SystemDaoImpl(JdbcTemplate jdbcTemplateIn){
final DataSource dataSource = DataSourceBuilder.create()
.driverClassName(config.getDriverClassName())
.url(config.getUrl())
.username(config.getUsername())
.password(config.getPassword())
.build();
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
...............
}
#Component
#ConfigurationProperties("custom")
public class DataSourceConfig {
private String url;
private String username;
private String password;
//#Value("${greeting.message}")
private String driverClassName;
....
}
I believe you follow the first boot-strapping for your central cloud registration to do so you need following artifact with in your client service pom file.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Add the following properties to you client service property file application.prop
spring.application.name=systems-lookup-service
spring.cloud.config.uri=http://localhost:"cloud-config-port"
spring.profiles.active=dev
spring.config.import=optional:configserver:
With in main class on central cloud config add the annotation #EnableConfigServer and within it pom file add following artifact
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
append following properties to your central cloud config property file
spring.application.name=configuration-server
server.port=8780
management.endpoints.web.exposure.include=*
spring.cloud.config.server.git.uri=file:absoluthe-path
spring.cloud.config.server.git.clone-on-start=true
spring.cloud.config.allowOverride=true
Finally add your client service properties in your gitrepo with naming servicename-profile convention.
Extra point
You may consider to use spring cloud boss, for hot reloading the configs and not restarting services to handshake again, find out more in here.
Disabled auto-configuration of the data source by annotating client main with #SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
I created a springboot application that uses Spring Boot and Apache Camel JDBC Component for inserting a record in postgreSQL. For this purpose I am using the following dependencies:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jdbc</artifactId>
<version>${camel.version}</version>
<!-- use the same version as your Camel core version -->
</dependency>
As for the database configuration, I created the following java class with an application.properties file:
Database Configuration java class:
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import org.apache.camel.support.SimpleRegistry;
import org.apache.commons.dbcp2.BasicDataSource;
public class DatabaseConfiguration {
public static SimpleRegistry createDatabaseConfiguration() throws IOException {
Properties properties = new Properties();
properties.load(new FileInputStream("src/main/resources/application.properties"));
BasicDataSource basic = new BasicDataSource();
basic.setDriverClassName(properties.getProperty("PostgresDBClassname"));
basic.setUsername(properties.getProperty("PostgresDBUsername"));
basic.setPassword(properties.getProperty("PostgresDBPassword"));
basic.setUrl(properties.getProperty("PostgresDBUrl"));
SimpleRegistry registry = new SimpleRegistry();
registry.bind("myDataSource", basic);
return registry;
}
}
application.properties file:
PostgresDBUsername = username
PostgresDBPassword = password
PostgresDBClassname = org.postgresql.Driver
PostgresDBUrl = jdbc:postgresql://localhost:5432/postgres
I wrote the router in the following way, noting that I tried to replace dataSource with myDataSource:
#Component
public class InsertRestService extends RouteBuilder {
#Override
public void configure() throws Exception {
rest("/").produces("text/plain")
.get("insert")
.to("direct:hello");
from("direct:hello")
.transform().simple("INSERT INTO person (name, country) VALUES (DANY, LB)")
.to("jdbc:dataSource") //spring boot starter jdbc creates the bean in the registry
.transform().simple("Data inserted in Postgres successfully");
}
}
I got the following error:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
I provided the URL in the application.properties file PostgresDBUrl
Also note that I downloaded the jdbc driver jar file and added it to the module path, after a right click on the package, build path, configure build path
So what can I do to solve this issue?
Thank you!!
I removed the configuration file (DatabaseConfiguration) and replaced the content of the application.properties file with:
spring.datasource.url=jdbc:postgresql://localhost:5432/test
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgres
spring.jpa.hibernate.ddl-auto=none
and it worked!
Check your pom.xml file and switch its packaging into war. It worked for me.
<packaging>war</packaging>
I have a spring boot microservice with kubernetes dependencies for configmap and secret support.The current spring boot version is 2.3.9.RELEASE . and the kubernetes dependency version is 1.1.0.RELEASE . its an old one , so i tried to update the dependency to its latest 1.1.10.RELEASE.
This is the updated pom details
<spring-cloud-kubernetes.version>1.1.10.RELEASE</spring-cloud-kubernetes.version>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-dependencies</artifactId>
<version>${spring-cloud-kubernetes.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-dependencies</artifactId>
<version>${spring-cloud-kubernetes.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
After updating the kubernetes dependency version to 1.1.10.RELEASE , am getting the below error while stating the app
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'propertyChangeWatcher' defined in class path resource [org/springframework/cloud/kubernetes/config/reload/ConfigReloadAutoConfiguration$ConfigReloadAutoConfigurationBeans.class]: Unsatisfied dependency expressed through method 'propertyChangeWatcher' parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configurationUpdateStrategy' defined in class path resource [org/springframework/cloud/kubernetes/config/reload/ConfigReloadAutoConfiguration$ConfigReloadAutoConfigurationBeans.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy]: Factory method 'configurationUpdateStrategy' threw exception; nested exception is java.lang.IllegalArgumentException: Restart endpoint is not enabled
This is my bootstrap.yml file
spring:
cloud:
kubernetes:
reload:
enabled: true
monitoring-config-maps: true
mode: polling
period: 15000
strategy: restart_context
config:
enabled: true
sources:
- name: demo
secrets:
enabled: true
enable-api: true
sources:
- name: demo-secret
management:
endpoint:
restart:
enabled: true
health:
enabled: true
info:
enabled: true
env:
enabled: true
refresh:
enabled: true
This is my application.yml file
management:
endpoints:
beans:
enabled: false
web:
exposure:
include: prometheus,info,refresh,health,env,restart
prometheus:
path: /api/actuator/prometheus
sensitive: false
I have enabled the restart endpoint , but still its not working . Please help me on this .
I tried the below way also , but still throwing the same issue.
<properties>
<spring.cloud-version>Hoxton.SR12</spring.cloud-version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Environment: Spring Boot 2.3.1, Java 11
I have tried out a few things already (also comparing with the sample-app by spring), but so far I have been unsuccessful in creating a WebClient that requires a ReactiveClientRegistrationRepository.
I get the following exception when starting up my spring-boot application:
required a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository'
The way I understand spring-boot-autoconfigure it should use the ReactiveOAuth2ClientAutoConfiguration, as in the yml-file the required properties are given.
Following some code-snippets, I can provide more if something is missing to get the whole context
Main-Class
#Slf4j
#SpringBootApplication
#EnableConfigurationProperties(MyAppConfigurationProperties.class)
public class MyApp{
public static void main(final String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Configuration:
#Configuration
//#Import(ReactiveOAuth2ClientAutoConfiguration.class) // in the test it works with this, but should not be required: spring-boot-autoconfigure
public class MyRestClientConfig {
#Bean
WebClient myWebClient(WebClient.Builder builder, ReactiveClientRegistrationRepository clientRegistrations) {
//content not relevant to this problem
}
}
Configuration for security
#EnableGlobalMethodSecurity(securedEnabled = true)
#EnableWebSecurity
#EnableWebFluxSecurity
public class SecurityConfig {
}
application.yml
spring:
security:
oauth2:
client:
registration:
providerid:
authorization-grant-type: "client_credentials"
client-id: "myClientId"
client-secret: "mySecret"
user-info-authentication-method: header
provider:
providerid:
token-uri: "working token-uri"
I tried with different dependencies, so some may not be required. Which dependencies are actually required?
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.security.oauth.boot</groupId>-->
<!-- <artifactId>spring-security-oauth2-autoconfigure</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.security.oauth</groupId>-->
<!-- <artifactId>spring-security-oauth2</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-oauth2-client</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.security</groupId>-->
<!-- <artifactId>spring-security-oauth2-core</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.security</groupId>-->
<!-- <artifactId>spring-security-oauth2-jose</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-webflux</artifactId>-->
<!-- </dependency>-->
In an integration-test the Spring-Boot-Application starts up
#EnableConfigurationProperties
#Import(ReactiveOAuth2ClientAutoConfiguration.class) // in the test it works with this, but should not be required: spring-boot-autoconfigure, can be omitted if added in MyRestClientConfig
#ComponentScan(basePackages = "com.mycompany")
public class ManualClientTester {
}
EDIT 1:
Debug of Positive Matches for Autoconfiguration
In test where it works:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
ReactiveOAuth2ClientAutoConfiguration matched:
- #ConditionalOnClass found required classes 'reactor.core.publisher.Flux', 'org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity', 'org.springframework.security.oauth2.client.registration.ClientRegistration' (OnClassCondition)
- NoneNestedConditions 0 matched 1 did not; NestedCondition on ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.ServletApplicationCondition not a servlet web application (ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition)
ReactiveOAuth2ClientConfigurations.ReactiveClientRegistrationRepositoryConfiguration matched:
- OAuth2 Clients Configured Condition found registered clients myClientId (ClientsConfiguredCondition)
- #ConditionalOnMissingBean (types: org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; SearchStrategy: all) did not find any beans (OnBeanCondition)
ReactiveOAuth2ClientConfigurations.ReactiveOAuth2ClientConfiguration matched:
- #ConditionalOnBean (types: org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; SearchStrategy: all) found bean 'clientRegistrationRepository' (OnBeanCondition)
ReactiveOAuth2ClientConfigurations.ReactiveOAuth2ClientConfiguration#authorizedClientRepository matched:
- #ConditionalOnMissingBean (types: org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; SearchStrategy: all) did not find any beans (OnBeanCondition)
ReactiveOAuth2ClientConfigurations.ReactiveOAuth2ClientConfiguration#authorizedClientService matched:
- #ConditionalOnMissingBean (types: org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; SearchStrategy: all) did not find any beans (OnBeanCondition)
When starting my spring boot application:
============================
CONDITIONS EVALUATION REPORT
============================
Negative matches:
-----------------
ReactiveOAuth2ClientAutoConfiguration:
Did not match:
- NoneNestedConditions 1 matched 0 did not; NestedCondition on ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.ServletApplicationCondition found 'session' scope (ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition)
Matched:
- #ConditionalOnClass found required classes 'reactor.core.publisher.Flux', 'org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity', 'org.springframework.security.oauth2.client.registration.ClientRegistration' (OnClassCondition)
EDIT 2:
After changing as suggested, I have now the following:
#EnableReactiveMethodSecurity
#EnableWebFluxSecurity
public class SecurityConfig {
}
pom.xml
<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>
Furthermore all used versions of spring-projects:
<spring-amqp.version>2.2.7.RELEASE</spring-amqp.version>
<spring-batch.version>4.2.4.RELEASE</spring-batch.version>
<spring-boot.version>2.3.1.RELEASE</spring-boot.version>
<spring-data-releasetrain.version>Neumann-SR1</spring-data-releasetrain.version>
<spring-framework.version>5.2.7.RELEASE</spring-framework.version>
<spring-hateoas.version>1.1.0.RELEASE</spring-hateoas.version>
<spring-integration.version>5.3.1.RELEASE</spring-integration.version>
<spring-kafka.version>2.5.2.RELEASE</spring-kafka.version>
<spring-ldap.version>2.3.3.RELEASE</spring-ldap.version>
<spring-restdocs.version>2.0.4.RELEASE</spring-restdocs.version>
<spring-retry.version>1.2.5.RELEASE</spring-retry.version>
<spring-security.version>5.3.3.RELEASE</spring-security.version>
<spring-session-bom.version>Dragonfruit-RELEASE</spring-session-bom.version>
<spring-ws.version>3.0.9.RELEASE</spring-ws.version>
<spring.boot.version>2.3.1.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR5</spring.cloud.version>
The problem still exists.
I ran into the same problem and noticed that the application created a ClientRegistrationRepository instead of a ReactiveClientRegistrationRepository. Somewhere in Spring boot the #EnableWebSecurity was added (we need the #EnableWebFluxSecurity in this case).
To fix the problem I've added the following property:
spring.main.web-application-type: reactive
If you're also using #SpringBootTest to test your application you also need to add the property there.
#SpringBootTest(properties = ["spring.main.web-application-type=reactive]")
or by setting the web environment to NONE
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
The reason why this happens is also explained in this answer: Error when using #EnableWebFluxSecurity in springboot
I'm still not happy about my solution, but I ended up doing the following:
#Bean
public ReactiveClientRegistrationRepository reactiveClientRegistrationRepository(OAuth2ClientProperties oAuth2ClientProperties) {
List<ClientRegistration> clientRegistrations = new ArrayList<>();
// because autoconfigure does not work for an unknown reason, here the ClientRegistrations are manually configured based on the application.yml
oAuth2ClientProperties.getRegistration()
.forEach((k, v) -> {
String tokenUri = oAuth2ClientProperties.getProvider().get(k).getTokenUri();
ClientRegistration clientRegistration = ClientRegistration
.withRegistrationId(k)
.tokenUri(tokenUri)
.clientId(v.getClientId())
.clientSecret(v.getClientSecret())
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.build();
clientRegistrations.add(clientRegistration);
});
return new InMemoryReactiveClientRegistrationRepository(clientRegistrations);
}
I use the spring-properties for OAuth and then create the ReactiveClientRegistrationRepository based on those properties.
Works this way:
#Bean
public WebClient webClient(ClientRegistrationRepository clientRegistrationRepository) {
InMemoryReactiveClientRegistrationRepository registrationRepository = new InMemoryReactiveClientRegistrationRepository(clientRegistrationRepository.findByRegistrationId("REG_ID"));
InMemoryReactiveOAuth2AuthorizedClientService clientService = new InMemoryReactiveOAuth2AuthorizedClientService(registrationRepository);
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager clientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(registrationRepository, clientService);
return WebClient.builder()
.baseUrl(BASEURL)
.filter(new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientManager))
.build();
}
Properties:
spring.security.oauth2.client.registration.REG_ID.client-id=CLIENT_ID
spring.security.oauth2.client.registration.REG_ID.client-name=CLIENT_NAME
spring.security.oauth2.client.registration.REG_ID.client-secret=SECRET
spring.security.oauth2.client.registration.REG_ID.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.REG_ID.scope=SCOPE
spring.security.oauth2.client.provider.REG_ID.issuer-uri=PATH_TO_.well-known/openid-configuration_SITE
EDIT:
Add the following before the return statement:
ServerOAuth2AuthorizedClientExchangeFilterFunction clientExchangeFilterFunction = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientManager);
clientExchangeFilterFunction.setDefaultClientRegistrationId("REG_ID");
And replace filter in the return statement with:
.filter(clientExchangeFilterFunction)
I solved this by writing this code
#Bean("oauthWebClient")
WebClient webClient(ClientRegistrationRepository clientRegistrations) {
InMemoryReactiveClientRegistrationRepository registrationRepository = new InMemoryReactiveClientRegistrationRepository(
clientRegistrations.findByRegistrationId("reg-id"));
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(
registrationRepository,
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("reg-id");
return WebClient.builder()
.filter(oauth)
.build();
}
Update:
Looks like the "user-info-authentication-method" (userInfoAuthenticationMethod) is part of the Provider and not the Registration. And please remove the double quotes too.
spring:
security:
oauth2:
client:
registration:
providerid:
authorization-grant-type: client_credentials
client-id: myClientId
client-secret: mySecret
provider:
providerid:
token-uri: <working token-uri>
user-info-authentication-method: header
Also a suggestion - to avoid possible conflicting/ incompatible dependencies, please use dependency management like this and try to have all spring boot starters. eg the spring security library comes as part of both spring-boot-starter-oauth2-client and spring-boot-starter-oauth2-resource-server:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Just these 2 dependencies should do the work: (these are picked from Gradle file, please change them to POM equivalent)
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
For tests, probably you may need this:
testImplementation 'org.springframework.security:spring-security-test:5.3.3.RELEASE'
You should not mix the two together:
#EnableWebSecurity
#EnableWebFluxSecurity
If your application is reactive, then just use #EnableWebFluxSecurity.
And coming to #EnableGlobalMethodSecurity(securedEnabled = true) , this is described here, and is recommended to remove that and use this instead:
#EnableReactiveMethodSecurity
it's difficult to provide relevant answer without a stacktrace.
Seem that Spring boot cant create ReactiveClientRegistrationRepository from your properties file.
Try to add a provider property on your client.
oauth2:
client:
registration:
registrationId:
provider: providerId
client-id: clientId
client-secret: secret
authorization-grant-type: client_credentials
ReactiveClientRepositoryRegistration Bean needs to be defined explicitly. You can refer to the spring documentation
https://docs.spring.io/spring-security/reference/reactive/oauth2/login/core.html#webflux-oauth2-login-register-reactiveclientregistrationrepository-bean
I am going to register my spring boot application to spring-boot-admin server.
Here is my SpringBootAdminApplication.java
#Configuration
#EnableAutoConfiguration
#EnableAdminServer
public class SpringBootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAdminApplication.class, args);
}
}
And pom.xml:
<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-example</artifactId>
<version>1.0.5</version>
</dependency>
</dependencies>
and application.properties
server.port = 8080
Server is running now:
Now, in client side:
properties:
spring.boot.admin.url=http://localhost:8080
info.version=#project.version#
spring.application.name=rest-module
pom.xml:
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>1.3.0</version>
</dependency>
But, when i run the spring boot from client, i get this error:
Created POST request for "http://localhost:8080/api/applications"
Setting request Accept header to [application/json, application/json, application/*+json, application/*+json]
Writing [Application [id=null, name=rest-module, managementUrl=http://Hayatloo-PC:8082, healthUrl=http://Hayatloo-PC:8082/health, serviceUrl=http://Hayatloo-PC:8082]] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#1637320b]
Failed to register application as Application [id=null, name=rest-module, managementUrl=http://Hayatloo-PC:8082, healthUrl=http://Hayatloo-PC:8082/health, serviceUrl=http://Hayatloo-PC:8082] at spring-boot-admin (http://localhost:8080/api/applications): 400 Bad Request
Why id=null ?
You messed up the versions. Try to update the client and server to the same versions. We try too keep em compatible but from 1.0.x to 1.3.x you have no chance.
Btw current version is 1.3.2.
Additional you are using the sample as dependency. This indeed works, but I wouldn't recommend it. You better setup your server as described in the guide. http://codecentric.github.io/spring-boot-admin/1.3.2/