Я пишу приложение с использованием автоматической настройки Java Spring Boot, которое безуспешно пытается отправить сообщение в Azure EventHub с использованием SPN для аутентификации, поскольку у меня возникает проблема с сертификатом. Мой код выглядит следующим образом:
Среда:
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>"
При выполнении sendEventHubMessage("Hello World") возникает следующая ошибка:
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
Есть идеи? если я подключаюсь к EvenHub с помощью строки подключения, все работает нормально, только когда я использую SPN, выдает ли мне эту ошибку, я полагаю, мне нужно получить сертификат где-то в Azure и импортировать его в Java-cacert?
Здесь вам нужно изменить указанный выше application.yml
формат файла, а также, кроме того, необходима небольшая корректировка, как вы можете проверить это, выполнив следующие шаги.
приложение.yml:
spring:
cloud:
azure:
credential:
client-id: "<SPN ClientId>"
client-secret: "<SPN SecretValue>"
tenant-id: "<TenantId>"
eventhubs:
namespace: "<namespaceName>"
producer:
event-hub-name: "<eventHubName>"
Проверьте это приложение ниже, которое подбирает EventHub по классу конфигурации.
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
для настройки клиента-производителя EventHub с использованием учетных данных SPN.Дерево приложений:
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
Приложение работает успешно:
Настройка SPN:
Центр событий:
Спасибо, к сожалению, я получаю эту ошибку, используя «имя-концентратора событий» в подходе к конфигурации «производитель»: «org.springframework.beans.factory.BeanCreationException: ошибка при создании bean-компонента с именем eventHubProducerAsyncClient, определенным в ресурсе пути к классу [com/azure] /spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfiguration$SharedProducerConnectionConfiguration.class]: не удалось создать экземпляр [com.azure.messaging.eventhubs.EventHubProducerAsyncClient]: фабричный метод 'eventHubProducerA syncClient' выдал исключение с сообщением: «eventHubName» не может быть пустой строкой».