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

tpalfy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 30f0f4c71a4 NIFI-16385 Made connection validation optional in SMB 
components (#11719)
30f0f4c71a4 is described below

commit 30f0f4c71a4522c6421f12eba81fd0d06e4f8648
Author: Peter Turcsanyi <[email protected]>
AuthorDate: Fri Sep 25 15:16:49 2026 +0200

    NIFI-16385 Made connection validation optional in SMB components (#11719)
    
    Signed-off-by: Tamas Palfy <[email protected]>
---
 .../org/apache/nifi/processors/smb/GetSmbFile.java |  2 ++
 .../org/apache/nifi/processors/smb/PutSmbFile.java |  2 ++
 .../services/smb/SmbjClientProviderService.java    |  2 ++
 .../nifi/services/smb/SmbjClientProvider.java      | 37 ++++++++++++++++++++--
 .../java/org/apache/nifi/smb/common/SmbClient.java | 23 ++++++++------
 .../org/apache/nifi/smb/common/SmbProperties.java  | 10 ++++++
 .../java/org/apache/nifi/smb/common/SmbUtils.java  |  5 ++-
 7 files changed, 69 insertions(+), 12 deletions(-)

diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/GetSmbFile.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/GetSmbFile.java
index 5860926e41d..99ffa22e837 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/GetSmbFile.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/GetSmbFile.java
@@ -76,6 +76,7 @@ import static 
org.apache.nifi.processors.smb.util.LocalSmbProperties.DOMAIN;
 import static org.apache.nifi.processors.smb.util.LocalSmbProperties.PASSWORD;
 import static 
org.apache.nifi.processors.smb.util.LocalSmbProperties.SMB_CLIENT_PROVIDER_SERVICE;
 import static org.apache.nifi.processors.smb.util.LocalSmbProperties.USERNAME;
+import static org.apache.nifi.smb.common.SmbProperties.CONNECTION_VALIDATION;
 import static org.apache.nifi.smb.common.SmbProperties.ENABLE_DFS;
 import static 
org.apache.nifi.smb.common.SmbProperties.OLD_ENABLE_DFS_PROPERTY_NAME;
 import static 
org.apache.nifi.smb.common.SmbProperties.OLD_SMB_DIALECT_PROPERTY_NAME;
@@ -221,6 +222,7 @@ public class GetSmbFile extends AbstractProcessor {
         SMB_DIALECT,
         USE_ENCRYPTION,
         ENABLE_DFS,
+        CONNECTION_VALIDATION,
         TIMEOUT
     );
 
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/PutSmbFile.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/PutSmbFile.java
index cfda90ec298..8bd0ad10d24 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/PutSmbFile.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/PutSmbFile.java
@@ -68,6 +68,7 @@ import static 
org.apache.nifi.processors.smb.util.LocalSmbProperties.SMB_DIALECT
 import static org.apache.nifi.processors.smb.util.LocalSmbProperties.TIMEOUT;
 import static org.apache.nifi.processors.smb.util.LocalSmbProperties.USERNAME;
 import static 
org.apache.nifi.processors.smb.util.LocalSmbProperties.USE_ENCRYPTION;
+import static org.apache.nifi.smb.common.SmbProperties.CONNECTION_VALIDATION;
 import static 
org.apache.nifi.smb.common.SmbProperties.OLD_ENABLE_DFS_PROPERTY_NAME;
 import static 
org.apache.nifi.smb.common.SmbProperties.OLD_SMB_DIALECT_PROPERTY_NAME;
 import static 
org.apache.nifi.smb.common.SmbProperties.OLD_TIMEOUT_PROPERTY_NAME;
@@ -164,6 +165,7 @@ public class PutSmbFile extends AbstractProcessor {
             SMB_DIALECT,
             USE_ENCRYPTION,
             ENABLE_DFS,
+            CONNECTION_VALIDATION,
             TIMEOUT);
 
     private static final Set<Relationship> RELATIONSHIPS = Set.of(
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientProviderService.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientProviderService.java
index 0b438746839..029c3907ea6 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientProviderService.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientProviderService.java
@@ -32,6 +32,7 @@ import java.util.List;
 import java.util.Map;
 
 import static org.apache.nifi.smb.common.SmbProperties.AUTHENTICATION_TYPE;
+import static org.apache.nifi.smb.common.SmbProperties.CONNECTION_VALIDATION;
 import static org.apache.nifi.smb.common.SmbProperties.DOMAIN;
 import static org.apache.nifi.smb.common.SmbProperties.ENABLE_DFS;
 import static org.apache.nifi.smb.common.SmbProperties.HOSTNAME;
@@ -70,6 +71,7 @@ public class SmbjClientProviderService extends 
AbstractControllerService impleme
             SMB_DIALECT,
             USE_ENCRYPTION,
             ENABLE_DFS,
+            CONNECTION_VALIDATION,
             TIMEOUT
     );
 
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/services/smb/SmbjClientProvider.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/services/smb/SmbjClientProvider.java
index 9f2162538ba..809dd5890ee 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/services/smb/SmbjClientProvider.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/services/smb/SmbjClientProvider.java
@@ -16,9 +16,11 @@
  */
 package org.apache.nifi.services.smb;
 
+import com.hierynomus.protocol.transport.TransportException;
 import com.hierynomus.smbj.SMBClient;
 import com.hierynomus.smbj.auth.AuthenticationContext;
 import com.hierynomus.smbj.auth.GSSAuthenticationContext;
+import com.hierynomus.smbj.common.SMBRuntimeException;
 import com.hierynomus.smbj.connection.Connection;
 import com.hierynomus.smbj.session.Session;
 import com.hierynomus.smbj.share.DiskShare;
@@ -94,14 +96,17 @@ public class SmbjClientProvider implements 
SmbClientProvider, Closeable {
 
     @Override
     public SmbClientService getClient(final ComponentLog logger, final 
Map<String, String> attributes) throws IOException {
-        final Connection connection = 
smbClient.connect(getHostname(attributes), getPort(attributes));
+        final String hostname = getHostname(attributes);
+        final Integer port = getPort(attributes);
         final URI serviceLocation = getServiceLocation(attributes);
 
+        final AuthenticationContext authenticationContext = 
createAuthenticationContext(logger);
+
         final Session session;
         final Share share;
 
         try {
-            session = 
connection.authenticate(createAuthenticationContext(logger));
+            session = createSession(hostname, port, authenticationContext);
         } catch (Exception e) {
             throw new IOException("Could not create session for share " + 
serviceLocation, e);
         }
@@ -121,6 +126,34 @@ public class SmbjClientProvider implements 
SmbClientProvider, Closeable {
         return new SmbjClientService(session, (DiskShare) share, 
getServiceLocation(attributes), logger);
     }
 
+    private Session createSession(String hostname, int port, 
AuthenticationContext authenticationContext) throws IOException {
+        Connection connection = smbClient.connect(hostname, port);
+
+        try {
+            return connection.authenticate(authenticationContext);
+        } catch (SMBRuntimeException e) {
+            if (e.getCause() != null && e.getCause() instanceof 
TransportException) {
+                logger.info("Stale connection found, unregistering it and 
creating a new one");
+
+                closeConnection(connection);
+                connection = smbClient.connect(hostname, port);
+
+                return connection.authenticate(authenticationContext);
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    private void closeConnection(final Connection connection) {
+        try {
+            if (connection != null) {
+                connection.close(true);
+            }
+        } catch (Exception e) {
+            logger.info("Could not close connection to {}", 
getServiceLocation(), e);
+        }
+    }
 
     private void closeSession(final Session session, URI serviceLocation) {
         try {
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbClient.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbClient.java
index 92dec5f957f..b170f78e136 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbClient.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbClient.java
@@ -29,7 +29,7 @@ import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
 /**
- * Extends {@link SMBClient} with connection health check.
+ * Extends {@link SMBClient} with optional connection health check.
  * <br/>
  * Workaround to https://github.com/hierynomus/smbj/issues/796.
  * <br/><br/>
@@ -49,20 +49,21 @@ class SmbClient extends SMBClient {
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(SmbClient.class);
 
-    private SMBEventBus bus;
+    private final SMBEventBus bus;
 
-    private SmbClient(final SmbConfig config, final SMBEventBus bus) {
+    private final boolean connectionValidationEnabled;
+
+    private SmbClient(final SmbConfig config, final SMBEventBus bus, final 
boolean connectionValidationEnabled) {
         super(config, bus);
+
+        this.bus = bus;
+        this.connectionValidationEnabled = connectionValidationEnabled;
     }
 
-    static SmbClient create(final SmbConfig config) {
+    static SmbClient create(final SmbConfig config, final boolean 
connectionValidationEnabled) {
         final SMBEventBus bus = new SMBEventBus();
 
-        final SmbClient client = new SmbClient(config, bus);
-
-        client.bus = bus;
-
-        return client;
+        return new SmbClient(config, bus, connectionValidationEnabled);
     }
 
     @Override
@@ -74,6 +75,10 @@ class SmbClient extends SMBClient {
     public synchronized Connection connect(final String hostname, final int 
port) throws IOException {
         final Connection connection = super.connect(hostname, port);
 
+        if (!connectionValidationEnabled) {
+            return connection;
+        }
+
         try {
             // SMB2 ECHO message can only be sent if this is not a new 
connection (and health check is only needed in this case)
             if (!connection.release()) {
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbProperties.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbProperties.java
index be2e88f4c0c..a14b2e0c318 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbProperties.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbProperties.java
@@ -162,6 +162,16 @@ public class SmbProperties {
             .defaultValue("false")
             .build();
 
+    public static final PropertyDescriptor CONNECTION_VALIDATION = new 
PropertyDescriptor.Builder()
+            .name("Connection Validation")
+            .description("When enabled, validates reused SMB connections with 
an SMB2 ECHO request and replaces stale connections. Please note " +
+                    "that Windows and Linux/Samba servers support this way of 
validation but others may not. Connection validation must be enabled " +
+                    "when DFS is used.")
+            .required(true)
+            .allowableValues("true", "false")
+            .defaultValue("true")
+            .build();
+
     public static final PropertyDescriptor TIMEOUT = new 
PropertyDescriptor.Builder()
             .name("Timeout")
             .description("Timeout for read and write operations.")
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbUtils.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbUtils.java
index b705c5c38a5..bcc5c3aeee1 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbUtils.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbUtils.java
@@ -21,6 +21,7 @@ import com.hierynomus.smbj.SmbConfig;
 import org.apache.nifi.context.PropertyContext;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.apache.nifi.smb.common.SmbProperties.CONNECTION_VALIDATION;
 import static org.apache.nifi.smb.common.SmbProperties.ENABLE_DFS;
 import static org.apache.nifi.smb.common.SmbProperties.SMB_DIALECT;
 import static org.apache.nifi.smb.common.SmbProperties.TIMEOUT;
@@ -33,7 +34,9 @@ public final class SmbUtils {
     }
 
     public static SMBClient buildSmbClient(final PropertyContext context) {
-        return SmbClient.create(buildSmbConfig(context));
+        final boolean connectionValidationEnabled =  
context.getProperty(CONNECTION_VALIDATION).asBoolean();
+
+        return SmbClient.create(buildSmbConfig(context), 
connectionValidationEnabled);
     }
 
     static SmbConfig buildSmbConfig(final PropertyContext context) {

Reply via email to