I am writting an application using Java Spring Boot auto configure that tries to send a message to Azure EventHub using SPN for authentication without avail as i'm getting a cert issue. My code looks like this:
Environment:
Java 17
Spring Boot: solace-spring-boot-starter:2.0.0
Spring Azure: spring-cloud-azure-starter-integration-eventhubs:5.13.0
EventHubProducerService
package com.mysample.producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.azure.messaging.eventhubs.EventData;
import com.azure.messaging.eventhubs.EventHubProducerClient;
import java.util.Collections;
@Service
public class EventHubProducerService {
@Autowired
private EventHubProducerClient producerClient;
public void sendEventHubMessage(String message){
producerClient.send(Collections.singletonList(new EventData(message)));
log.info("message sent successfully to EventHub");
}
}
application.yml
spring.cloud.azure:
eventhubs:
namespace: "<namespaceName>"
eventHubName: "<eventHubName>"
credential:
client-id: "<SPN ClientId>"
client-secret: "<SPN SecretValue>"
profile:
tenant-id: "<TenantId>"
The error is the following when sendEventHubMessage("Hello World") gets executed:
2024-07-11T14:57:45.612-04:00 WARN 9632 --- [ctor-http-nio-1] r.netty.http.client.HttpClientConnect : [330ebfae, L:/<ip>:<port> - R:login.microsoftonline.com/<ip>:443] The connection observed an error
javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem
at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.handshakeException(ReferenceCountedOpenSslEngine.java:1927) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.wrap(ReferenceCountedOpenSslEngine.java:848) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at java.base/javax.net.ssl.SSLEngine.wrap(SSLEngine.java:564) ~[na:na]
at io.netty.handler.ssl.SslHandler.wrap(SslHandler.java:1129) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.SslHandler.wrapNonAppData(SslHandler.java:973) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1509) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.SslHandler.decodeNonJdkCompatible(SslHandler.java:1347) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1387) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:530) ~[netty-codec-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:469) ~[netty-codec-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290) ~[netty-codec-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1407) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.111.Final.jar:4.1.111.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:994) ~[netty-common-4.1.111.Final.jar:4.1.111.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.111.Final.jar:4.1.111.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.111.Final.jar:4.1.111.Final]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439) ~[na:na]
at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) ~[na:na]
at java.base/sun.security.validator.Validator.validate(Validator.java:264) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:285) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144) ~[na:na]
at io.netty.handler.ssl.EnhancingX509ExtendedTrustManager.checkServerTrusted(EnhancingX509ExtendedTrustManager.java:69) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback.verify(ReferenceCountedOpenSslClientContext.java:235) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.ReferenceCountedOpenSslContext$AbstractCertificateVerifier.verify(ReferenceCountedOpenSslContext.java:797) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.internal.tcnative.CertificateVerifierTask.runTask(CertificateVerifierTask.java:36) ~[netty-tcnative-classes-2.0.65.Final.jar:2.0.65.Final]
at io.netty.internal.tcnative.SSLTask.run(SSLTask.java:48) ~[netty-tcnative-classes-2.0.65.Final.jar:2.0.65.Final]
at io.netty.internal.tcnative.SSLTask.run(SSLTask.java:42) ~[netty-tcnative-classes-2.0.65.Final.jar:2.0.65.Final]
at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.runAndResetNeedTask(ReferenceCountedOpenSslEngine.java:1533) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.access$700(ReferenceCountedOpenSslEngine.java:94) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.ReferenceCountedOpenSslEngine$TaskDecorator.run(ReferenceCountedOpenSslEngine.java:1505) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1649) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1495) ~[netty-handler-4.1.111.Final.jar:4.1.111.Final]
... 21 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[na:na]
at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:na]
at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) ~[na:na]
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434) ~[na:na]
... 36 common frames omitted
Any ideas? if i connect to EvenHub using a connection-string it works fine, only when i'm using SPN does it give me this error, i presume i have to get a cert somewhere in azure and import it to the java cacert?
Here, you need to change the above application.yml
file format and also Additionally, needed slight adjustment as you can check that in the below steps.
application.yml:
spring:
cloud:
azure:
credential:
client-id: "<SPN ClientId>"
client-secret: "<SPN SecretValue>"
tenant-id: "<TenantId>"
eventhubs:
namespace: "<namespaceName>"
producer:
event-hub-name: "<eventHubName>"
Check this below application that picks up the EventHub by a configuration class.
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.azure.messaging.eventhubs.EventHubClientBuilder;
import com.azure.messaging.eventhubs.EventHubProducerClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EventHubConfig {
@Value("${spring.cloud.azure.credential.client-id}")
private String clientId;
@Value("${spring.cloud.azure.credential.client-secret}")
private String clientSecret;
@Value("${spring.cloud.azure.credential.tenant-id}")
private String tenantId;
@Value("${spring.cloud.azure.eventhubs.namespace}")
private String namespace;
@Value("${spring.cloud.azure.eventhubs.producer.event-hub-name}")
private String eventHubName;
@Bean
public EventHubProducerClient producerClient() {
ClientSecretCredential credential = new ClientSecretCredentialBuilder()
.clientId(clientId)
.clientSecret(clientSecret)
.tenantId(tenantId)
.build();
return new EventHubClientBuilder()
.credential(namespace, eventHubName, credential)
.buildProducerClient();
}
}
EventHubConfig
to set up the EventHub producer client using the SPN credentials.Application tree:
my-spring-boot-app/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── com/
│ │ │ │ ├── mysample/
│ │ │ │ │ ├── MySpringBootApplication.java
│ │ │ │ │ ├── config/
│ │ │ │ │ │ └── EventHubConfig.java
│ │ │ │ │ ├── consumer/
│ │ │ │ │ │ └── SomeClass.java
│ │ │ │ │ ├── producer/
│ │ │ │ │ │ └── EventHubProducerService.java
│ │ ├── resources/
│ │ │ ├── application.yml
│ │ │ └── logback-spring.xml (optional, for logging configuration)
├── pom.xml
Application runs successfully:
SPN setup:
EventHub: