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());
+ }
+
+}