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

jiangtian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 4256d38070d Add keystore truststore expire check and avoid unnecessary 
error log printed (#16552)
4256d38070d is described below

commit 4256d38070d0773b68a761a06836ad3f8b1d6793
Author: Haonan <[email protected]>
AuthorDate: Sat Oct 11 18:47:53 2025 +0800

    Add keystore truststore expire check and avoid unnecessary error log 
printed (#16552)
    
    * Add keystore truststore expire check
    
    * Avoid unnecessary error log printed
    
    * Avoid print file name when access denied
    
    * avoid file name printed
---
 .../apache/iotdb/rpc/BaseRpcTransportFactory.java  | 12 +++++-
 .../iotdb/rpc/NettyTNonblockingTransport.java      | 23 ++++++++---
 .../apache/iotdb/rpc/TElasticFramedTransport.java  | 10 +++++
 .../org/apache/iotdb/db/service/RestService.java   |  2 +-
 .../service/AbstractThriftServiceThread.java       | 45 +++++++++++++++++++++-
 5 files changed, 83 insertions(+), 9 deletions(-)

diff --git 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java
 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java
index 1175b16a935..eccebe2eafe 100644
--- 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java
+++ 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java
@@ -26,6 +26,10 @@ import org.apache.thrift.transport.TTransport;
 import org.apache.thrift.transport.TTransportException;
 import org.apache.thrift.transport.TTransportFactory;
 
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
 @SuppressWarnings("java:S1135") // ignore todos
 public class BaseRpcTransportFactory extends TTransportFactory {
 
@@ -95,8 +99,12 @@ public class BaseRpcTransportFactory extends 
TTransportFactory {
       throws TTransportException {
     TSSLTransportFactory.TSSLTransportParameters params =
         new TSSLTransportFactory.TSSLTransportParameters();
-    params.setTrustStore(trustStore, trustStorePwd);
-    params.setKeyStore(keyStore, keyStorePwd);
+    if (Files.exists(Paths.get(trustStore)) && 
Files.exists(Paths.get(keyStore))) {
+      params.setTrustStore(trustStore, trustStorePwd);
+      params.setKeyStore(keyStore, keyStorePwd);
+    } else {
+      throw new TTransportException(new IOException("Could not load keystore 
or truststore file"));
+    }
     TTransport transport = TSSLTransportFactory.getClientSocket(ip, port, 
timeout, params);
     return inner.getTransport(transport);
   }
diff --git 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/NettyTNonblockingTransport.java
 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/NettyTNonblockingTransport.java
index 8cf6c51a95c..b42b901cc18 100644
--- 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/NettyTNonblockingTransport.java
+++ 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/NettyTNonblockingTransport.java
@@ -47,6 +47,7 @@ import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.TrustManagerFactory;
 
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
@@ -54,6 +55,7 @@ import java.nio.ByteBuffer;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
+import java.nio.file.AccessDeniedException;
 import java.security.KeyStore;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -166,12 +168,15 @@ public class NettyTNonblockingTransport extends 
TNonblockingTransport {
                                   "SSL handshake completed successfully for 
{}:{}", host, port);
                             }
                           } else {
-                            if (logger.isDebugEnabled()) {
+                            if (!future
+                                .cause()
+                                .getMessage()
+                                .contains("SslHandler removed before handshake 
completed")) {
+                              logger.warn(
+                                  "SSL handshake failed for {}:{}", host, 
port, future.cause());
+                            } else if (logger.isDebugEnabled()) {
                               logger.debug(
-                                  "SSL handshake failed for {}:{}: {}",
-                                  host,
-                                  port,
-                                  future.cause().getMessage());
+                                  "SSL handshake failed for {}:{}", host, 
port, future.cause());
                             }
                           }
                         });
@@ -187,6 +192,10 @@ public class NettyTNonblockingTransport extends 
TNonblockingTransport {
       KeyStore keyStore = KeyStore.getInstance("JKS");
       try (FileInputStream fis = new FileInputStream(keystorePath)) {
         keyStore.load(fis, keystorePassword.toCharArray());
+      } catch (AccessDeniedException e) {
+        throw new AccessDeniedException("Failed to load keystore file");
+      } catch (FileNotFoundException e) {
+        throw new FileNotFoundException("keystore file not found");
       }
       KeyManagerFactory kmf =
           
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
@@ -198,6 +207,10 @@ public class NettyTNonblockingTransport extends 
TNonblockingTransport {
       KeyStore trustStore = KeyStore.getInstance("JKS");
       try (FileInputStream fis = new FileInputStream(truststorePath)) {
         trustStore.load(fis, truststorePassword.toCharArray());
+      } catch (AccessDeniedException e) {
+        throw new AccessDeniedException("Failed to load truststore file");
+      } catch (FileNotFoundException e) {
+        throw new FileNotFoundException("truststore file not found");
       }
       TrustManagerFactory tmf =
           
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
diff --git 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TElasticFramedTransport.java
 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TElasticFramedTransport.java
index 05a6a83117d..0ff58f71e12 100644
--- 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TElasticFramedTransport.java
+++ 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TElasticFramedTransport.java
@@ -25,6 +25,9 @@ import org.apache.thrift.transport.TTransportException;
 import org.apache.thrift.transport.TTransportFactory;
 import org.apache.thrift.transport.layered.TFramedTransport;
 
+import javax.net.ssl.SSLHandshakeException;
+
+import java.io.EOFException;
 import java.net.SocketTimeoutException;
 
 // https://github.com/apache/thrift/blob/master/doc/specs/thrift-rpc.md
@@ -126,6 +129,13 @@ public class TElasticFramedTransport extends TTransport {
       if (e.getCause() instanceof SocketTimeoutException) {
         throw new TTransportException(TTransportException.TIMED_OUT, 
e.getCause());
       }
+      // When client with SSL shut down due to time out. Some unnecessary 
error logs may be printed.
+      // Adding this workaround to avoid the problem.
+      if (e.getCause() instanceof SSLHandshakeException
+          && e.getCause().getCause() != null
+          && e.getCause().getCause() instanceof EOFException) {
+        throw new TTransportException(TTransportException.END_OF_FILE, 
e.getCause());
+      }
       throw e;
     }
     return readBuffer.read(buf, off, len);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/RestService.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/RestService.java
index fa8df0c9a69..7fc4d788380 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/RestService.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/RestService.java
@@ -67,7 +67,7 @@ public class RestService implements IService {
     if (clientAuth) {
       sslContextFactory.setTrustStorePath(trustStorePath);
       sslContextFactory.setTrustStorePassword(trustStorePwd);
-      sslContextFactory.setNeedClientAuth(clientAuth);
+      sslContextFactory.setNeedClientAuth(true);
     }
 
     ServerConnector httpsConnector =
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java
index 7537308d6cd..39b11ba677a 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java
@@ -44,7 +44,13 @@ import org.apache.thrift.transport.TTransportFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.net.InetSocketAddress;
+import java.nio.file.AccessDeniedException;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -177,13 +183,15 @@ public abstract class AbstractThriftServiceThread extends 
Thread {
     this.serviceName = serviceName;
 
     try {
+      validateCertificate(keyStorePath, keyStorePwd);
       TSSLTransportFactory.TSSLTransportParameters params =
           new TSSLTransportFactory.TSSLTransportParameters();
       params.setKeyStore(keyStorePath, keyStorePwd);
       if (trustStorePath != null && !trustStorePath.isEmpty()) {
+        validateCertificate(trustStorePath, trustStorePwd);
         params.setTrustStore(trustStorePath, trustStorePwd);
+        params.requireClientAuth(true);
       }
-      params.requireClientAuth(false);
       InetSocketAddress socketAddress = new InetSocketAddress(bindAddress, 
port);
       serverTransport =
           TSSLTransportFactory.getServerSocket(
@@ -197,6 +205,41 @@ public abstract class AbstractThriftServiceThread extends 
Thread {
     }
   }
 
+  private static void validateCertificate(String keyStorePath, String 
keystorePassword)
+      throws TTransportException {
+    try {
+      KeyStore keystore = KeyStore.getInstance("JKS");
+      try (FileInputStream fis = new FileInputStream(keyStorePath)) {
+        keystore.load(fis, keystorePassword.toCharArray());
+      }
+
+      Enumeration<String> aliases = keystore.aliases();
+      while (aliases.hasMoreElements()) {
+        String currentAlias = aliases.nextElement();
+        checkCertificate(keystore, currentAlias);
+      }
+    } catch (AccessDeniedException e) {
+      throw new TTransportException("Failed to load keystore or truststore 
file");
+    } catch (FileNotFoundException e) {
+      throw new TTransportException("keystore or truststore file not found");
+    } catch (Exception e) {
+      throw new TTransportException(e);
+    }
+  }
+
+  private static void checkCertificate(KeyStore keystore, String alias) throws 
Exception {
+    if (!keystore.containsAlias(alias)) {
+      return;
+    }
+
+    X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
+    if (cert == null) {
+      return;
+    }
+
+    cert.checkValidity();
+  }
+
   @SuppressWarnings("squid:S107")
   protected AbstractThriftServiceThread(
       TProcessor processor,

Reply via email to