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

stoty pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite-avatica.git


The following commit(s) were added to refs/heads/main by this push:
     new dc597c69a [CALCITE-1480] Support specifying ciphersuites and 
algorithms for TLS
dc597c69a is described below

commit dc597c69ac6115b6aa5e7256ce08d8b82c2ea205
Author: Istvan Toth <[email protected]>
AuthorDate: Mon Jul 14 09:10:20 2025 +0200

    [CALCITE-1480] Support specifying ciphersuites and algorithms for TLS
---
 .../apache/calcite/avatica/server/HttpServer.java  |  35 +++++-
 .../org/apache/calcite/avatica/TLSCipherTest.java  | 127 +++++++++++++++++++++
 2 files changed, 161 insertions(+), 1 deletion(-)

diff --git 
a/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java 
b/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
index 9c6b44cb2..cb9fa4dee 100644
--- a/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
+++ b/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
@@ -526,6 +526,9 @@ public static class Builder<T> {
 
     private String keystoreType;
 
+    private String[] includeProtocols;
+    private String[] includeCipherSuites;
+
     private List<ServerCustomizer<T>> serverCustomizers = 
Collections.emptyList();
 
     // The maximum size in bytes of an http header the server will read (64KB)
@@ -795,6 +798,29 @@ public Builder<T> withTLS(File keystore, String 
keystorePassword, File truststor
       return this;
     }
 
+    /**
+     * Configures the server to use TLS for wire encryption.
+     *
+     * @param keystore The server's keystore
+     * @param keystorePassword The keystore's password
+     * @param truststore The truststore containing the key used to generate 
the server's key
+     * @param truststorePassword The truststore's password
+     * @param keyStoreType The keystore's type
+     * @param includeProtocols Included TLS protocols, as expected by Jetty
+     * @param includeCipherSuites Included cypher suites, as expected by Jetty
+     * @return <code>this</code>
+     */
+    public Builder<T> withTLS(File keystore, String keystorePassword, File 
truststore,
+            String truststorePassword, String keyStoreType, String[] 
includeProtocols,
+            String[] includeCipherSuites) {
+      this.withTLS(keystore, keystorePassword, truststore, truststorePassword);
+      // we don't want to force specifying a keyStoreType here, null is default
+      this.keystoreType = keyStoreType;
+      this.includeProtocols = includeProtocols;
+      this.includeCipherSuites = includeCipherSuites;
+      return this;
+    }
+
     /**
      * Adds customizers to configure a Server before startup.
      *
@@ -870,7 +896,8 @@ public HttpServer build() {
           maxAllowedHeaderSize);
     }
 
-    protected SslContextFactory.Server buildSSLContextFactory() {
+    // Visible for testing
+    public SslContextFactory.Server buildSSLContextFactory() {
       SslContextFactory.Server sslFactory = null;
       if (usingTLS) {
         sslFactory = new SslContextFactory.Server();
@@ -881,6 +908,12 @@ protected SslContextFactory.Server 
buildSSLContextFactory() {
         if (keystoreType != null && 
!keystoreType.equals(DEFAULT_KEYSTORE_TYPE)) {
           sslFactory.setKeyStoreType(keystoreType);
         }
+        if (includeProtocols != null) {
+          sslFactory.setIncludeProtocols(includeProtocols);
+        }
+        if (includeCipherSuites != null) {
+          sslFactory.setIncludeCipherSuites(includeCipherSuites);
+        }
       }
       return sslFactory;
     }
diff --git a/server/src/test/java/org/apache/calcite/avatica/TLSCipherTest.java 
b/server/src/test/java/org/apache/calcite/avatica/TLSCipherTest.java
new file mode 100644
index 000000000..48936489f
--- /dev/null
+++ b/server/src/test/java/org/apache/calcite/avatica/TLSCipherTest.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.avatica;
+
+import org.apache.calcite.avatica.remote.Driver.Serialization;
+import org.apache.calcite.avatica.server.HttpServer;
+import org.apache.calcite.avatica.server.HttpServer.Builder;
+
+import org.eclipse.jetty.util.ssl.SslContextFactory.Server;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.sql.SQLException;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * Simple unit tests for testing that the protocol/cipher suite parameters are 
properly propagated
+ * to Jetty.
+ */
+public class TLSCipherTest extends HttpBaseTest {
+
+  public TLSCipherTest() {
+    super("dummy");
+  }
+
+  @BeforeClass
+  public static void setup() throws SQLException {
+    setupClass();
+  }
+
+  @Test
+  public void testTLSv11() {
+    String[] protocolList = new String[] { "TLSv1.1" };
+
+    Builder httpServerBuilder =
+        new HttpServer.Builder()
+            .withPort(0)
+            .withTLS(KEYSTORE, KEYSTORE_PASSWORD, KEYSTORE, KEYSTORE_PASSWORD, 
null,
+              protocolList, null)
+            .withHandler(localService, Serialization.PROTOBUF);
+
+    Server sslFactory = httpServerBuilder.buildSSLContextFactory();
+    assertArrayEquals(protocolList, sslFactory.getIncludeProtocols());
+  }
+
+  @Test
+  public void testTLSv1112() {
+    String[] protocolList = new String[] { "TLSv1.1", "TLSv1.2" };
+
+    Builder httpServerBuilder =
+        new HttpServer.Builder()
+            .withPort(0)
+            .withTLS(KEYSTORE, KEYSTORE_PASSWORD, KEYSTORE, KEYSTORE_PASSWORD, 
null,
+              protocolList, null)
+            .withHandler(localService, Serialization.PROTOBUF);
+
+    Server sslFactory = httpServerBuilder.buildSSLContextFactory();
+    assertArrayEquals(protocolList, sslFactory.getIncludeProtocols());
+  }
+
+  @Test
+  public void testSingleCipherSuite() {
+    String[] cipherSuiteList = new String[] { 
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" };
+
+    Builder httpServerBuilder =
+        new HttpServer.Builder()
+            .withPort(0)
+            .withTLS(KEYSTORE, KEYSTORE_PASSWORD, KEYSTORE, KEYSTORE_PASSWORD, 
null,
+              null, cipherSuiteList)
+            .withHandler(localService, Serialization.PROTOBUF);
+
+    Server sslFactory = httpServerBuilder.buildSSLContextFactory();
+    assertArrayEquals(cipherSuiteList, sslFactory.getIncludeCipherSuites());
+  }
+
+  @Test
+  public void testMultipleCipherSuites() {
+    String[] cipherSuiteList =
+        new String[] { "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+            "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" };
+
+    Builder httpServerBuilder =
+        new HttpServer.Builder()
+            .withPort(0)
+            .withTLS(KEYSTORE, KEYSTORE_PASSWORD, KEYSTORE, KEYSTORE_PASSWORD, 
null,
+              null, cipherSuiteList)
+            .withHandler(localService, Serialization.PROTOBUF);
+
+    Server sslFactory = httpServerBuilder.buildSSLContextFactory();
+    assertArrayEquals(cipherSuiteList, sslFactory.getIncludeCipherSuites());
+  }
+
+  @Test
+  public void testProtocolAndCipherSuites() {
+    String[] protocolList = new String[] { "TLSv1.2" };
+    String[] cipherSuiteList =
+        new String[] { "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+            "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" };
+
+    Builder httpServerBuilder =
+        new HttpServer.Builder()
+            .withPort(0)
+            .withTLS(KEYSTORE, KEYSTORE_PASSWORD, KEYSTORE, KEYSTORE_PASSWORD, 
null,
+              protocolList, cipherSuiteList)
+            .withHandler(localService, Serialization.PROTOBUF);
+
+    Server sslFactory = httpServerBuilder.buildSSLContextFactory();
+    assertArrayEquals(protocolList, sslFactory.getIncludeProtocols());
+    assertArrayEquals(cipherSuiteList, sslFactory.getIncludeCipherSuites());
+  }
+
+}

Reply via email to