Provider ID must be specified for client registration 'azure'? - spring

When I upgrade to Spring Boot 2.6.6, the app shows error like this:
I have this dependencies on my pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${spring-cloud-azure.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
this configuration on my application.properties:
azure.activedirectory.tenant-id=*******.
spring.security.oauth2.client.registration.azure.client-id=*********.
azure.activedirectory.client-id=************.
spring.security.oauth2.client.registration.azure.client-secret=*************.
azure.activedirectory.client-secret=*************.
and the security configuration class is
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").authenticated();
http.authorizeRequests().anyRequest().permitAll();
http.addFilterBefore(jwtTokenFilterBean(),UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);
http.csrf().disable() ;
}
and this is the bean class
#Bean
public FilterRegistrationBean<CorsFilter> simpleCorsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new
CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
when I try to run the application, give me this error:
Caused by: java.lang.IllegalStateException: Provider ID must be specified for client registration 'azure'
at org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter.getBuilder(OAuth2ClientPropertiesRegistrationAdapter.java:95) ~[spring-boot-autoconfigure-2.6.6.jar:2.6.6]
at org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter.getClientRegistration(OAuth2ClientPropertiesRegistrationAdapter.java:61) ~[spring-boot-autoconfigure-2.6.6.jar:2.6.6]
at org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter.lambda$getClientRegistrations$0(OAuth2ClientPropertiesRegistrationAdapter.java:53) ~[spring-boot-autoconfigure-2.6.6.jar:2.6.6]
at java.util.HashMap.forEach(Unknown Source) ~[?:1.8.0_65]
why would this happen? what should I do to fix this problem?
Thanks in advance.

Please check if application properties has the provider configured and having correct scopes for the api required.
Provided below some application properties.Please check for the missing ones or if everything is correct.
ex:application.properties
spring.security.oauth2.client.registration.azure.client-id=XXXXXXXXXX
spring.security.oauth2.client.registration.azure.client-secret=XXXXXXXXXX
spring.security.oauth2.client.registration.azure.scope=openid,profile,email,offline_access //here provide required scopes ex:
spring.security.oauth2.client.registration.azure.redirect-uri-template=’{baseUrl}/login/oauth2/code/{registrationId}’
spring.security.oauth2.client.registration.azure.client-name=xxxxxxxxx
spring.security.oauth2.client.registration.azure.provider=xxxxxxxxx
spring.security.oauth2.client.registration.azure.client-authentication-method=basic
spring.security.oauth2.client.registration. azure.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider. azure.authorization-uri=https://login.microsoftonline.com/<tenantid>/oauth2/v2/authorize
spring.security.oauth2.client.provider. azure.token-uri= https://login.microsoftonline.com/xxxxxxxxxxxxxx/oauth2/v2/token
spring.security.oauth2.client.provider.xxxxxxxxx.user-info-uri=https://login.microsoftonline.com/xxxxxxxxxxxxxx/openid/userinfo
spring.security.oauth2.client.provider. azure.user-name-attribute=name
spring.security.oauth2.client.provider. azure.user-info-authentication-method=header
spring.security.oauth2.client.provider. azure.jwk-set-uri=https://login.microsoftonline.com/xxxxxxxxxxxxxx/discovery/v2/keys
If the api is graph api , the scope can be https://graph.microsoft.com/user.read and if it is not graph api make sure to expose an api and give proper permissions and grant admin consent for the same .
Also please check the manifest to see accesstokenacceptedversion , tr y changing it to 2 if it is null or 1 befor or vice versa and make the configuration for the same i.e;
if v2 the property spring.security.oauth2.client.provider. azure.authorization-uri=https://login.microsoftonline.com/<tenantid>/oauth2/v2/authorize or
if v1
spring.security.oauth2.client.provider.azure.authorization-uri=https://login.microsoftonline.com/<tenantid>/oauth2/authorize
References:
spring boot -stack overflow
-reduce-the-standard-scope-authorization-requst-spring-boot-sends-to-azure
clientregistrationrepository-bean-is-not-found-SO

Related

Unable to Access Spring Boot Actuator Endpoints

I try to use actuator endpoints in spring boot. The application runs smoothly. My pom file is given below:
<?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.7.3</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.luv2code.springboot</groupId>
<artifactId>thymeleafdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>thymeleafdemo</name>
<description>Ab Jove principium</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- umumi bağımlılıklar -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Here is the content of the application.properties file:
spring.datasource.url=DATABASE_URL
spring.datasource.username=USERNAME
spring.datasource.password=PASSWORD
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
# Spring Data JPA properties
spring.data.jpa.repository.packages=com.yok.springboot.thymeleafdemo.dao
spring.data.jpa.entity.packages-to-scan=com.yok.springboot.thymeleafdemo.entity
spring.jpa.hibernate.use-new-id-generator-mappings=false
spring.jpa.hibernate.ddl-auto=create
#
# JDBC properties
#
app.datasource.jdbc-url=DATABASE_URL
app.datasource.username=USERNAME
app.datasource.password=PASSWORD
#
# Hikari properties
spring.datasource.hikari.maximumPoolSize=10
spring.datasource.hikari.idleTimeout=2000
spring.datasource.hikari.poolName=SpringBootJPAHikariCP
spring.datasource.hikari.maxLifetime=20000
spring.datasource.hikari.connectionTimeout=30000
# Actuator properties
# expose all endpoints:
management.endpoints.web.exposure.include=*
management.endpoints.beans.enabled=true
management.endpoints.web.exposure.include=info,env
management.endpoint.env.enabled=true
management.endpoint.info.enabled=true
management.endpoints.enabled-by-default=true
This is the start of my Spring Boot Application:
package com.yok.springboot.thymeleafdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ThymeleafdemoApplication {
public static void main(String[] args) {
SpringApplication.run(ThymeleafdemoApplication.class, args);
}
}
Whenever I try to connect /health,/Info or /metrics endpoint by typing http://localhost:8080/health, the HTTP request transfers to http://localhost:8080/showMyLoginPage. I cannot reach endpoint. How can I solve this? Thanks in advance.
Edit -1
Mr. Fatih demands me to observe the result "http://localhost:8080/actuator" and this picture reveals: the picture
Here is the console output of the application:
https://drive.google.com/file/d/1zYP1qe-Ohbcan93ZO6rqjxX9LqlGiIIg/view?usp=sharing
Edit-2
The problem is partly solved. The actuators are available after the login of the application. But the problem is, after the login page, the homepage appears. All actuators are working, however, whenever I hit http://localhost:8080/actuator/health URL, {"status":"DOWN"} appears at the screen. Here is the console output taken during this operation:
reached urls:
http://localhost:8080/showMyLoginPage
http://localhost:8080/students/list/page/1
http://localhost:8080/actuator/health
http://localhost:8080/actuator/heapdump
http://localhost:8080/actuator/env
console output: (exception has thrown)
java.lang.IllegalArgumentException: dataSource or dataSourceClassName
or jdbcUrl is required. at
com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:1029)
~[HikariCP-4.0.3.jar:na] at
com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:109)
~[HikariCP-4.0.3.jar:na] at
org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:159)
~[spring-jdbc-5.3.22.jar:5.3.22] at
org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:117)
~[spring-jdbc-5.3.22.jar:5.3.22] at
org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80)
~[spring-jdbc-5.3.22.jar:5.3.22] at
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:330)
~[spring-jdbc-5.3.22.jar:5.3.22] at
org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator.getProduct(DataSourceHealthIndicator.java:122)
~[spring-boot-actuator-2.7.3.jar:2.7.3] at
org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator.doDataSourceHealthCheck(DataSourceHealthIndicator.java:105)
~[spring-boot-actuator-2.7.3.jar:2.7.3] at
org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator.doHealthCheck(DataSourceHealthIndicator.java:100)
~[spring-boot-actuator-2.7.3.jar:2.7.3]
Edit-3
Mr Fatih pointed out some of the changes at the WebSecurityConfiguration. I have changed the code and I am getting this error:
java.lang.IllegalStateException: permitAll only works with either
HttpSecurity.authorizeRequests() or
HttpSecurity.authorizeHttpRequests(). Please define one or the other
but not both.
Here is the change I've made:
/*
* import section have omitted for brevity
*/
#Configuration
#EnableWebSecurity
public class DemoSecurityConfig {
/*
* other codes have omitted for brevity
*/
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
(authz) -> authz.antMatchers("/actuator/**").permitAll().anyRequest().authenticated());
http.authorizeRequests(
configurer -> configurer.antMatchers("/**").hasRole("ADMIN").antMatchers("/**").hasRole("USER"))
.formLogin(configurer -> configurer.loginPage("/showMyLoginPage")
.loginProcessingUrl("/authenticateTheUser").permitAll())
.logout(configurer -> configurer.permitAll())
.exceptionHandling(configurer -> configurer.accessDeniedPage("/access-denied"));
return http.build();
}
}
Here is the console output: https://drive.google.com/file/d/1CtjRBHXVRqirZ0Vt_3FEhx_N9oEwyfFZ/view
You are using the spring-security package for application security. So when you want to access your /actuator endpoints, you need to log in first. If you want to access your /actuator endpoints without logging in, you must configure a security configuration. With the following configuration, you can exclude all endpoints starting with /actuator from security.
#EnableWebSecurity
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/actuator/**").permitAll().anyRequest().authenticated();
}
}
Since WebSecurityConfigurerAdapter has been deprecated, you can do this as well.
#Configuration
public class SecurityConfiguration {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(autz -> autz
.mvcMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}
** is a wildcard definition and allows you to access this endpoint without logging in, regardless of what comes after the actuator part.
Please Consider using a version for your dependency as far as i remember 1.9.5 RELEASE or 1.9.5 might help in this context , i had the same issue a year ago.

How can I use client_credentials to access another oauth2 resource from spring cloud gateway

I want to use client credentials flow to access an OAuth protected resource from spring cloud gateway
There is no authentication needed to hit the gateway end point
The resource is OAuth2 protected and I have to use client credentials flow
Based on the matching PATH and HEADERS the request will be redirected to the corresponding service using cloud gateway routes in props file
I need to get the OAuth token from an Auth service and pass the bearer token in the call to the protected resource
Observations:
The token end point is not called for a token
I am getting 403 Forbidden error from the protected resource
I have tried many solutions provided in stackoverflow but I am not able to resolve the issue. What am I missing here?
Configuration file:
spring:
main.web-application-type: reactive
security:
oauth2:
client:
registration:
my-app:
client-id: client-id
client-secret: client-secret
authorization-grant-type: client_credentials
provider:
my-app:
token-uri: https://xxxxxxxx.com/oauth2/token
SecurityConfig:
#EnableWebFluxSecurity
public class SecurityConfig {
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http.oauth2Client().and().build();
}
#Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build();
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
#Bean
public WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
return WebClient.builder().filter(oauth).build();
}
}
App:
#SpringBootApplication(
exclude = {
SecurityAutoConfiguration.class
})
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
POM:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>4.1.72.Final</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.0.1</version>
</dependency>
</dependencies>

How to send mail using Spring Batch

I want to send mail after processor. These is my step configuration:
public Step remindByMail() {
return stepBuilderFactory
.get("remindByMail")
.<Customer, SimpleMailMessage> chunk(1)
.reader(getCustomerList())
.processor(new MailProcessor())
.writer(new SendMail())
.build();
}
public class MailProcessor implements ItemProcessor<Customer, SimpleMailMessage> {
private String from = "aaa#oku.com";
#Override
public SimpleMailMessage process(Customer customer) throws Exception {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo("duyetpt#oku.com");
message.setSubject("Welcome " + customer.getUsername());
message.setText(customer.getInfo());
return message;
}
}
public class SendMail implements ItemWriter<SimpleMailMessage> {
#Override
public void write(List<? extends SimpleMailMessage> messages) throws Exception {
messages.stream().forEach((message)->mailSender.send(message));
}
}
And I have set these properties in application.properties file,
spring.mail.default-encoding=UTF-8
spring.mail.protocol=smtp
spring.mail.host=195.179.79.52
spring.mail.port=25
spring.mail.username=admin
spring.mail.password=admin
spring.mail.properties.mail.smtp.auth=true
My pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-task</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
However, I got the error:
org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: No authentication mechanisms supported by both server and client
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:440)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:323)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:312)
.....
Caused by: javax.mail.AuthenticationFailedException: No authentication mechanisms supported by both server and client
at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:880)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:780)
.....
What should I do to send mail using Spring Batch?
Its my guess by your error message - No authentication mechanisms supported by both server and client that below properties needs to be removed from your configuration.
spring.mail.username=admin
spring.mail.password=admin
spring.mail.properties.mail.smtp.auth=true
In Spring Boot + Batch , I send emails using my organization's server without these properties as user name & passwords are not needed because program has to reside in organization network & that is the only security.
Its altogether a different story if one is trying to use - gmail , yahoo etc.

Spring boot 2 reactive web websocket conflict with datarest

I'm using spring boot 2 to create a project and use websocket using reactive web dependency. My application is worked correctly until I add datarest dependency. after I add datarest dependency application give
' failed: Error during WebSocket handshake: Unexpected response code: 404
is any way to resolve this conflict?.
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.integration/spring-integration-file -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
WebSocketConfiguration
#Configuration
public class WebSocketConfiguration {
#Bean
public IntegrationFlow fileFlow(PublishSubscribeChannel channel, #Value("file://${HOME}/Desktop/in") File file) {
FileInboundChannelAdapterSpec in = Files.inboundAdapter(file).autoCreateDirectory(true);
return IntegrationFlows.from(
in,
p -> p.poller(pollerFactory -> {
return pollerFactory.fixedRate(1000);
})
).channel(channel).get();
}
#Bean
#Primary
public PublishSubscribeChannel incomingFilesChannel() {
return new PublishSubscribeChannel();
}
#Bean
public WebSocketHandlerAdapter webSocketHandlerAdapter() {
return new WebSocketHandlerAdapter();
}
#Bean
public WebSocketHandler webSocketHandler(PublishSubscribeChannel channel) {
return session -> {
Map<String, MessageHandler> connections = new ConcurrentHashMap<>();
Flux<WebSocketMessage> publisher = Flux.create((Consumer<FluxSink<WebSocketMessage>>) fluxSink -> {
connections.put(session.getId(), new ForwardingMessageHandler(session, fluxSink));
channel.subscribe(connections.get(session.getId()));
}).doFinally(signalType -> {
channel.unsubscribe(connections.get(session.getId()));
connections.remove(session.getId());
});
return session.send(publisher);
};
}
#Bean
public HandlerMapping handlerMapping(WebSocketHandler webSocketHandler) {
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(10);
handlerMapping.setUrlMap(Collections.singletonMap("/ws/files", webSocketHandler));
return handlerMapping;
}
}
spring-boot-starter-data-rest brings spring-boot-starter-web as a transitive dependency (so basically Spring MVC). This makes Spring Boot configure your application as a Spring MVC web application.
Spring Data REST does not currently support Spring WebFlux (see this issue for more information on that).
Your only choice is to remove the Spring Data REST dependency, as you can't have both Spring MVC and Spring WebFlux in the same Spring Boot application.

Spring Boot + Apache Camel HTTP component crashes at start: missing EmbeddedServletContainerFactory bean

Just taking Spring-Boot for a spin and decided to mix in Camel because I need some arcane Headers work in the rest client I am working on. Setting up the application was fine until I added the camel-http component to my POM, then I get this on init:
Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
I've havent got the first idea of where to start to look for the problem. I gather Spring Boot will look up the classpath and try to wire stuff up, so is there a way for the to block the Camel packages from being acted on or something of the sort?
Complete log of the start up in this Gist
Here's my main aplication code:
#ComponentScan
#EnableAutoConfiguration
public class Application {
private static ApplicationContext ctx;
public static void main(String[] args) throws Exception {
ctx = SpringApplication.run(Application.class, args);
//Right outta Spring 4 docs
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
//---
// FIXME: ugly hack to allow some POC woek while wait for proper Camel/Spring4 unit tests fix.
Application app = new Application();
app.executeTests();
}
/**
* Dev QOL - unit tests are broken for now, see:
* https://issues.apache.org/jira/browse/CAMEL-7074
* <p/>
* Waiting for fix (Too lay to checkout and build my own Camel)
*/
private void executeTests() throws Exception {
testAuth();
}
#Bean
DefaultCamelContext camelCtx() throws Exception {
DefaultCamelContext camel = new DefaultCamelContext();
camel.addRoutes(cryptsyRouteBuilder());
camel.start();
return camel;
}
#Bean
public CryptsyRouteBuilder cryptsyRouteBuilder() throws Exception{
CryptsyRouteBuilder bean = new CryptsyRouteBuilder();
bean.setCryptsy(cryptsy());
return bean;
}
#Bean
public Cryptsy cryptsy() throws IOException {
return new Cryptsy();
}
protected void testAuth() throws Exception {
ProducerTemplate producer = camelCtx().createProducerTemplate();
producer.requestBody("direct:start", "Why, hullo there", String.class);
}
}
And my POM dependencies:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>0.5.0.BUILD-SNAPSHOT</version>
</parent>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-actuator</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- Camel -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-javaconfig</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-quartz</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http</artifactId>
<version>${camel.version}</version>
</dependency>
<!-- Assorted -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
<properties>
<start-class>xxx.xxxx.Application</start-class>
<camel.version>2.12.2</camel.version>
</properties>
The exception is telling you that Spring Boot thinks you want to build a web server, but can't find the right dependencies on the classpath. The most obvious reason for that in your case would be that the HTTP dependencies you added included Servlet APIs. I see no reason why you need that for a client app, but only you would know whether you need it or not. Maybe you can exclude it?
If you do need the Servlet dependencies and just want to explicitly tell Boot that you aren't creating a web application you can set the property spring.main.web_environment=false, or use the SpringApplication (or SpringApplicationBuilder) API directly to set the same flag. See docs here for background information.

Resources