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 5aaf365468 NIFI-14514 ListSmb skips folders it cannot access due to 
insufficient permissions
5aaf365468 is described below

commit 5aaf365468c661ee7e525f1b7a80d93e97f811e5
Author: Peter Turcsanyi <[email protected]>
AuthorDate: Tue May 6 18:19:51 2025 +0200

    NIFI-14514 ListSmb skips folders it cannot access due to insufficient 
permissions
    
    This closes #9917.
    
    Signed-off-by: Tamas Palfy <[email protected]>
---
 .../services/smb/SmbClientProviderService.java     |  3 +-
 .../org/apache/nifi/processors/smb/FetchSmb.java   |  4 +--
 .../org/apache/nifi/processors/smb/ListSmb.java    |  2 +-
 .../apache/nifi/processors/smb/FetchSmbTest.java   |  3 +-
 .../apache/nifi/processors/smb/ListSmbTest.java    |  5 +--
 .../services/smb/SmbjClientProviderService.java    |  5 +--
 .../nifi/services/smb/SmbjClientService.java       | 22 ++++++++++--
 .../nifi/services/smb/SmbjClientServiceIT.java     | 40 +++++++++++++++++++++-
 .../nifi/services/smb/SmbjClientServiceTest.java   | 39 ++++++++++++++-------
 9 files changed, 99 insertions(+), 24 deletions(-)

diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-client-api/src/main/java/org/apache/nifi/services/smb/SmbClientProviderService.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-client-api/src/main/java/org/apache/nifi/services/smb/SmbClientProviderService.java
index 3dc23f1aa0..c451d9e45c 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-client-api/src/main/java/org/apache/nifi/services/smb/SmbClientProviderService.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-client-api/src/main/java/org/apache/nifi/services/smb/SmbClientProviderService.java
@@ -19,6 +19,7 @@ package org.apache.nifi.services.smb;
 import java.io.IOException;
 import java.net.URI;
 import org.apache.nifi.controller.ControllerService;
+import org.apache.nifi.logging.ComponentLog;
 
 public interface SmbClientProviderService extends ControllerService {
 
@@ -34,6 +35,6 @@ public interface SmbClientProviderService extends 
ControllerService {
      *
      * @return the client.
      */
-    SmbClientService getClient() throws IOException;
+    SmbClientService getClient(ComponentLog logger) throws IOException;
 
 }
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/FetchSmb.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/FetchSmb.java
index 52feec30f1..92d1a4d5ad 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/FetchSmb.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/FetchSmb.java
@@ -150,7 +150,7 @@ public class FetchSmb extends AbstractProcessor {
 
         final SmbClientProviderService clientProviderService = 
context.getProperty(SMB_CLIENT_PROVIDER_SERVICE).asControllerService(SmbClientProviderService.class);
 
-        try (SmbClientService client = clientProviderService.getClient()) {
+        try (SmbClientService client = 
clientProviderService.getClient(getLogger())) {
             flowFile = session.write(flowFile, outputStream -> 
client.readFile(filePath, outputStream));
 
             session.transfer(flowFile, REL_SUCCESS);
@@ -183,7 +183,7 @@ public class FetchSmb extends AbstractProcessor {
 
         final SmbClientProviderService clientProviderService = 
context.getProperty(SMB_CLIENT_PROVIDER_SERVICE).asControllerService(SmbClientProviderService.class);
 
-        try (SmbClientService client = clientProviderService.getClient()) {
+        try (SmbClientService client = 
clientProviderService.getClient(getLogger())) {
             if (completionStrategy == CompletionStrategy.MOVE) {
                 final String destinationDirectory = 
context.getProperty(DESTINATION_DIRECTORY).evaluateAttributeExpressions(attributes).getValue();
                 final boolean createDestinationDirectory = 
context.getProperty(CREATE_DESTINATION_DIRECTORY).asBoolean();
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/ListSmb.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/ListSmb.java
index b2f45ec4a5..156659e1d5 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/ListSmb.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/ListSmb.java
@@ -443,7 +443,7 @@ public class ListSmb extends 
AbstractListProcessor<SmbListableEntity> {
         final SmbClientProviderService clientProviderService =
                 
context.getProperty(SMB_CLIENT_PROVIDER_SERVICE).asControllerService(SmbClientProviderService.class);
         final String directory = getDirectory(context);
-        final SmbClientService clientService = 
clientProviderService.getClient();
+        final SmbClientService clientService = 
clientProviderService.getClient(getLogger());
         return clientService.listFiles(directory).onClose(() -> {
             try {
                 clientService.close();
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/test/java/org/apache/nifi/processors/smb/FetchSmbTest.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/test/java/org/apache/nifi/processors/smb/FetchSmbTest.java
index 6847fccb41..1b344a1bd5 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/test/java/org/apache/nifi/processors/smb/FetchSmbTest.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/test/java/org/apache/nifi/processors/smb/FetchSmbTest.java
@@ -23,6 +23,7 @@ import java.net.URI;
 import java.util.HashMap;
 import java.util.Map;
 import org.apache.commons.io.IOUtils;
+import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.services.smb.SmbClientProviderService;
 import org.apache.nifi.services.smb.SmbClientService;
 import org.apache.nifi.services.smb.SmbException;
@@ -62,7 +63,7 @@ class FetchSmbTest {
     @BeforeEach
     public void beforeEach() throws Exception {
         mockCloseable = MockitoAnnotations.openMocks(this);
-        
when(clientProviderService.getClient()).thenReturn(mockNifiSmbClientService);
+        
when(clientProviderService.getClient(any(ComponentLog.class))).thenReturn(mockNifiSmbClientService);
         
when(clientProviderService.getIdentifier()).thenReturn(CLIENT_SERVICE_PROVIDER_ID);
         
when(clientProviderService.getServiceLocation()).thenReturn(URI.create("smb://localhost:445/share"));
     }
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/test/java/org/apache/nifi/processors/smb/ListSmbTest.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/test/java/org/apache/nifi/processors/smb/ListSmbTest.java
index cacf587634..2c13fbdb17 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/test/java/org/apache/nifi/processors/smb/ListSmbTest.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/test/java/org/apache/nifi/processors/smb/ListSmbTest.java
@@ -48,6 +48,7 @@ import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 import org.apache.nifi.distributed.cache.client.DistributedMapCacheClient;
+import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.processor.util.list.ListedEntity;
 import org.apache.nifi.processors.smb.util.InitialListingStrategy;
 import org.apache.nifi.services.smb.SmbClientProviderService;
@@ -113,7 +114,7 @@ class ListSmbTest {
         final SmbClientProviderService clientProviderService = 
mock(SmbClientProviderService.class);
         
when(clientProviderService.getIdentifier()).thenReturn("different-client-provider");
         
when(clientProviderService.getServiceLocation()).thenReturn(URI.create("smb://localhost:445/share"));
-        
when(clientProviderService.getClient()).thenReturn(mockNifiSmbClientService);
+        
when(clientProviderService.getClient(any(ComponentLog.class))).thenReturn(mockNifiSmbClientService);
         testRunner.setProperty(SMB_CLIENT_PROVIDER_SERVICE, 
"different-client-provider");
         testRunner.addControllerService("different-client-provider", 
clientProviderService);
         testRunner.enableControllerService(clientProviderService);
@@ -309,7 +310,7 @@ class ListSmbTest {
         testRunner.setProperty(DIRECTORY, "testDirectory");
 
         final SmbClientProviderService clientProviderService = 
mockSmbClientProviderService();
-        
when(clientProviderService.getClient()).thenReturn(mockNifiSmbClientService);
+        
when(clientProviderService.getClient(any(ComponentLog.class))).thenReturn(mockNifiSmbClientService);
         testRunner.setProperty(SMB_CLIENT_PROVIDER_SERVICE, 
CLIENT_SERVICE_PROVIDER_ID);
         testRunner.addControllerService(CLIENT_SERVICE_PROVIDER_ID, 
clientProviderService);
         testRunner.enableControllerService(clientProviderService);
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 7d6258c1ee..85c773daff 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
@@ -29,6 +29,7 @@ import org.apache.nifi.annotation.lifecycle.OnEnabled;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.controller.AbstractControllerService;
 import org.apache.nifi.controller.ConfigurationContext;
+import org.apache.nifi.logging.ComponentLog;
 
 import java.io.IOException;
 import java.net.URI;
@@ -149,7 +150,7 @@ public class SmbjClientProviderService extends 
AbstractControllerService impleme
     }
 
     @Override
-    public SmbClientService getClient() throws IOException {
+    public SmbClientService getClient(final ComponentLog logger) throws 
IOException {
         final Connection connection = smbClient.connect(hostname, port);
 
         final Session session;
@@ -173,7 +174,7 @@ public class SmbjClientProviderService extends 
AbstractControllerService impleme
             throw new IllegalArgumentException("DiskShare not found. Share " + 
share.getClass().getSimpleName() + " found on " + getServiceLocation());
         }
 
-        return new SmbjClientService(session, (DiskShare) share, 
getServiceLocation());
+        return new SmbjClientService(session, (DiskShare) share, 
getServiceLocation(), logger);
     }
 
     private void closeSession(final Session session) {
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientService.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientService.java
index 4e04bf85d1..6e0ab503b6 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientService.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientService.java
@@ -31,6 +31,7 @@ import com.hierynomus.smbj.session.Session;
 import com.hierynomus.smbj.share.Directory;
 import com.hierynomus.smbj.share.DiskShare;
 import com.hierynomus.smbj.share.File;
+import org.apache.nifi.logging.ComponentLog;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,11 +52,13 @@ class SmbjClientService implements SmbClientService {
     private final Session session;
     private final DiskShare share;
     private final URI serviceLocation;
+    private final ComponentLog logger;
 
-    SmbjClientService(final Session session, final DiskShare share, final URI 
serviceLocation) {
+    SmbjClientService(final Session session, final DiskShare share, final URI 
serviceLocation, final ComponentLog logger) {
         this.session = session;
         this.share = share;
         this.serviceLocation = serviceLocation;
+        this.logger = logger;
     }
 
     @Override
@@ -72,7 +75,22 @@ class SmbjClientService implements SmbClientService {
     @Override
     public Stream<SmbListableEntity> listFiles(final String directoryPath) {
         return Stream.of(directoryPath).flatMap(path -> {
-            final Directory directory = openDirectory(path);
+            final Directory directory;
+            try {
+                directory = openDirectory(path);
+            } catch (SMBApiException e) {
+                if (e.getStatus() == NtStatus.STATUS_ACCESS_DENIED) {
+                    logger.warn("Could not list directory [{}/{}] because the 
user does not have access to it.", serviceLocation, path, e);
+                    return Stream.empty();
+                } else if (e.getStatus() == NtStatus.STATUS_BAD_NETWORK_NAME) {
+                    // DFS resolution may return STATUS_BAD_NETWORK_NAME if 
the user does not have access at share level
+                    logger.warn("Could not list directory [{}/{}] because the 
share does not exist or the user does not have access to it.", serviceLocation, 
path, e);
+                    return Stream.empty();
+                } else {
+                    throw e;
+                }
+            }
+
             return stream(directory::spliterator, 0, false)
                     .map(entity -> buildSmbListableEntity(entity, path, 
serviceLocation))
                     .filter(entity -> !specialDirectory(entity))
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/test/java/org/apache/nifi/services/smb/SmbjClientServiceIT.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/test/java/org/apache/nifi/services/smb/SmbjClientServiceIT.java
index fc1d4ca3b5..5d34305b4a 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/test/java/org/apache/nifi/services/smb/SmbjClientServiceIT.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/test/java/org/apache/nifi/services/smb/SmbjClientServiceIT.java
@@ -24,8 +24,10 @@ import static 
org.apache.nifi.services.smb.SmbjClientProviderService.PORT;
 import static org.apache.nifi.services.smb.SmbjClientProviderService.SHARE;
 import static org.apache.nifi.services.smb.SmbjClientProviderService.USERNAME;
 import static org.apache.nifi.smb.common.SmbProperties.TIMEOUT;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.Mockito.mock;
 
 import eu.rekawek.toxiproxy.Proxy;
 import eu.rekawek.toxiproxy.ToxiproxyClient;
@@ -41,6 +43,7 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.util.MockConfigurationContext;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -130,7 +133,7 @@ public class SmbjClientServiceIT {
                 SmbClientService s = null;
                 try {
 
-                    s = smbjClientProviderService.getClient();
+                    s = 
smbjClientProviderService.getClient(mock(ComponentLog.class));
                     if (iteration == 25) {
                         proxy.toxics().bandwidth("CUT_CONNECTION_DOWNSTREAM", 
ToxicDirection.DOWNSTREAM, 0L);
                         proxy.toxics().bandwidth("CUT_CONNECTION_UPSTREAM", 
ToxicDirection.UPSTREAM, 0L);
@@ -176,6 +179,41 @@ public class SmbjClientServiceIT {
         smbjClientProviderService.onDisabled();
     }
 
+    @Test
+    public void shouldContinueListingAfterPermissionDenied() throws Exception {
+        writeFile("testDirectory/directory1/file1", "content");
+        writeFile("testDirectory/directory2/file2", "content");
+        writeFile("testDirectory/directory3/file3", "content");
+
+        sambaContainer.execInContainer("bash", "-c", "chmod 000 
/folder/testDirectory/directory2");
+
+        SmbjClientProviderService smbjClientProviderService = new 
SmbjClientProviderService();
+
+        Map<PropertyDescriptor, String> properties = new HashMap<>();
+        properties.put(HOSTNAME, sambaContainer.getHost());
+        properties.put(PORT, 
String.valueOf(sambaContainer.getMappedPort(445)));
+        properties.put(SHARE, "share");
+        properties.put(USERNAME, "username");
+        properties.put(PASSWORD, "password");
+        properties.put(DOMAIN, "domain");
+        properties.put(TIMEOUT, "0.5 sec");
+
+        MockConfigurationContext mockConfigurationContext = new 
MockConfigurationContext(properties, null, null);
+        smbjClientProviderService.onEnabled(mockConfigurationContext);
+
+        SmbClientService smbClientService = 
smbjClientProviderService.getClient(mock(ComponentLog.class));
+
+        final Set<String> actual = smbClientService.listFiles("testDirectory")
+                .map(SmbListableEntity::getIdentifier)
+                .collect(toSet());
+
+        assertEquals(2, actual.size());
+        assertTrue(actual.contains("testDirectory/directory1/file1"));
+        assertTrue(actual.contains("testDirectory/directory3/file3"));
+
+        smbjClientProviderService.onDisabled();
+    }
+
     private void writeFile(String path, String content) {
         String containerPath = "/folder/" + path;
         sambaContainer.copyFileToContainer(Transferable.of(content), 
containerPath);
diff --git 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/test/java/org/apache/nifi/services/smb/SmbjClientServiceTest.java
 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/test/java/org/apache/nifi/services/smb/SmbjClientServiceTest.java
index 13fafdf58b..fdaf8ab714 100644
--- 
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/test/java/org/apache/nifi/services/smb/SmbjClientServiceTest.java
+++ 
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/test/java/org/apache/nifi/services/smb/SmbjClientServiceTest.java
@@ -16,16 +16,22 @@
  */
 package org.apache.nifi.services.smb;
 
+import com.hierynomus.mserref.NtStatus;
+import com.hierynomus.mssmb2.SMBApiException;
 import com.hierynomus.smbj.session.Session;
 import com.hierynomus.smbj.share.DiskShare;
-import org.junit.jupiter.api.AfterEach;
+import org.apache.nifi.logging.ComponentLog;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -37,26 +43,21 @@ class SmbjClientServiceTest {
     @Mock
     DiskShare share;
 
+    @Mock
+    ComponentLog logger;
+
     @InjectMocks
     SmbjClientService underTest;
 
-    private AutoCloseable mockCloseable;
-
     @BeforeEach
-    public void beforeEach() {
+    void beforeEach() {
         MockitoAnnotations.openMocks(this);
-    }
 
-    @AfterEach
-    public void closeMock() throws Exception {
-        if (mockCloseable != null) {
-            mockCloseable.close();
-        }
+        when(session.connectShare(anyString())).thenReturn(share);
     }
 
     @Test
-    public void shouldCreateDirectoriesRecursively() throws Exception {
-        when(session.connectShare(anyString())).thenReturn(share);
+    void ensureDirectoryShouldCreateDirectoriesRecursively() throws Exception {
         when(share.fileExists("directory")).thenReturn(true);
         when(share.fileExists("path")).thenReturn(false);
         when(share.fileExists("to")).thenReturn(false);
@@ -67,7 +68,21 @@ class SmbjClientServiceTest {
         verify(share).mkdir("directory/path");
         verify(share).mkdir("directory/path/to");
         verify(share).mkdir("directory/path/to/create");
+    }
 
+    @Test
+    void listFilesShouldHandlePermissionErrors() {
+        mockOpenDirectory("dir1", NtStatus.STATUS_ACCESS_DENIED);
+        mockOpenDirectory("dir2", NtStatus.STATUS_BAD_NETWORK_NAME);
+        mockOpenDirectory("dir3", NtStatus.STATUS_OTHER);
+
+        assertEquals(0, underTest.listFiles("dir1").count());
+        assertEquals(0, underTest.listFiles("dir2").count());
+        assertThrows(SMBApiException.class, () -> 
underTest.listFiles("dir3").count());
     }
 
+    private void mockOpenDirectory(String directoryName, NtStatus 
responseStatus) {
+        when(share.openDirectory(eq(directoryName), any(), any(), any(), 
any(), any()))
+                .thenThrow(new SMBApiException(responseStatus.getValue(), 
null, null));
+    }
 }
\ No newline at end of file

Reply via email to