diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt index 8a99a2cd80e..c115fb3cccd 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt @@ -1,2 +1,14 @@ Comparing source compatibility of opentelemetry-sdk-common-1.65.0-SNAPSHOT.jar against opentelemetry-sdk-common-1.64.0.jar -No changes. \ No newline at end of file +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.common.export.HttpSenderConfig (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.TlsCompatibilityMode getTlsCompatibilityMode() ++++ NEW ENUM: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.common.export.TlsCompatibilityMode (compatible) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW INTERFACE: java.lang.constant.Constable + +++ NEW INTERFACE: java.lang.Comparable + +++ NEW INTERFACE: java.io.Serializable + +++ NEW SUPERCLASS: java.lang.Enum + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.sdk.common.export.TlsCompatibilityMode MODERN + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.sdk.common.export.TlsCompatibilityMode COMPATIBLE + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.export.TlsCompatibilityMode valueOf(java.lang.String) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.export.TlsCompatibilityMode[] values() diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/HttpExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/HttpExporterBuilder.java index 98a5a2e2b85..087386b2868 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/HttpExporterBuilder.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/HttpExporterBuilder.java @@ -17,6 +17,7 @@ import io.opentelemetry.sdk.common.export.HttpSenderProvider; import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; +import io.opentelemetry.sdk.common.export.TlsCompatibilityMode; import io.opentelemetry.sdk.common.internal.ComponentId; import io.opentelemetry.sdk.common.internal.StandardComponentId; import java.net.URI; @@ -69,6 +70,7 @@ public final class HttpExporterBuilder { private ComponentLoader componentLoader = ComponentLoader.forClassLoader(HttpExporterBuilder.class.getClassLoader()); @Nullable private ExecutorService executorService; + private TlsCompatibilityMode tlsCompatibilityMode = TlsCompatibilityMode.MODERN; public HttpExporterBuilder( StandardComponentId.ExporterType exporterType, String defaultEndpoint) { @@ -167,6 +169,11 @@ public HttpExporterBuilder setExecutorService(ExecutorService executorService) { return this; } + public HttpExporterBuilder setTlsCompatibilityMode(TlsCompatibilityMode tlsCompatibilityMode) { + this.tlsCompatibilityMode = tlsCompatibilityMode; + return this; + } + public HttpExporterBuilder exportAsJson() { this.exportAsJson = true; exporterType = mapToJsonTypeIfPossible(exporterType); @@ -204,6 +211,7 @@ public HttpExporterBuilder copy() { copy.internalTelemetryVersion = internalTelemetryVersion; copy.proxyOptions = proxyOptions; copy.componentLoader = componentLoader; + copy.tlsCompatibilityMode = tlsCompatibilityMode; return copy; } @@ -247,7 +255,8 @@ public HttpExporter build() { executorService, // 4mb to align with spec guidance - even though we don't do anything with the // response today, we will so better to have future-looking memory profile - 4 * 1024L * 1024L)); + 4 * 1024L * 1024L, + tlsCompatibilityMode)); LOGGER.log(Level.FINE, "Using HttpSender: " + httpSender.getClass().getName()); return new HttpExporter( diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/ImmutableHttpSenderConfig.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/ImmutableHttpSenderConfig.java index a6d04ae6aa4..8b74b05a654 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/ImmutableHttpSenderConfig.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/ImmutableHttpSenderConfig.java @@ -10,6 +10,7 @@ import io.opentelemetry.sdk.common.export.HttpSenderConfig; import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; +import io.opentelemetry.sdk.common.export.TlsCompatibilityMode; import java.net.URI; import java.time.Duration; import java.util.List; @@ -36,7 +37,8 @@ static HttpSenderConfig create( @Nullable SSLContext sslContext, @Nullable X509TrustManager trustManager, @Nullable ExecutorService executorService, - long maxResponseBodySize) { + long maxResponseBodySize, + TlsCompatibilityMode tlsCompatibilityMode) { return new AutoValue_ImmutableHttpSenderConfig( endpoint, contentType, @@ -49,9 +51,13 @@ static HttpSenderConfig create( sslContext, trustManager, executorService, - maxResponseBodySize); + maxResponseBodySize, + tlsCompatibilityMode); } @Override public abstract long getMaxResponseBodySize(); + + @Override + public abstract TlsCompatibilityMode getTlsCompatibilityMode(); } diff --git a/exporters/sender/okhttp/build.gradle.kts b/exporters/sender/okhttp/build.gradle.kts index 85aa30f3125..8775368adaa 100644 --- a/exporters/sender/okhttp/build.gradle.kts +++ b/exporters/sender/okhttp/build.gradle.kts @@ -27,3 +27,16 @@ dependencies { testImplementation("com.linecorp.armeria:armeria-junit5") } + +tasks.withType().configureEach { + // OkHttpHttpSenderTlsCompatibilityTest needs TLSv1/TLSv1.1 available to test COMPATIBLE_TLS + // against a legacy-protocol-only server. jdk.tls.disabledAlgorithms is a security property + // (not a regular system property) that the JDK caches the first time any TLS code runs in + // the JVM, so mutating it at test runtime only works if nothing else in the shared test JVM + // has touched TLS yet -- not guaranteed. Overriding it via java.security.properties applies + // at JVM bootstrap, before that caching can happen, so it's always in effect. + systemProperty( + "java.security.properties", + file("src/test/resources/enable-legacy-tls-test.security").absolutePath + ) +} diff --git a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java index b5c611d1bcb..c3eb1cc8bd4 100644 --- a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java +++ b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java @@ -14,6 +14,7 @@ import io.opentelemetry.sdk.common.export.MessageWriter; import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; +import io.opentelemetry.sdk.common.export.TlsCompatibilityMode; import java.io.IOException; import java.net.URI; import java.time.Duration; @@ -79,7 +80,8 @@ public OkHttpHttpSender( @Nullable SSLContext sslContext, @Nullable X509TrustManager trustManager, @Nullable ExecutorService executorService, - long maxResponseBodySize) { + long maxResponseBodySize, + TlsCompatibilityMode tlsCompatibilityMode) { int callTimeoutMillis = (int) Math.min(timeout.toMillis(), Integer.MAX_VALUE); int connectTimeoutMillis = (int) Math.min(connectTimeout.toMillis(), Integer.MAX_VALUE); @@ -109,8 +111,13 @@ public OkHttpHttpSender( boolean isPlainHttp = endpoint.getScheme().equals("http"); if (isPlainHttp) { builder.connectionSpecs(Collections.singletonList(ConnectionSpec.CLEARTEXT)); - } else if (sslContext != null && trustManager != null) { - builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager); + } else { + if (sslContext != null && trustManager != null) { + builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager); + } + if (tlsCompatibilityMode == TlsCompatibilityMode.COMPATIBLE) { + builder.connectionSpecs(Collections.singletonList(ConnectionSpec.COMPATIBLE_TLS)); + } } this.client = builder.build(); diff --git a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderProvider.java b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderProvider.java index 581cf9bb549..3b14382f2a3 100644 --- a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderProvider.java +++ b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderProvider.java @@ -31,6 +31,7 @@ public HttpSender createSender(HttpSenderConfig httpSenderConfig) { httpSenderConfig.getSslContext(), httpSenderConfig.getTrustManager(), httpSenderConfig.getExecutorService(), - httpSenderConfig.getMaxResponseBodySize()); + httpSenderConfig.getMaxResponseBodySize(), + httpSenderConfig.getTlsCompatibilityMode()); } } diff --git a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTest.java b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTest.java index 0edc216aee6..06bc497c6d1 100644 --- a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTest.java +++ b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTest.java @@ -12,6 +12,7 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.HttpResponse; import io.opentelemetry.sdk.common.export.MessageWriter; +import io.opentelemetry.sdk.common.export.TlsCompatibilityMode; import java.io.OutputStream; import java.net.ServerSocket; import java.net.URI; @@ -48,7 +49,8 @@ void send_rejectedExecution_callsOnError() { null, null, executor, - Long.MAX_VALUE); + Long.MAX_VALUE, + TlsCompatibilityMode.MODERN); AtomicReference responseRef = new AtomicReference<>(); AtomicReference errorRef = new AtomicReference<>(); @@ -211,7 +213,8 @@ private static OkHttpHttpSender newSender( null, null, executorService, - Long.MAX_VALUE); + Long.MAX_VALUE, + TlsCompatibilityMode.MODERN); } private static class NoOpRequestBodyWriter implements MessageWriter { diff --git a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTlsCompatibilityTest.java b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTlsCompatibilityTest.java new file mode 100644 index 00000000000..1022ec78539 --- /dev/null +++ b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSenderTlsCompatibilityTest.java @@ -0,0 +1,249 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.sender.okhttp.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.MultiThreadIoEventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioIoHandler; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.ssl.ApplicationProtocolConfig; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.opentelemetry.exporter.internal.TlsUtil; +import io.opentelemetry.sdk.common.export.HttpResponse; +import io.opentelemetry.sdk.common.export.MessageWriter; +import io.opentelemetry.sdk.common.export.TlsCompatibilityMode; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; +import java.security.NoSuchAlgorithmException; +import java.time.Duration; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.Nullable; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +/** + * Tests TLS compatibility modes against a server that only supports legacy TLS protocols. + * + *

OkHttp's {@code ConnectionSpec.MODERN_TLS} and {@code ConnectionSpec.COMPATIBLE_TLS} differ in + * the supported TLS protocol versions. + * + *

The test server is restricted to TLSv1/TLSv1.1 because these are the protocol versions that + * distinguish MODERN_TLS from COMPATIBLE_TLS. + */ +class OkHttpHttpSenderTlsCompatibilityTest { + + @RegisterExtension + static final SelfSignedCertificateExtension certificate = new SelfSignedCertificateExtension(); + + private static EventLoopGroup bossGroup; + private static EventLoopGroup workerGroup; + private static Channel serverChannel; + private static URI serverUri; + + @BeforeAll + static void setup() throws Exception { + bossGroup = new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory()); + + workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()); + + SslContext sslContext = + SslContextBuilder.forServer(certificate.privateKey(), certificate.certificate()) + .protocols("TLSv1", "TLSv1.1") + .applicationProtocolConfig(ApplicationProtocolConfig.DISABLED) + .build(); + + ServerBootstrap bootstrap = new ServerBootstrap(); + + bootstrap + .group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler( + new ChannelInitializer() { + + @Override + protected void initChannel(SocketChannel ch) { + + ChannelPipeline pipeline = ch.pipeline(); + + pipeline.addLast(sslContext.newHandler(ch.alloc())); + + pipeline.addLast(new HttpServerCodec()); + + pipeline.addLast(new HttpObjectAggregator(1024 * 1024)); + + pipeline.addLast( + new SimpleChannelInboundHandler() { + + @Override + protected void channelRead0( + ChannelHandlerContext ctx, FullHttpRequest request) { + + FullHttpResponse response = + new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK); + + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } + }); + } + }); + + serverChannel = bootstrap.bind(0).sync().channel(); + + int port = ((InetSocketAddress) serverChannel.localAddress()).getPort(); + + serverUri = URI.create("https://localhost:" + port + "/"); + } + + @AfterAll + static void restoreDisabledAlgorithms() throws Exception { + if (serverChannel != null) { + serverChannel.close().sync(); + } + + if (bossGroup != null) { + bossGroup.shutdownGracefully().sync(); + } + + if (workerGroup != null) { + workerGroup.shutdownGracefully().sync(); + } + } + + @Test + void modernTls_cannotReachLegacyProtocolOnlyServer() throws Exception { + // If this JVM's TLS provider does not implement TLSv1/1.1, skip instead of + // failing for an unrelated reason. + assumeTrue( + supportsProtocol("TLSv1") || supportsProtocol("TLSv1.1"), + "TLSv1/TLSv1.1 are not supported by this JVM"); + + OkHttpHttpSender sender = buildSender(TlsCompatibilityMode.MODERN); + + Result result = send(sender); + + assertThat(result.response).isNull(); + assertThat(result.error) + .isNotNull(); // handshake failure: no protocol version in common with the server + } + + @Test + void compatibleTls_reachesLegacyProtocolOnlyServer() throws Exception { + assumeTrue( + supportsProtocol("TLSv1") || supportsProtocol("TLSv1.1"), + "TLSv1/TLSv1.1 are not supported by this JVM"); + + OkHttpHttpSender sender = buildSender(TlsCompatibilityMode.COMPATIBLE); + + Result result = send(sender); + + assertThat(result.error).isNull(); + assertThat(result.response).isNotNull(); + assertThat(result.response.getStatusCode()).isEqualTo(200); + } + + private static OkHttpHttpSender buildSender(TlsCompatibilityMode tlsCompatibilityMode) + throws Exception { + X509TrustManager trustManager = TlsUtil.trustManager(certificate.certificate().getEncoded()); + SSLContext sslContext = SSLContext.getInstance("TLS"); + // Use the same trust configuration in both tests so only the TLS compatibility + // mode differs. + sslContext.init(null, new TrustManager[] {trustManager}, null); + + return new OkHttpHttpSender( + serverUri, + "text/plain", + null, + Duration.ofSeconds(10), + Duration.ofSeconds(10), + Collections::emptyMap, + null, + null, + sslContext, + trustManager, + null, + Long.MAX_VALUE, + tlsCompatibilityMode); + } + + private static Result send(OkHttpHttpSender sender) throws InterruptedException { + AtomicReference responseRef = new AtomicReference<>(); + AtomicReference errorRef = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + + sender.send( + new NoOpRequestBodyWriter(), + response -> { + responseRef.set(response); + latch.countDown(); + }, + error -> { + errorRef.set(error); + latch.countDown(); + }); + + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + return new Result(responseRef.get(), errorRef.get()); + } + + private static boolean supportsProtocol(String protocol) { + try { + SSLContext.getInstance(protocol); + return true; + } catch (NoSuchAlgorithmException e) { + return false; + } + } + + private static class Result { + @Nullable final HttpResponse response; + @Nullable final Throwable error; + + Result(@Nullable HttpResponse response, @Nullable Throwable error) { + this.response = response; + this.error = error; + } + } + + private static class NoOpRequestBodyWriter implements MessageWriter { + @Override + public void writeMessage(OutputStream output) {} + + @Override + public int getContentLength() { + return 0; + } + } +} diff --git a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSuppressionTest.java b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSuppressionTest.java index c64247a9b36..22ce6d5e8fc 100644 --- a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSuppressionTest.java +++ b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSuppressionTest.java @@ -6,6 +6,7 @@ package io.opentelemetry.exporter.sender.okhttp.internal; import io.opentelemetry.sdk.common.export.MessageWriter; +import io.opentelemetry.sdk.common.export.TlsCompatibilityMode; import java.io.IOException; import java.io.OutputStream; import java.net.URI; @@ -47,6 +48,7 @@ OkHttpHttpSender createSender(String endpoint) { null, null, null, - Long.MAX_VALUE); + Long.MAX_VALUE, + TlsCompatibilityMode.MODERN); } } diff --git a/exporters/sender/okhttp/src/test/resources/enable-legacy-tls-test.security b/exporters/sender/okhttp/src/test/resources/enable-legacy-tls-test.security new file mode 100644 index 00000000000..d50868d1bfb --- /dev/null +++ b/exporters/sender/okhttp/src/test/resources/enable-legacy-tls-test.security @@ -0,0 +1,8 @@ +# Used only for this module's test JVM (see build.gradle.kts), via -Djava.security.properties. +# +# Mirrors the JDK's default jdk.tls.disabledAlgorithms, minus TLSv1 and TLSv1.1, so that +# OkHttpHttpSenderTlsCompatibilityTest can exercise COMPATIBLE_TLS against a legacy-protocol-only +# server. Setting this via java.security.properties applies at JVM bootstrap, before any class +# has a chance to initialize the JDK's TLS internals and cache the previous value +jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ + EC keySize < 224, 3DES_EDE_CBC, anon, NULL, include jdk.disabled.namedCurves diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/HttpSenderConfig.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/HttpSenderConfig.java index be40289dd9c..b6410c91fdd 100644 --- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/HttpSenderConfig.java +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/HttpSenderConfig.java @@ -98,4 +98,15 @@ public interface HttpSenderConfig { default long getMaxResponseBodySize() { return 4 * 1024L * 1024L; } + + /** + * The TLS compatibility mode to use when connecting to an HTTPS endpoint. + * + *

Defaults to {@link TlsCompatibilityMode#MODERN}, which uses modern TLS versions only. {@link + * TlsCompatibilityMode#COMPATIBLE} enables support for legacy TLS versions for compatibility with + * older servers. + */ + default TlsCompatibilityMode getTlsCompatibilityMode() { + return TlsCompatibilityMode.MODERN; + } } diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/TlsCompatibilityMode.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/TlsCompatibilityMode.java new file mode 100644 index 00000000000..663ada329e9 --- /dev/null +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/export/TlsCompatibilityMode.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.common.export; + +/** + * Controls the range of TLS protocol versions a {@link HttpSender} is willing to negotiate when + * connecting to an HTTPS endpoint. + * + *

This is intentionally implementation-neutral: it says nothing about OkHttp's {@code + * ConnectionSpec} or any other sender-specific concept. Each {@link HttpSenderProvider} maps it to + * whatever mechanism its underlying HTTP client exposes. + */ +public enum TlsCompatibilityMode { + /** + * The default TLS configuration intended for modern servers and clients. In OkHttp terms, this + * corresponds to {@code ConnectionSpec.MODERN_TLS}. + */ + MODERN, + + /** + * A broader set of TLS protocol versions for compatibility with older endpoints. For OkHttp + * senders, this corresponds to {@code ConnectionSpec.COMPATIBLE_TLS}. + * + *

Prefer upgrading the client or server platform instead of using this mode when possible: it + * widens the negotiable protocol range down to TLSv1.0. + */ + COMPATIBLE +}