This is an automated email from the ASF dual-hosted git repository.

pjfanning pushed a commit to branch 1.3.x
in repository https://gitbox.apache.org/repos/asf/pekko-grpc.git


The following commit(s) were added to refs/heads/1.3.x by this push:
     new 953719f5 add verify-hostname support (#820) (#845)
953719f5 is described below

commit 953719f545cbf09c01b9f211dc23008d6ed1e458
Author: PJ Fanning <[email protected]>
AuthorDate: Wed Aug 19 23:20:55 2026 +0100

    add verify-hostname support (#820) (#845)
    
    * add verify-hostname support (#820)
    
    * upgrade setup-sbt due to build issues
    
    * Update PekkoHttpClientUtils.scala
---
 .github/workflows/build-test.yml                   | 14 ++++----
 .github/workflows/headers.yml                      |  2 +-
 .github/workflows/link-validator.yml               |  2 +-
 .../workflows/nightly-snapshot-dependency-test.yml |  2 +-
 .github/workflows/publish-1.0-docs.yml             |  2 +-
 .github/workflows/publish-1.0-snapshots.yml        |  2 +-
 .github/workflows/publish-1.1-docs.yml             |  2 +-
 .github/workflows/publish-1.1-snapshots.yml        |  2 +-
 .github/workflows/publish-1.2-docs.yml             |  2 +-
 .github/workflows/publish-1.2-snapshots.yml        |  2 +-
 .github/workflows/publish-nightly.yml              |  2 +-
 runtime/src/main/resources/reference.conf          |  6 ++++
 .../org/apache/pekko/grpc/GrpcClientSettings.scala | 22 +++++++++---
 .../pekko/grpc/internal/PekkoHttpClientUtils.scala | 41 +++++++++++++++-------
 14 files changed, 70 insertions(+), 33 deletions(-)

diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml
index 98456b38..0f5ffa2f 100644
--- a/.github/workflows/build-test.yml
+++ b/.github/workflows/build-test.yml
@@ -37,7 +37,7 @@ jobs:
           java-version: 11
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Cache Coursier cache
         uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d # 
v8.1.1
@@ -64,7 +64,7 @@ jobs:
           java-version: 11
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Cache Coursier cache
         uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d # 
v8.1.1
@@ -95,7 +95,7 @@ jobs:
           java-version: ${{ matrix.JAVA_VERSION }}
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Cache Coursier cache
         uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d # 
v8.1.1
@@ -130,7 +130,7 @@ jobs:
           java-version: 8
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Install go
         uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # 
v5.5.0
@@ -162,7 +162,7 @@ jobs:
           java-version: 8
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Cache Coursier cache
         uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d # 
v8.1.1
@@ -221,7 +221,7 @@ jobs:
           java-version: 8
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Cache Coursier cache
         uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d # 
v8.1.1
@@ -270,7 +270,7 @@ jobs:
           java-version: 11
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Cache Coursier cache
         uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d # 
v8.1.1
diff --git a/.github/workflows/headers.yml b/.github/workflows/headers.yml
index e0c25374..f1f9128b 100644
--- a/.github/workflows/headers.yml
+++ b/.github/workflows/headers.yml
@@ -37,7 +37,7 @@ jobs:
           java-version: 8
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Cache Coursier cache
         uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d # 
v8.1.1
diff --git a/.github/workflows/link-validator.yml 
b/.github/workflows/link-validator.yml
index 48dba86f..845d2991 100644
--- a/.github/workflows/link-validator.yml
+++ b/.github/workflows/link-validator.yml
@@ -33,7 +33,7 @@ jobs:
           java-version: 11
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Cache Coursier cache
         uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d # 
v8.1.1
diff --git a/.github/workflows/nightly-snapshot-dependency-test.yml 
b/.github/workflows/nightly-snapshot-dependency-test.yml
index 37bed5f3..e5401ad8 100644
--- a/.github/workflows/nightly-snapshot-dependency-test.yml
+++ b/.github/workflows/nightly-snapshot-dependency-test.yml
@@ -32,7 +32,7 @@ jobs:
           java-version: 8    
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Test
         run: |-
diff --git a/.github/workflows/publish-1.0-docs.yml 
b/.github/workflows/publish-1.0-docs.yml
index e41aa9c3..bab24838 100644
--- a/.github/workflows/publish-1.0-docs.yml
+++ b/.github/workflows/publish-1.0-docs.yml
@@ -40,7 +40,7 @@ jobs:
           java-version: 8    
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Build Documentation
         run: |-
diff --git a/.github/workflows/publish-1.0-snapshots.yml 
b/.github/workflows/publish-1.0-snapshots.yml
index 27470842..72c32401 100644
--- a/.github/workflows/publish-1.0-snapshots.yml
+++ b/.github/workflows/publish-1.0-snapshots.yml
@@ -31,7 +31,7 @@ jobs:
           java-version: 8    
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Publish
         run: |-
diff --git a/.github/workflows/publish-1.1-docs.yml 
b/.github/workflows/publish-1.1-docs.yml
index 6cf3df6f..e2c40657 100644
--- a/.github/workflows/publish-1.1-docs.yml
+++ b/.github/workflows/publish-1.1-docs.yml
@@ -40,7 +40,7 @@ jobs:
           java-version: 8    
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Build Documentation
         run: |-
diff --git a/.github/workflows/publish-1.1-snapshots.yml 
b/.github/workflows/publish-1.1-snapshots.yml
index 79531426..ee2f38c6 100644
--- a/.github/workflows/publish-1.1-snapshots.yml
+++ b/.github/workflows/publish-1.1-snapshots.yml
@@ -33,7 +33,7 @@ jobs:
           java-version: 8    
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Publish
         run: |-
diff --git a/.github/workflows/publish-1.2-docs.yml 
b/.github/workflows/publish-1.2-docs.yml
index b5481c5e..475ff900 100644
--- a/.github/workflows/publish-1.2-docs.yml
+++ b/.github/workflows/publish-1.2-docs.yml
@@ -40,7 +40,7 @@ jobs:
           java-version: 8    
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Build Documentation
         run: |-
diff --git a/.github/workflows/publish-1.2-snapshots.yml 
b/.github/workflows/publish-1.2-snapshots.yml
index dd775dc1..19a66976 100644
--- a/.github/workflows/publish-1.2-snapshots.yml
+++ b/.github/workflows/publish-1.2-snapshots.yml
@@ -33,7 +33,7 @@ jobs:
           java-version: 8    
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Publish
         run: |-
diff --git a/.github/workflows/publish-nightly.yml 
b/.github/workflows/publish-nightly.yml
index c62a241d..a0aebfe8 100644
--- a/.github/workflows/publish-nightly.yml
+++ b/.github/workflows/publish-nightly.yml
@@ -32,7 +32,7 @@ jobs:
           java-version: 8    
 
       - name: Install sbt
-        uses: sbt/setup-sbt@6444f4c8111de4b9059c3975def104b03cfaa5f0 # v1.5.2
+        uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1.5.7
 
       - name: Publish
         run: |-
diff --git a/runtime/src/main/resources/reference.conf 
b/runtime/src/main/resources/reference.conf
index 99fcc62a..89a84f85 100644
--- a/runtime/src/main/resources/reference.conf
+++ b/runtime/src/main/resources/reference.conf
@@ -38,6 +38,12 @@ pekko.grpc.client."*" {
   # leave empty to auto-detect, or configure 'jdk' or 'openssl'.
   ssl-provider = ""
 
+  # Whether to verify the server's hostname against its TLS certificate (RFC 
2818).
+  # When false (the default), the client accepts any valid certificate 
regardless
+  # of hostname. This is insecure for production and should only be used for 
testing.
+  # Only effective for the pekko-http backend; the netty backend always 
verifies.
+  verify-hostname = false
+
   # TODO: Enforce HTTP/2 TLS restrictions: 
https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-9.2
 
   # The number of times to try connecting before giving up.
diff --git 
a/runtime/src/main/scala/org/apache/pekko/grpc/GrpcClientSettings.scala 
b/runtime/src/main/scala/org/apache/pekko/grpc/GrpcClientSettings.scala
index 11c6eef1..116b3188 100644
--- a/runtime/src/main/scala/org/apache/pekko/grpc/GrpcClientSettings.scala
+++ b/runtime/src/main/scala/org/apache/pekko/grpc/GrpcClientSettings.scala
@@ -158,7 +158,8 @@ object GrpcClientSettings {
       getOptionalString(clientConfiguration, "user-agent"),
       clientConfiguration.getBoolean("use-tls"),
       getOptionalString(clientConfiguration, "load-balancing-policy"),
-      clientConfiguration.getString("backend"))
+      clientConfiguration.getString("backend"),
+      verifyHostname = clientConfiguration.getBoolean("verify-hostname"))
 
   private def getOptionalString(config: Config, path: String): Option[String] =
     config.getString(path) match {
@@ -206,7 +207,8 @@ final class GrpcClientSettings private (
     val useTls: Boolean,
     val loadBalancingPolicy: Option[String],
     val backend: String,
-    val channelBuilderOverrides: NettyChannelBuilder => NettyChannelBuilder = 
identity) {
+    val channelBuilderOverrides: NettyChannelBuilder => NettyChannelBuilder = 
identity,
+    val verifyHostname: Boolean) {
   require(
     sslContext.isEmpty || trustManager.isEmpty,
     "Configuring the sslContext or the trustManager is mutually exclusive")
@@ -294,6 +296,16 @@ final class GrpcClientSettings private (
   def withBackend(value: String): GrpcClientSettings =
     copy(backend = value)
 
+  /**
+   * Whether to verify the server's hostname against its TLS certificate (RFC 
2818).
+   * When false (the default), the client accepts any valid certificate 
regardless
+   * of hostname. This is insecure for production and should only be used for 
testing.
+   * Only effective for the pekko-http backend; the netty backend always 
verifies.
+   * @since 2.0.0
+   */
+  def withVerifyHostname(value: Boolean): GrpcClientSettings =
+    copy(verifyHostname = value)
+
   private def copy(
       serviceName: String = serviceName,
       servicePortName: Option[String] = servicePortName,
@@ -311,7 +323,8 @@ final class GrpcClientSettings private (
       connectionAttempts: Option[Int] = connectionAttempts,
       loadBalancingPolicy: Option[String] = loadBalancingPolicy,
       backend: String = backend,
-      channelBuilderOverrides: NettyChannelBuilder => NettyChannelBuilder = 
channelBuilderOverrides)
+      channelBuilderOverrides: NettyChannelBuilder => NettyChannelBuilder = 
channelBuilderOverrides,
+      verifyHostname: Boolean = verifyHostname)
       : GrpcClientSettings =
     new GrpcClientSettings(
       callCredentials = callCredentials,
@@ -331,5 +344,6 @@ final class GrpcClientSettings private (
       connectionAttempts = connectionAttempts,
       loadBalancingPolicy = loadBalancingPolicy,
       backend = backend,
-      channelBuilderOverrides = channelBuilderOverrides)
+      channelBuilderOverrides = channelBuilderOverrides,
+      verifyHostname = verifyHostname)
 }
diff --git 
a/runtime/src/main/scala/org/apache/pekko/grpc/internal/PekkoHttpClientUtils.scala
 
b/runtime/src/main/scala/org/apache/pekko/grpc/internal/PekkoHttpClientUtils.scala
index 3567bf1e..efd16b53 100644
--- 
a/runtime/src/main/scala/org/apache/pekko/grpc/internal/PekkoHttpClientUtils.scala
+++ 
b/runtime/src/main/scala/org/apache/pekko/grpc/internal/PekkoHttpClientUtils.scala
@@ -16,7 +16,7 @@ package org.apache.pekko.grpc.internal
 import java.net.InetSocketAddress
 import java.security.SecureRandom
 import java.util.concurrent.CompletionStage
-import scala.concurrent.duration._
+
 import org.apache.pekko
 import pekko.{ Done, NotUsed }
 import pekko.actor.ClassicActorSystemProvider
@@ -27,6 +27,7 @@ import pekko.grpc.{ GrpcClientSettings, GrpcResponseMetadata, 
GrpcSingleResponse
 import pekko.http.scaladsl.model.HttpEntity.{ Chunk, Chunked, LastChunk, 
Strict }
 import pekko.http.scaladsl.{ ClientTransport, ConnectionContext, Http }
 import pekko.http.scaladsl.model._
+import pekko.http.scaladsl.model.StatusCodes
 import pekko.http.scaladsl.model.headers.RawHeader
 import pekko.http.scaladsl.settings.ClientConnectionSettings
 import pekko.stream.{ Materializer, OverflowStrategy }
@@ -38,8 +39,8 @@ import io.grpc.{ CallOptions, MethodDescriptor, Status, 
StatusRuntimeException }
 import javax.net.ssl.{ KeyManager, SSLContext, TrustManager }
 import scala.collection.immutable
 import scala.concurrent.{ ExecutionContext, Future, Promise }
+import scala.concurrent.duration._
 import scala.util.{ Failure, Success }
-import pekko.http.scaladsl.model.StatusCodes
 
 /**
  * INTERNAL API
@@ -94,18 +95,34 @@ object PekkoHttpClientUtils {
 
     val http2client =
       if (settings.useTls) {
-        val connectionContext =
-          ConnectionContext.httpsClient {
-            settings.sslContext.getOrElse {
-              settings.trustManager match {
-                case None => SSLContext.getDefault
-                case Some(trustManager) =>
-                  val sslContext: SSLContext = SSLContext.getInstance("TLS")
-                  sslContext.init(Array[KeyManager](), 
Array[TrustManager](trustManager), new SecureRandom)
-                  sslContext
-              }
+        if (!settings.verifyHostname) {
+          log.warning(
+            "TLS hostname verification is disabled for pekko-http client '{}'. 
" +
+            "This is insecure and should only be used for testing. " +
+            "Enable it with verify-hostname = true in your configuration. " +
+            "Note: the netty backend always verifies hostnames.",
+            settings.serviceName)
+        }
+        val sslContext =
+          settings.sslContext.getOrElse {
+            settings.trustManager match {
+              case None => SSLContext.getDefault
+              case Some(trustManager) =>
+                val ctx: SSLContext = SSLContext.getInstance("TLS")
+                ctx.init(Array[KeyManager](), 
Array[TrustManager](trustManager), new SecureRandom)
+                ctx
             }
           }
+        val connectionContext =
+          ConnectionContext.httpsClient((hostname, port) => {
+            val engine = sslContext.createSSLEngine(hostname, port)
+            if (settings.verifyHostname) {
+              val sslParams = engine.getSSLParameters
+              sslParams.setEndpointIdentificationAlgorithm("HTTPS")
+              engine.setSSLParameters(sslParams)
+            }
+            engine
+          })
 
         
builder.withCustomHttpsConnectionContext(connectionContext).managedPersistentHttp2()
       } else {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to