From 895075f9e55cb4474110283a66333365c5ceae1d Mon Sep 17 00:00:00 2001
From: jason plumb <75337021+breedx-splk@users.noreply.github.com>
Date: Tue, 7 Mar 2023 10:54:26 -0800
Subject: [PATCH] Add TlsConfigHelper for additional TLS configurability
(#5246)
* add TlsConfigHelper for additional TLS configurability and wire up internal builders.
* add javadoc and spotless
* add keys for "validity" testing.
* fix tests
* fix tests
* address code review comments
* fix typo
* allow keymanager to be nullable.
* fix test
* so....much...null......away
* backfill tests
* checkstyle
* test coverage
* address code review comments
---
.../exporter/internal/TlsConfigHelper.java | 197 +++++++++++++++++
.../exporter/internal/TlsUtil.java | 2 +-
.../internal/grpc/GrpcExporterBuilder.java | 33 +--
.../internal/grpc/ManagedChannelUtil.java | 71 +++----
.../okhttp/OkHttpExporterBuilder.java | 49 +++--
.../internal/TlsConfigHelperTest.java | 201 ++++++++++++++++++
.../jaeger/JaegerGrpcSpanExporterBuilder.java | 4 +-
.../jaeger/JaegerGrpcSpanExporterTest.java | 17 +-
.../OtlpHttpMetricExporterBuilder.java | 4 +-
.../trace/OtlpHttpSpanExporterBuilder.java | 4 +-
.../OtlpGrpcMetricExporterBuilder.java | 4 +-
.../trace/OtlpGrpcSpanExporterBuilder.java | 4 +-
.../OtlpHttpLogRecordExporterBuilder.java | 4 +-
.../OtlpGrpcLogRecordExporterBuilder.java | 4 +-
.../AbstractGrpcTelemetryExporterTest.java | 12 +-
.../AbstractHttpTelemetryExporterTest.java | 8 +-
...anagedChannelTelemetryExporterBuilder.java | 27 +--
.../sampler/DefaultGrpcServiceBuilder.java | 26 +--
.../DefaultGrpcServiceBuilderTest.java | 9 +-
19 files changed, 524 insertions(+), 156 deletions(-)
create mode 100644 exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsConfigHelper.java
create mode 100644 exporters/common/src/test/java/io/opentelemetry/exporter/internal/TlsConfigHelperTest.java
diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsConfigHelper.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsConfigHelper.java
new file mode 100644
index 00000000000..ce5555e83d7
--- /dev/null
+++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsConfigHelper.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.internal;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.logging.Logger;
+import javax.annotation.Nullable;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Utility class to help with management of TLS related components. This class is ultimately
+ * responsible for enabling TLS via callbacks passed to the configure[...]() methods. This class is
+ * only intended for internal OpenTelemetry exporter usage and should not be used by end-users.
+ *
+ *
This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public class TlsConfigHelper {
+
+ private static final Logger logger = Logger.getLogger(TlsConfigHelper.class.getName());
+
+ private final TlsUtility tlsUtil;
+
+ @Nullable private X509KeyManager keyManager;
+ @Nullable private X509TrustManager trustManager;
+ @Nullable private SSLSocketFactory sslSocketFactory;
+
+ public TlsConfigHelper() {
+ this(new TlsUtility() {});
+ }
+
+ @VisibleForTesting
+ TlsConfigHelper(TlsUtility tlsUtil) {
+ this.tlsUtil = tlsUtil;
+ }
+
+ /** Sets the X509TrustManager. */
+ public TlsConfigHelper setTrustManager(X509TrustManager trustManager) {
+ this.trustManager = trustManager;
+ return this;
+ }
+
+ /**
+ * Creates a new X509TrustManager from the given cert content.
+ *
+ * @param trustedCertsPem Certificate in PEM format.
+ * @return this
+ */
+ public TlsConfigHelper createTrustManager(byte[] trustedCertsPem) {
+ try {
+ this.trustManager = tlsUtil.trustManager(trustedCertsPem);
+ } catch (SSLException e) {
+ throw new IllegalStateException(
+ "Error creating X509TrustManager with provided certs. Are they valid X.509 in PEM format?",
+ e);
+ }
+ return this;
+ }
+
+ /**
+ * Creates a new X509KeyManager from the given private key and certificate, both in PEM format.
+ *
+ * @param privateKeyPem Private key content in PEM format.
+ * @param certificatePem Certificate content in PEM format.
+ * @return this
+ */
+ public TlsConfigHelper createKeyManager(byte[] privateKeyPem, byte[] certificatePem) {
+ try {
+ if (keyManager != null) {
+ logger.warning(
+ "Previous X509 Key manager is being replaced. This is probably an error and should only be set once.");
+ }
+ keyManager = tlsUtil.keyManager(privateKeyPem, certificatePem);
+ return this;
+ } catch (SSLException e) {
+ throw new IllegalStateException(
+ "Error creating X509KeyManager with provided certs. Are they valid X.509 in PEM format?",
+ e);
+ }
+ }
+
+ /**
+ * Assigns the X509KeyManager.
+ *
+ * @return this
+ */
+ public TlsConfigHelper setKeyManager(X509KeyManager keyManager) {
+ if (this.keyManager != null) {
+ logger.warning(
+ "Previous X509 Key manager is being replaced. This is probably an error and should only be set once.");
+ }
+ this.keyManager = keyManager;
+ return this;
+ }
+
+ /**
+ * Sets the SSLSocketFactory, which is passed into the callback within
+ * configureWithSocketFactory().
+ */
+ public TlsConfigHelper setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
+ this.sslSocketFactory = sslSocketFactory;
+ return this;
+ }
+
+ /**
+ * Functional wrapper type used in configure methods. Exists primarily to declare checked
+ * SSLException.
+ */
+ public interface SslSocketFactoryConfigurer {
+ void configure(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)
+ throws SSLException;
+ }
+
+ /**
+ * Functional wrapper type used in configure methods. Exists primarily to declare checked
+ * SSLException.
+ */
+ public interface KeyManagerConfigurer {
+ void configure(X509TrustManager trustManager, @Nullable X509KeyManager keyManager)
+ throws SSLException;
+ }
+
+ /**
+ * Configures TLS by invoking the given callback with the X509TrustManager and X509KeyManager. If
+ * the trust manager or key manager have not yet been configured, this method does nothing.
+ */
+ public void configureWithKeyManager(KeyManagerConfigurer configurer) {
+ if (trustManager == null) {
+ return;
+ }
+ try {
+ configurer.configure(trustManager, keyManager);
+ } catch (SSLException e) {
+ wrapException(e);
+ }
+ }
+
+ /**
+ * Configures TLS by invoking the provided consumer with a new SSLSocketFactory and the
+ * preconfigured X509TrustManager. If the trust manager has not been configured, this method does
+ * nothing.
+ */
+ public void configureWithSocketFactory(SslSocketFactoryConfigurer configurer) {
+ if (trustManager == null) {
+ warnIfOtherComponentsConfigured();
+ return;
+ }
+
+ try {
+ SSLSocketFactory sslSocketFactory = this.sslSocketFactory;
+ if (sslSocketFactory == null) {
+ sslSocketFactory = tlsUtil.sslSocketFactory(keyManager, trustManager);
+ }
+ configurer.configure(sslSocketFactory, trustManager);
+ } catch (SSLException e) {
+ wrapException(e);
+ }
+ }
+
+ private static void wrapException(SSLException e) {
+ throw new IllegalStateException(
+ "Could not configure TLS connection, are certs in valid X.509 in PEM format?", e);
+ }
+
+ private void warnIfOtherComponentsConfigured() {
+ if (sslSocketFactory != null) {
+ logger.warning("sslSocketFactory has been configured without an X509TrustManager.");
+ return;
+ }
+ if (keyManager != null) {
+ logger.warning("An X509KeyManager has been configured without an X509TrustManager.");
+ }
+ }
+
+ // Exists for testing
+ interface TlsUtility {
+ default SSLSocketFactory sslSocketFactory(
+ @Nullable X509KeyManager keyManager, X509TrustManager trustManager) throws SSLException {
+ return TlsUtil.sslSocketFactory(keyManager, trustManager);
+ }
+
+ default X509TrustManager trustManager(byte[] trustedCertificatesPem) throws SSLException {
+ return TlsUtil.trustManager(trustedCertificatesPem);
+ }
+
+ default X509KeyManager keyManager(byte[] privateKeyPem, byte[] certificatePem)
+ throws SSLException {
+ return TlsUtil.keyManager(privateKeyPem, certificatePem);
+ }
+ }
+}
diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsUtil.java
index 83d9d89f2f1..2be05aed694 100644
--- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsUtil.java
+++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsUtil.java
@@ -89,7 +89,7 @@ public static SSLSocketFactory sslSocketFactory(
}
/**
- * Creates {@link KeyManager} initiaded by keystore containing single private key with matching
+ * Creates {@link KeyManager} initiated by keystore containing single private key with matching
* certificate chain.
*/
public static X509KeyManager keyManager(byte[] privateKeyPem, byte[] certificatePem)
diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/GrpcExporterBuilder.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/GrpcExporterBuilder.java
index b77d825e324..cade0f018ca 100644
--- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/GrpcExporterBuilder.java
+++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/GrpcExporterBuilder.java
@@ -14,7 +14,7 @@
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
-import io.opentelemetry.exporter.internal.TlsUtil;
+import io.opentelemetry.exporter.internal.TlsConfigHelper;
import io.opentelemetry.exporter.internal.marshal.Marshaler;
import io.opentelemetry.exporter.internal.okhttp.OkHttpUtil;
import io.opentelemetry.exporter.internal.retry.RetryInterceptor;
@@ -29,9 +29,6 @@
import java.util.function.BiFunction;
import java.util.function.Supplier;
import javax.annotation.Nullable;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
@@ -55,9 +52,7 @@ public class GrpcExporterBuilder {
private URI endpoint;
private boolean compressionEnabled = false;
private final Map headers = new HashMap<>();
- @Nullable private byte[] trustedCertificatesPem;
- @Nullable private byte[] privateKeyPem;
- @Nullable private byte[] certificatePem;
+ private final TlsConfigHelper tlsConfigHelper = new TlsConfigHelper();
@Nullable private RetryPolicy retryPolicy;
private Supplier meterProviderSupplier = GlobalOpenTelemetry::getMeterProvider;
@@ -103,14 +98,13 @@ public GrpcExporterBuilder setCompression(String compressionMethod) {
return this;
}
- public GrpcExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- this.trustedCertificatesPem = trustedCertificatesPem;
+ public GrpcExporterBuilder configureTrustManager(byte[] trustedCertificatesPem) {
+ tlsConfigHelper.createTrustManager(trustedCertificatesPem);
return this;
}
- public GrpcExporterBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- this.privateKeyPem = privateKeyPem;
- this.certificatePem = certificatePem;
+ public GrpcExporterBuilder configureKeyManager(byte[] privateKeyPem, byte[] certificatePem) {
+ tlsConfigHelper.createKeyManager(privateKeyPem, certificatePem);
return this;
}
@@ -139,20 +133,7 @@ public GrpcExporter build() {
clientBuilder.callTimeout(Duration.ofNanos(timeoutNanos));
- if (trustedCertificatesPem != null) {
- try {
- X509TrustManager trustManager = TlsUtil.trustManager(trustedCertificatesPem);
- X509KeyManager keyManager = null;
- if (privateKeyPem != null && certificatePem != null) {
- keyManager = TlsUtil.keyManager(privateKeyPem, certificatePem);
- }
- clientBuilder.sslSocketFactory(
- TlsUtil.sslSocketFactory(keyManager, trustManager), trustManager);
- } catch (SSLException e) {
- throw new IllegalStateException(
- "Could not set trusted certificates, are they valid X.509 in PEM format?", e);
- }
- }
+ tlsConfigHelper.configureWithSocketFactory(clientBuilder::sslSocketFactory);
String endpoint = this.endpoint.resolve(grpcEndpointPath).toString();
if (endpoint.startsWith("http://")) {
diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/ManagedChannelUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/ManagedChannelUtil.java
index ce8972b6c61..df2b3141d78 100644
--- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/ManagedChannelUtil.java
+++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/ManagedChannelUtil.java
@@ -12,6 +12,7 @@
import io.grpc.ManagedChannelBuilder;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyChannelBuilder;
+import io.netty.handler.ssl.SslContext;
import io.opentelemetry.exporter.internal.TlsUtil;
import io.opentelemetry.exporter.internal.retry.RetryPolicy;
import io.opentelemetry.exporter.internal.retry.RetryUtil;
@@ -46,47 +47,45 @@ public final class ManagedChannelUtil {
*/
public static void setClientKeysAndTrustedCertificatesPem(
ManagedChannelBuilder> managedChannelBuilder,
- @Nullable byte[] privateKeyPem,
- @Nullable byte[] certificatePem,
- byte[] trustedCertificatesPem)
+ X509TrustManager tmf,
+ @Nullable X509KeyManager kmf)
throws SSLException {
requireNonNull(managedChannelBuilder, "managedChannelBuilder");
- requireNonNull(trustedCertificatesPem, "trustedCertificatesPem");
-
- X509TrustManager tmf = TlsUtil.trustManager(trustedCertificatesPem);
- X509KeyManager kmf = null;
- if (privateKeyPem != null && certificatePem != null) {
- kmf = TlsUtil.keyManager(privateKeyPem, certificatePem);
- }
+ requireNonNull(tmf, "X509TrustManager");
// gRPC does not abstract TLS configuration so we need to check the implementation and act
// accordingly.
- if (managedChannelBuilder.getClass().getName().equals("io.grpc.netty.NettyChannelBuilder")) {
- NettyChannelBuilder nettyBuilder = (NettyChannelBuilder) managedChannelBuilder;
- nettyBuilder.sslContext(
- GrpcSslContexts.forClient().keyManager(kmf).trustManager(tmf).build());
- } else if (managedChannelBuilder
- .getClass()
- .getName()
- .equals("io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder")) {
- io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder nettyBuilder =
- (io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder) managedChannelBuilder;
- nettyBuilder.sslContext(
- io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts.forClient()
- .trustManager(tmf)
- .keyManager(kmf)
- .build());
- } else if (managedChannelBuilder
- .getClass()
- .getName()
- .equals("io.grpc.okhttp.OkHttpChannelBuilder")) {
- io.grpc.okhttp.OkHttpChannelBuilder okHttpBuilder =
- (io.grpc.okhttp.OkHttpChannelBuilder) managedChannelBuilder;
- okHttpBuilder.sslSocketFactory(TlsUtil.sslSocketFactory(kmf, tmf));
- } else {
- throw new SSLException(
- "TLS certificate configuration not supported for unrecognized ManagedChannelBuilder "
- + managedChannelBuilder.getClass().getName());
+ String channelBuilderClassName = managedChannelBuilder.getClass().getName();
+ switch (channelBuilderClassName) {
+ case "io.grpc.netty.NettyChannelBuilder":
+ {
+ NettyChannelBuilder nettyBuilder = (NettyChannelBuilder) managedChannelBuilder;
+ SslContext sslContext =
+ GrpcSslContexts.forClient().keyManager(kmf).trustManager(tmf).build();
+ nettyBuilder.sslContext(sslContext);
+ break;
+ }
+ case "io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder":
+ {
+ io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder nettyBuilder =
+ (io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder) managedChannelBuilder;
+ io.grpc.netty.shaded.io.netty.handler.ssl.SslContext sslContext =
+ io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts.forClient()
+ .trustManager(tmf)
+ .keyManager(kmf)
+ .build();
+ nettyBuilder.sslContext(sslContext);
+ break;
+ }
+ case "io.grpc.okhttp.OkHttpChannelBuilder":
+ io.grpc.okhttp.OkHttpChannelBuilder okHttpBuilder =
+ (io.grpc.okhttp.OkHttpChannelBuilder) managedChannelBuilder;
+ okHttpBuilder.sslSocketFactory(TlsUtil.sslSocketFactory(kmf, tmf));
+ break;
+ default:
+ throw new SSLException(
+ "TLS certificate configuration not supported for unrecognized ManagedChannelBuilder "
+ + channelBuilderClassName);
}
}
diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/okhttp/OkHttpExporterBuilder.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/okhttp/OkHttpExporterBuilder.java
index 37c7090fc0e..39bc659d9d9 100644
--- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/okhttp/OkHttpExporterBuilder.java
+++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/okhttp/OkHttpExporterBuilder.java
@@ -8,7 +8,7 @@
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
-import io.opentelemetry.exporter.internal.TlsUtil;
+import io.opentelemetry.exporter.internal.TlsConfigHelper;
import io.opentelemetry.exporter.internal.auth.Authenticator;
import io.opentelemetry.exporter.internal.marshal.Marshaler;
import io.opentelemetry.exporter.internal.retry.RetryInterceptor;
@@ -18,7 +18,7 @@
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import javax.annotation.Nullable;
-import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Headers;
@@ -44,9 +44,8 @@ public final class OkHttpExporterBuilder {
private boolean compressionEnabled = false;
private boolean exportAsJson = false;
@Nullable private Headers.Builder headersBuilder;
- @Nullable private byte[] trustedCertificatesPem;
- @Nullable private byte[] privateKeyPem;
- @Nullable private byte[] certificatePem;
+
+ private final TlsConfigHelper tlsConfigHelper = new TlsConfigHelper();
@Nullable private RetryPolicy retryPolicy;
private Supplier meterProviderSupplier = GlobalOpenTelemetry::getMeterProvider;
@Nullable private Authenticator authenticator;
@@ -91,14 +90,28 @@ public OkHttpExporterBuilder setAuthenticator(Authenticator authenticator) {
return this;
}
- public OkHttpExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- this.trustedCertificatesPem = trustedCertificatesPem;
+ public OkHttpExporterBuilder configureTrustManager(byte[] trustedCertificatesPem) {
+ tlsConfigHelper.createTrustManager(trustedCertificatesPem);
+ return this;
+ }
+
+ public OkHttpExporterBuilder setTrustManager(X509TrustManager trustManager) {
+ tlsConfigHelper.setTrustManager(trustManager);
return this;
}
- public OkHttpExporterBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- this.privateKeyPem = privateKeyPem;
- this.certificatePem = certificatePem;
+ public OkHttpExporterBuilder configureKeyManager(byte[] privateKeyPem, byte[] certificatePem) {
+ tlsConfigHelper.createKeyManager(privateKeyPem, certificatePem);
+ return this;
+ }
+
+ public OkHttpExporterBuilder setKeyManager(X509KeyManager keyManager) {
+ tlsConfigHelper.setKeyManager(keyManager);
+ return this;
+ }
+
+ public OkHttpExporterBuilder setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
+ tlsConfigHelper.setSslSocketFactory(sslSocketFactory);
return this;
}
@@ -123,21 +136,7 @@ public OkHttpExporter build() {
.dispatcher(OkHttpUtil.newDispatcher())
.callTimeout(Duration.ofNanos(timeoutNanos));
- if (trustedCertificatesPem != null) {
- try {
- X509TrustManager trustManager = TlsUtil.trustManager(trustedCertificatesPem);
- X509KeyManager keyManager = null;
- if (privateKeyPem != null && certificatePem != null) {
- keyManager = TlsUtil.keyManager(privateKeyPem, certificatePem);
- }
- clientBuilder.sslSocketFactory(
- TlsUtil.sslSocketFactory(keyManager, trustManager), trustManager);
- } catch (SSLException e) {
- throw new IllegalStateException(
- "Could not set trusted certificate for OTLP HTTP connection, are they valid X.509 in PEM format?",
- e);
- }
- }
+ tlsConfigHelper.configureWithSocketFactory(clientBuilder::sslSocketFactory);
Headers headers = headersBuilder == null ? null : headersBuilder.build();
diff --git a/exporters/common/src/test/java/io/opentelemetry/exporter/internal/TlsConfigHelperTest.java b/exporters/common/src/test/java/io/opentelemetry/exporter/internal/TlsConfigHelperTest.java
new file mode 100644
index 00000000000..ccdac920265
--- /dev/null
+++ b/exporters/common/src/test/java/io/opentelemetry/exporter/internal/TlsConfigHelperTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.internal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
+import io.github.netmikey.logunit.api.LogCapturer;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class TlsConfigHelperTest {
+ @RegisterExtension
+ static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension();
+
+ @RegisterExtension
+ LogCapturer logs = LogCapturer.create().captureForLogger(TlsConfigHelper.class.getName());
+
+ @Mock TlsConfigHelper.TlsUtility tlsUtil;
+
+ @Test
+ void createTrustManager_exceptionMapped() throws Exception {
+ when(tlsUtil.trustManager(any())).thenThrow(new SSLException("boom"));
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+ assertThrows(
+ IllegalStateException.class,
+ () -> {
+ helper.createTrustManager(serverTls.certificate().getEncoded());
+ });
+ }
+
+ @Test
+ void createKeymanager_exceptionMapped() throws Exception {
+ when(tlsUtil.keyManager(any(), any())).thenThrow(new SSLException("boom"));
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+ assertThrows(
+ IllegalStateException.class,
+ () -> {
+ helper.createKeyManager(
+ serverTls.privateKey().getEncoded(), serverTls.certificate().getEncoded());
+ });
+ }
+
+ @Test
+ void socketFactory_happyPathWithBytes() throws Exception {
+
+ byte[] cert = serverTls.certificate().getEncoded();
+ byte[] key = serverTls.privateKey().getEncoded();
+ AtomicReference seenTrustManager = new AtomicReference<>();
+ AtomicReference seenSocketFactory = new AtomicReference<>();
+
+ X509TrustManager trustManager = mock(X509TrustManager.class);
+ X509KeyManager keyManager = mock(X509KeyManager.class);
+ SSLSocketFactory sslSocketFactory = mock(SSLSocketFactory.class);
+
+ when(tlsUtil.trustManager(cert)).thenReturn(trustManager);
+ when(tlsUtil.keyManager(key, cert)).thenReturn(keyManager);
+ when(tlsUtil.sslSocketFactory(keyManager, trustManager)).thenReturn(sslSocketFactory);
+
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+
+ helper.createKeyManager(key, cert);
+ helper.createTrustManager(cert);
+ helper.configureWithSocketFactory(
+ (sf, tm) -> {
+ seenTrustManager.set(tm);
+ seenSocketFactory.set(sf);
+ });
+ assertSame(trustManager, seenTrustManager.get());
+ assertSame(sslSocketFactory, seenSocketFactory.get());
+ }
+
+ @Test
+ void socketFactory_noTrustManager() {
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+ helper.configureWithSocketFactory(
+ (sf, tm) -> {
+ fail("Should not have called due to missing trust manager");
+ });
+ verifyNoInteractions(tlsUtil);
+ }
+
+ @Test
+ void socketFactoryCallbackExceptionHandled() {
+ X509TrustManager trustManager = mock(X509TrustManager.class);
+
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+
+ helper.setTrustManager(trustManager);
+ assertThrows(
+ IllegalStateException.class,
+ () -> {
+ helper.configureWithSocketFactory(
+ (sf, tm) -> {
+ throw new SSLException("bad times");
+ });
+ });
+ }
+
+ @Test
+ void configureWithKeyManagerHappyPath() {
+ AtomicReference seenTrustManager = new AtomicReference<>();
+ AtomicReference seenKeyManager = new AtomicReference<>();
+
+ X509TrustManager trustManager = mock(X509TrustManager.class);
+ X509KeyManager keyManager = mock(X509KeyManager.class);
+
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+
+ helper.setTrustManager(trustManager);
+ helper.setKeyManager(keyManager);
+ helper.configureWithKeyManager(
+ (tm, km) -> {
+ seenTrustManager.set(tm);
+ seenKeyManager.set(km);
+ });
+ assertThat(seenTrustManager.get()).isSameAs(trustManager);
+ assertThat(seenKeyManager.get()).isSameAs(keyManager);
+ }
+
+ @Test
+ void configureWithKeyManagerExceptionHandled() {
+ X509TrustManager trustManager = mock(X509TrustManager.class);
+ X509KeyManager keyManager = mock(X509KeyManager.class);
+
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+
+ helper.setTrustManager(trustManager);
+ helper.setKeyManager(keyManager);
+ assertThrows(
+ IllegalStateException.class,
+ () ->
+ helper.configureWithKeyManager(
+ (trustManager1, keyManager1) -> {
+ throw new SSLException("ouchey");
+ }));
+ }
+
+ @Test
+ void configureWithKeyManagerNoTrustManager() {
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+ helper.configureWithKeyManager(
+ (tm, km) -> {
+ fail();
+ });
+ verifyNoInteractions(tlsUtil);
+ }
+
+ @Test
+ void setKeyManagerReplacesAndWarns() {
+ X509KeyManager keyManager1 = mock(X509KeyManager.class);
+ X509KeyManager keyManager2 = mock(X509KeyManager.class);
+
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+
+ helper.setTrustManager(mock(X509TrustManager.class));
+ helper.setKeyManager(keyManager1);
+ helper.setKeyManager(keyManager2);
+
+ helper.configureWithKeyManager((tm, km) -> assertSame(km, keyManager2));
+ logs.assertContains("Previous X509 Key manager is being replaced");
+ }
+
+ @Test
+ void createKeyManagerReplacesAndWarns() throws Exception {
+ X509KeyManager keyManager1 = mock(X509KeyManager.class);
+ X509KeyManager keyManager2 = mock(X509KeyManager.class);
+
+ byte[] cert = serverTls.certificate().getEncoded();
+ byte[] key = serverTls.privateKey().getEncoded();
+
+ when(tlsUtil.keyManager(key, cert)).thenReturn(keyManager2);
+ TlsConfigHelper helper = new TlsConfigHelper(tlsUtil);
+
+ helper.setTrustManager(mock(X509TrustManager.class));
+ helper.setKeyManager(keyManager1);
+ helper.createKeyManager(key, cert);
+
+ helper.configureWithKeyManager((tm, km) -> assertSame(km, keyManager2));
+ logs.assertContains("Previous X509 Key manager is being replaced");
+ }
+}
diff --git a/exporters/jaeger/src/main/java/io/opentelemetry/exporter/jaeger/JaegerGrpcSpanExporterBuilder.java b/exporters/jaeger/src/main/java/io/opentelemetry/exporter/jaeger/JaegerGrpcSpanExporterBuilder.java
index c30ad9f1651..8c8d9671ea0 100644
--- a/exporters/jaeger/src/main/java/io/opentelemetry/exporter/jaeger/JaegerGrpcSpanExporterBuilder.java
+++ b/exporters/jaeger/src/main/java/io/opentelemetry/exporter/jaeger/JaegerGrpcSpanExporterBuilder.java
@@ -109,13 +109,13 @@ public JaegerGrpcSpanExporterBuilder setTimeout(Duration timeout) {
* use the system default trusted certificates.
*/
public JaegerGrpcSpanExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- delegate.setTrustedCertificates(trustedCertificatesPem);
+ delegate.configureTrustManager(trustedCertificatesPem);
return this;
}
/** Sets the client key and chain to use for verifying servers when mTLS is enabled. */
public JaegerGrpcSpanExporterBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- delegate.setClientTls(privateKeyPem, certificatePem);
+ delegate.configureKeyManager(privateKeyPem, certificatePem);
return this;
}
diff --git a/exporters/jaeger/src/test/java/io/opentelemetry/exporter/jaeger/JaegerGrpcSpanExporterTest.java b/exporters/jaeger/src/test/java/io/opentelemetry/exporter/jaeger/JaegerGrpcSpanExporterTest.java
index 0d364bdbc82..d9b0e66f1db 100644
--- a/exporters/jaeger/src/test/java/io/opentelemetry/exporter/jaeger/JaegerGrpcSpanExporterTest.java
+++ b/exporters/jaeger/src/test/java/io/opentelemetry/exporter/jaeger/JaegerGrpcSpanExporterTest.java
@@ -14,6 +14,7 @@
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.server.ServiceRequestContext;
import com.linecorp.armeria.server.grpc.protocol.AbstractUnaryGrpcService;
+import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
import io.github.netmikey.logunit.api.LogCapturer;
import io.opentelemetry.api.common.AttributeKey;
@@ -39,7 +40,6 @@
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.net.InetAddress;
import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -88,6 +88,12 @@ protected CompletionStage handleMessage(
@RegisterExtension
LogCapturer logs = LogCapturer.create().captureForType(OkHttpGrpcExporter.class);
+ @RegisterExtension
+ static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension();
+
+ @RegisterExtension
+ static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension();
+
private static JaegerGrpcSpanExporter exporter;
@BeforeAll
@@ -285,22 +291,21 @@ private static SpanData testSpanData(Resource resource, String spanName) {
}
@Test
- void validTrustedConfig() {
+ void validTrustedConfig() throws Exception {
assertThatCode(
() ->
JaegerGrpcSpanExporter.builder()
- .setTrustedCertificates("foobar".getBytes(StandardCharsets.UTF_8)))
+ .setTrustedCertificates(serverTls.certificate().getEncoded()))
.doesNotThrowAnyException();
}
@Test
- void validClientKeyConfig() {
+ void validClientKeyConfig() throws Exception {
assertThatCode(
() ->
JaegerGrpcSpanExporter.builder()
.setClientTls(
- "foobar".getBytes(StandardCharsets.UTF_8),
- "foobar".getBytes(StandardCharsets.UTF_8)))
+ clientTls.privateKey().getEncoded(), serverTls.certificate().getEncoded()))
.doesNotThrowAnyException();
}
diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java
index 83c19c14534..1ab0f5c8e05 100644
--- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java
+++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java
@@ -99,7 +99,7 @@ public OtlpHttpMetricExporterBuilder addHeader(String key, String value) {
* use the system default trusted certificates.
*/
public OtlpHttpMetricExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- delegate.setTrustedCertificates(trustedCertificatesPem);
+ delegate.configureTrustManager(trustedCertificatesPem);
return this;
}
@@ -108,7 +108,7 @@ public OtlpHttpMetricExporterBuilder setTrustedCertificates(byte[] trustedCertif
* The key must be PKCS8, and both must be in PEM format.
*/
public OtlpHttpMetricExporterBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- delegate.setClientTls(privateKeyPem, certificatePem);
+ delegate.configureKeyManager(privateKeyPem, certificatePem);
return this;
}
diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java
index 6ce05a36482..3d8ddbc68df 100644
--- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java
+++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java
@@ -87,7 +87,7 @@ public OtlpHttpSpanExporterBuilder addHeader(String key, String value) {
* use the system default trusted certificates.
*/
public OtlpHttpSpanExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- delegate.setTrustedCertificates(trustedCertificatesPem);
+ delegate.configureTrustManager(trustedCertificatesPem);
return this;
}
@@ -96,7 +96,7 @@ public OtlpHttpSpanExporterBuilder setTrustedCertificates(byte[] trustedCertific
* The key must be PKCS8, and both must be in PEM format.
*/
public OtlpHttpSpanExporterBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- delegate.setClientTls(privateKeyPem, certificatePem);
+ delegate.configureKeyManager(privateKeyPem, certificatePem);
return this;
}
diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterBuilder.java
index 3bc796b36e9..5197c17887e 100644
--- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterBuilder.java
+++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterBuilder.java
@@ -131,7 +131,7 @@ public OtlpGrpcMetricExporterBuilder setCompression(String compressionMethod) {
* use the system default trusted certificates.
*/
public OtlpGrpcMetricExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- delegate.setTrustedCertificates(trustedCertificatesPem);
+ delegate.configureTrustManager(trustedCertificatesPem);
return this;
}
@@ -140,7 +140,7 @@ public OtlpGrpcMetricExporterBuilder setTrustedCertificates(byte[] trustedCertif
* The key must be PKCS8, and both must be in PEM format.
*/
public OtlpGrpcMetricExporterBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- delegate.setClientTls(privateKeyPem, certificatePem);
+ delegate.configureKeyManager(privateKeyPem, certificatePem);
return this;
}
diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterBuilder.java
index 505f8e56dcc..8ead941f91d 100644
--- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterBuilder.java
+++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterBuilder.java
@@ -115,7 +115,7 @@ public OtlpGrpcSpanExporterBuilder setCompression(String compressionMethod) {
* use the system default trusted certificates.
*/
public OtlpGrpcSpanExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- delegate.setTrustedCertificates(trustedCertificatesPem);
+ delegate.configureTrustManager(trustedCertificatesPem);
return this;
}
@@ -124,7 +124,7 @@ public OtlpGrpcSpanExporterBuilder setTrustedCertificates(byte[] trustedCertific
* The key must be PKCS8, and both must be in PEM format.
*/
public OtlpGrpcSpanExporterBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- delegate.setClientTls(privateKeyPem, certificatePem);
+ delegate.configureKeyManager(privateKeyPem, certificatePem);
return this;
}
diff --git a/exporters/otlp/logs/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java b/exporters/otlp/logs/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java
index 4a201104e8d..657b2dd819b 100644
--- a/exporters/otlp/logs/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java
+++ b/exporters/otlp/logs/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java
@@ -83,7 +83,7 @@ public OtlpHttpLogRecordExporterBuilder addHeader(String key, String value) {
* use the system default trusted certificates.
*/
public OtlpHttpLogRecordExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- delegate.setTrustedCertificates(trustedCertificatesPem);
+ delegate.configureTrustManager(trustedCertificatesPem);
return this;
}
@@ -93,7 +93,7 @@ public OtlpHttpLogRecordExporterBuilder setTrustedCertificates(byte[] trustedCer
*/
public OtlpHttpLogRecordExporterBuilder setClientTls(
byte[] privateKeyPem, byte[] certificatePem) {
- delegate.setClientTls(privateKeyPem, certificatePem);
+ delegate.configureKeyManager(privateKeyPem, certificatePem);
return this;
}
diff --git a/exporters/otlp/logs/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterBuilder.java b/exporters/otlp/logs/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterBuilder.java
index 2802bbdc5f0..f6ec0e0b908 100644
--- a/exporters/otlp/logs/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterBuilder.java
+++ b/exporters/otlp/logs/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterBuilder.java
@@ -115,7 +115,7 @@ public OtlpGrpcLogRecordExporterBuilder setCompression(String compressionMethod)
* use the system default trusted certificates.
*/
public OtlpGrpcLogRecordExporterBuilder setTrustedCertificates(byte[] trustedCertificatesPem) {
- delegate.setTrustedCertificates(trustedCertificatesPem);
+ delegate.configureTrustManager(trustedCertificatesPem);
return this;
}
@@ -125,7 +125,7 @@ public OtlpGrpcLogRecordExporterBuilder setTrustedCertificates(byte[] trustedCer
*/
public OtlpGrpcLogRecordExporterBuilder setClientTls(
byte[] privateKeyPem, byte[] certificatePem) {
- delegate.setClientTls(privateKeyPem, certificatePem);
+ delegate.configureKeyManager(privateKeyPem, certificatePem);
return this;
}
diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java
index ea7001f602f..6b45c8a0f9c 100644
--- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java
+++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java
@@ -304,8 +304,10 @@ void withHeaders() {
void tls() throws Exception {
TelemetryExporter exporter =
exporterBuilder()
- .setEndpoint(server.httpsUri().toString())
.setTrustedCertificates(Files.readAllBytes(certificate.certificateFile().toPath()))
+ .setClientTls(
+ certificate.privateKey().getEncoded(), certificate.certificate().getEncoded())
+ .setEndpoint(server.httpsUri().toString())
.build();
try {
CompletableResultCode result =
@@ -337,10 +339,9 @@ void tls_badCert() {
() ->
exporterBuilder()
.setEndpoint(server.httpsUri().toString())
- .setTrustedCertificates("foobar".getBytes(StandardCharsets.UTF_8))
- .build())
+ .setTrustedCertificates("foobar".getBytes(StandardCharsets.UTF_8)))
.isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Could not set trusted certificates");
+ .hasMessageContaining("Error creating X509TrustManager with provided certs.");
}
@ParameterizedTest
@@ -652,8 +653,7 @@ void validConfig() {
.doesNotThrowAnyException();
assertThatCode(
- () ->
- exporterBuilder().setTrustedCertificates("foobar".getBytes(StandardCharsets.UTF_8)))
+ () -> exporterBuilder().setTrustedCertificates(certificate.certificate().getEncoded()))
.doesNotThrowAnyException();
}
diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java
index 47f26524435..10e6b3d1fdf 100644
--- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java
+++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java
@@ -368,10 +368,9 @@ void tls_badCert() {
() ->
exporterBuilder()
.setEndpoint(server.httpsUri() + path)
- .setTrustedCertificates("foobar".getBytes(StandardCharsets.UTF_8))
- .build())
+ .setTrustedCertificates("foobar".getBytes(StandardCharsets.UTF_8)))
.isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Could not set trusted certificate");
+ .hasMessageContaining("Error creating X509TrustManager with provided certs");
}
@ParameterizedTest
@@ -555,8 +554,7 @@ void validConfig() {
.doesNotThrowAnyException();
assertThatCode(
- () ->
- exporterBuilder().setTrustedCertificates("foobar".getBytes(StandardCharsets.UTF_8)))
+ () -> exporterBuilder().setTrustedCertificates(certificate.certificate().getEncoded()))
.doesNotThrowAnyException();
}
diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/ManagedChannelTelemetryExporterBuilder.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/ManagedChannelTelemetryExporterBuilder.java
index 7ef720419f6..7ff40964207 100644
--- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/ManagedChannelTelemetryExporterBuilder.java
+++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/ManagedChannelTelemetryExporterBuilder.java
@@ -9,6 +9,7 @@
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
+import io.opentelemetry.exporter.internal.TlsConfigHelper;
import io.opentelemetry.exporter.internal.grpc.ManagedChannelUtil;
import io.opentelemetry.exporter.internal.otlp.OtlpUserAgent;
import io.opentelemetry.exporter.internal.retry.RetryPolicy;
@@ -18,7 +19,6 @@
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
-import javax.net.ssl.SSLException;
/**
* Wraps a {@link TelemetryExporterBuilder}, delegating methods to upstream gRPC's {@link
@@ -40,9 +40,7 @@ private ManagedChannelTelemetryExporterBuilder(TelemetryExporterBuilder deleg
@Nullable private ManagedChannelBuilder> channelBuilder;
- @Nullable private byte[] privateKeyPem;
- @Nullable private byte[] certificatePem;
- @Nullable private byte[] trustedCertificatesPem;
+ private final TlsConfigHelper tlsConfigHelper = new TlsConfigHelper();
@Override
public TelemetryExporterBuilder setEndpoint(String endpoint) {
@@ -89,14 +87,13 @@ public TelemetryExporterBuilder addHeader(String key, String value) {
@Override
public TelemetryExporterBuilder setTrustedCertificates(byte[] certificates) {
- this.trustedCertificatesPem = certificates;
+ tlsConfigHelper.createTrustManager(certificates);
return this;
}
@Override
public TelemetryExporterBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- this.privateKeyPem = privateKeyPem;
- this.certificatePem = certificatePem;
+ tlsConfigHelper.createKeyManager(privateKeyPem, certificatePem);
return this;
}
@@ -126,15 +123,13 @@ public TelemetryExporterBuilder setChannel(ManagedChannel channel) {
@Override
public TelemetryExporter build() {
requireNonNull(channelBuilder, "channel");
- if (trustedCertificatesPem != null) {
- try {
- ManagedChannelUtil.setClientKeysAndTrustedCertificatesPem(
- channelBuilder, privateKeyPem, certificatePem, trustedCertificatesPem);
- } catch (SSLException e) {
- throw new IllegalStateException(
- "Could not set trusted certificates, are they valid X.509 in PEM format?", e);
- }
- }
+
+ tlsConfigHelper.configureWithKeyManager(
+ (tm, km) -> {
+ requireNonNull(channelBuilder, "channel");
+ ManagedChannelUtil.setClientKeysAndTrustedCertificatesPem(channelBuilder, tm, km);
+ });
+
ManagedChannel channel = channelBuilder.build();
delegate.setChannel(channel);
TelemetryExporter delegateExporter = delegate.build();
diff --git a/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/DefaultGrpcServiceBuilder.java b/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/DefaultGrpcServiceBuilder.java
index b7e7a398c4b..e0d39cfa23b 100644
--- a/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/DefaultGrpcServiceBuilder.java
+++ b/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/DefaultGrpcServiceBuilder.java
@@ -16,6 +16,7 @@
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
+import io.opentelemetry.exporter.internal.TlsConfigHelper;
import io.opentelemetry.exporter.internal.grpc.ManagedChannelUtil;
import io.opentelemetry.exporter.internal.grpc.MarshalerServiceStub;
import io.opentelemetry.exporter.internal.marshal.Marshaler;
@@ -25,7 +26,6 @@
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import javax.annotation.Nullable;
-import javax.net.ssl.SSLException;
final class DefaultGrpcServiceBuilder
implements GrpcServiceBuilder {
@@ -39,10 +39,8 @@ final class DefaultGrpcServiceBuilder setCompression(String compressionMe
public DefaultGrpcServiceBuilder setTrustedCertificates(
byte[] trustedCertificatesPem) {
requireNonNull(trustedCertificatesPem, "trustedCertificatesPem");
- this.trustedCertificatesPem = trustedCertificatesPem;
+ tlsConfigHelper.createTrustManager(trustedCertificatesPem);
return this;
}
@Override
public GrpcServiceBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) {
- this.privateKeyPem = privateKeyPem;
- this.certificatePem = certificatePem;
+ tlsConfigHelper.createKeyManager(privateKeyPem, certificatePem);
return this;
}
@@ -147,17 +144,10 @@ public GrpcService build() {
managedChannelBuilder.intercept(MetadataUtils.newAttachHeadersInterceptor(metadata));
}
- if (trustedCertificatesPem != null) {
- try {
- ManagedChannelUtil.setClientKeysAndTrustedCertificatesPem(
- managedChannelBuilder, privateKeyPem, certificatePem, trustedCertificatesPem);
- } catch (SSLException e) {
- throw new IllegalStateException(
- "Could not set trusted certificates for gRPC TLS connection, are they valid "
- + "X.509 in PEM format?",
- e);
- }
- }
+ tlsConfigHelper.configureWithKeyManager(
+ (tm, km) ->
+ ManagedChannelUtil.setClientKeysAndTrustedCertificatesPem(
+ managedChannelBuilder, tm, km));
if (retryPolicy != null) {
managedChannelBuilder.defaultServiceConfig(toServiceConfig(grpcServiceName, retryPolicy));
diff --git a/sdk-extensions/jaeger-remote-sampler/src/testGrpcNetty/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/DefaultGrpcServiceBuilderTest.java b/sdk-extensions/jaeger-remote-sampler/src/testGrpcNetty/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/DefaultGrpcServiceBuilderTest.java
index dd8d231e03c..efe3bc193b6 100644
--- a/sdk-extensions/jaeger-remote-sampler/src/testGrpcNetty/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/DefaultGrpcServiceBuilderTest.java
+++ b/sdk-extensions/jaeger-remote-sampler/src/testGrpcNetty/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/DefaultGrpcServiceBuilderTest.java
@@ -8,15 +8,19 @@
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.exporter.internal.retry.RetryPolicy;
import java.net.URI;
-import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
class DefaultGrpcServiceBuilderTest {
+ @RegisterExtension
+ static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension();
+
private static DefaultGrpcServiceBuilder<
SamplingStrategyParametersMarshaler, SamplingStrategyResponseUnMarshaler>
exporterBuilder() {
@@ -52,8 +56,7 @@ void validConfig() {
.doesNotThrowAnyException();
assertThatCode(
- () ->
- exporterBuilder().setTrustedCertificates("foobar".getBytes(StandardCharsets.UTF_8)))
+ () -> exporterBuilder().setTrustedCertificates(serverTls.certificate().getEncoded()))
.doesNotThrowAnyException();
assertThatCode(() -> exporterBuilder().addRetryPolicy(RetryPolicy.getDefault()))