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

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


The following commit(s) were added to refs/heads/master by this push:
     new cb8d29b0b Change the worker log file permission only for download 
requests that are served (#8978)
cb8d29b0b is described below

commit cb8d29b0bdf4b480a35facc67d40f8e605acced2
Author: Richard Zowalla <[email protected]>
AuthorDate: Sat Aug 22 18:13:58 2026 +0200

    Change the worker log file permission only for download requests that are 
served (#8978)
---
 .../handler/LogviewerLogDownloadHandler.java       |  5 +-
 .../daemon/logviewer/utils/LogFileDownloader.java  | 11 ++-
 .../handler/LogviewerLogDownloadHandlerTest.java   | 78 ++++++++++++++++++++++
 3 files changed, 88 insertions(+), 6 deletions(-)

diff --git 
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogDownloadHandler.java
 
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogDownloadHandler.java
index 49ac9aadd..5c6f91377 100644
--- 
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogDownloadHandler.java
+++ 
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogDownloadHandler.java
@@ -29,7 +29,6 @@ import org.apache.storm.metric.StormMetricsRegistry;
 
 public class LogviewerLogDownloadHandler {
 
-    private WorkerLogs workerLogs;
     private final LogFileDownloader logFileDownloadHelper;
 
     /**
@@ -43,8 +42,7 @@ public class LogviewerLogDownloadHandler {
      */
     public LogviewerLogDownloadHandler(String logRoot, String daemonLogRoot, 
WorkerLogs workerLogs,
         ResourceAuthorizer resourceAuthorizer, StormMetricsRegistry 
metricsRegistry) {
-        this.workerLogs = workerLogs;
-        this.logFileDownloadHelper = new LogFileDownloader(logRoot, 
daemonLogRoot, resourceAuthorizer, metricsRegistry);
+        this.logFileDownloadHelper = new LogFileDownloader(logRoot, 
daemonLogRoot, workerLogs, resourceAuthorizer, metricsRegistry);
     }
 
     /**
@@ -57,7 +55,6 @@ public class LogviewerLogDownloadHandler {
      *
      */
     public Response downloadLogFile(String host, String fileName, String user) 
throws IOException {
-        workerLogs.setLogFilePermission(fileName);
         return logFileDownloadHelper.downloadFile(host, fileName, user, false);
     }
 
diff --git 
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/utils/LogFileDownloader.java
 
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/utils/LogFileDownloader.java
index ef3c961f1..919c0df04 100644
--- 
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/utils/LogFileDownloader.java
+++ 
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/utils/LogFileDownloader.java
@@ -36,6 +36,7 @@ public class LogFileDownloader {
     private final Meter numFileDownloadExceptions;
     private final Path logRoot;
     private final Path daemonLogRoot;
+    private final WorkerLogs workerLogs;
     private final ResourceAuthorizer resourceAuthorizer;
 
     /**
@@ -43,13 +44,15 @@ public class LogFileDownloader {
      *
      * @param logRoot root worker log directory
      * @param daemonLogRoot root daemon log directory
+     * @param workerLogs {@link WorkerLogs}
      * @param resourceAuthorizer {@link ResourceAuthorizer}
      * @param metricsRegistry The logviewer metrics registry
      */
-    public LogFileDownloader(String logRoot, String daemonLogRoot, 
ResourceAuthorizer resourceAuthorizer,
-        StormMetricsRegistry metricsRegistry) {
+    public LogFileDownloader(String logRoot, String daemonLogRoot, WorkerLogs 
workerLogs,
+        ResourceAuthorizer resourceAuthorizer, StormMetricsRegistry 
metricsRegistry) {
         this.logRoot = Paths.get(logRoot).toAbsolutePath().normalize();
         this.daemonLogRoot = 
Paths.get(daemonLogRoot).toAbsolutePath().normalize();
+        this.workerLogs = workerLogs;
         this.resourceAuthorizer = resourceAuthorizer;
         this.fileDownloadSizeDistMb = 
metricsRegistry.registerHistogram("logviewer:download-file-size-rounded-MB");
         this.numFileDownloadExceptions = 
metricsRegistry.registerMeter(ExceptionMeterNames.NUM_FILE_DOWNLOAD_EXCEPTIONS);
@@ -79,6 +82,10 @@ public class LogFileDownloader {
         
         if (file.toFile().exists()) {
             if (isDaemon || resourceAuthorizer.isUserAllowedToAccessFile(user, 
fileName)) {
+                if (!isDaemon) {
+                    //Only widen the permission of a worker log once the 
request is known to be served
+                    workerLogs.setLogFilePermission(fileName);
+                }
                 fileDownloadSizeDistMb.update(Math.round((double) 
file.toFile().length() / FileUtils.ONE_MB));
                 String downloadedFileName;
                 Path pathRelativeToRootDir = rootDir.relativize(file);
diff --git 
a/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogDownloadHandlerTest.java
 
b/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogDownloadHandlerTest.java
index 1853d5aed..5a6f34fda 100644
--- 
a/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogDownloadHandlerTest.java
+++ 
b/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogDownloadHandlerTest.java
@@ -24,6 +24,11 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.common.net.HttpHeaders;
 import java.io.IOException;
@@ -121,6 +126,79 @@ public class LogviewerLogDownloadHandlerTest {
         }
     }
 
+    @Test
+    public void 
testDownloadLogFileUnauthorizedUserDoesNotChangeLogFilePermission() throws 
IOException {
+        try (TmpPath rootPath = new TmpPath()) {
+            Path daemonLogRoot = rootPath.getFile().toPath().resolve("logs");
+            Path workerLogRoot = daemonLogRoot.resolve("workers-artifacts");
+            Path file = 
workerLogRoot.resolve("topoA").resolve("1111").resolve("worker.log");
+            Files.createDirectories(file.getParent());
+            Files.createFile(file);
+
+            ResourceAuthorizer resourceAuthorizer = 
mock(ResourceAuthorizer.class);
+            when(resourceAuthorizer.isUserAllowedToAccessFile(anyString(), 
anyString())).thenReturn(false);
+            WorkerLogs workerLogs = mock(WorkerLogs.class);
+
+            LogviewerLogDownloadHandler handler = new 
LogviewerLogDownloadHandler(workerLogRoot.toString(),
+                daemonLogRoot.toString(), workerLogs, resourceAuthorizer, new 
StormMetricsRegistry());
+
+            Response response = handler.downloadLogFile("host", 
"topoA/1111/worker.log", "user");
+
+            Utils.forceDelete(rootPath.toString());
+
+            assertThat(response.getStatus(), 
is(Response.Status.FORBIDDEN.getStatusCode()));
+            verify(workerLogs, never()).setLogFilePermission(anyString());
+        }
+    }
+
+    @Test
+    public void testDownloadLogFileAuthorizedUserSetsLogFilePermission() 
throws IOException {
+        try (TmpPath rootPath = new TmpPath()) {
+            Path daemonLogRoot = rootPath.getFile().toPath().resolve("logs");
+            Path workerLogRoot = daemonLogRoot.resolve("workers-artifacts");
+            Path file = 
workerLogRoot.resolve("topoA").resolve("1111").resolve("worker.log");
+            Files.createDirectories(file.getParent());
+            Files.createFile(file);
+
+            ResourceAuthorizer resourceAuthorizer = 
mock(ResourceAuthorizer.class);
+            when(resourceAuthorizer.isUserAllowedToAccessFile(anyString(), 
anyString())).thenReturn(true);
+            WorkerLogs workerLogs = mock(WorkerLogs.class);
+
+            LogviewerLogDownloadHandler handler = new 
LogviewerLogDownloadHandler(workerLogRoot.toString(),
+                daemonLogRoot.toString(), workerLogs, resourceAuthorizer, new 
StormMetricsRegistry());
+
+            Response response = handler.downloadLogFile("host", 
"topoA/1111/worker.log", "user");
+
+            Utils.forceDelete(rootPath.toString());
+
+            assertThat(response.getStatus(), 
is(Response.Status.OK.getStatusCode()));
+            verify(workerLogs).setLogFilePermission("topoA/1111/worker.log");
+        }
+    }
+
+    @Test
+    public void testDownloadDaemonLogFileDoesNotChangeLogFilePermission() 
throws IOException {
+        try (TmpPath rootPath = new TmpPath()) {
+            Path daemonLogRoot = rootPath.getFile().toPath().resolve("logs");
+            Path workerLogRoot = daemonLogRoot.resolve("workers-artifacts");
+            Path daemonFile = daemonLogRoot.resolve("nimbus.log");
+            Files.createDirectories(workerLogRoot);
+            Files.createFile(daemonFile);
+
+            WorkerLogs workerLogs = mock(WorkerLogs.class);
+
+            LogviewerLogDownloadHandler handler = new 
LogviewerLogDownloadHandler(workerLogRoot.toString(),
+                daemonLogRoot.toString(), workerLogs, new 
ResourceAuthorizer(Utils.readStormConfig()), new StormMetricsRegistry());
+
+            Response response = handler.downloadDaemonLogFile("host", 
"nimbus.log", "user");
+
+            Utils.forceDelete(rootPath.toString());
+
+            assertThat(response.getStatus(), 
is(Response.Status.OK.getStatusCode()));
+            verify(workerLogs, never()).setLogFilePermission(anyString());
+        }
+    }
+
     private LogviewerLogDownloadHandler createHandlerTraversalTests(Path 
rootPath) throws IOException {
         Path daemonLogRoot = rootPath.resolve("logs");
         Path fileOutsideDaemonRoot = rootPath.resolve("evil.sh");

Reply via email to