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 b7865e47a Apply the configured log user and group lists to daemon log
requests (#8973)
b7865e47a is described below
commit b7865e47abadb315556a694dcdbb7a8568bae3ee
Author: Richard Zowalla <[email protected]>
AuthorDate: Sat Aug 22 19:29:55 2026 +0200
Apply the configured log user and group lists to daemon log requests (#8973)
---
.../logviewer/handler/LogviewerLogPageHandler.java | 4 +
.../handler/LogviewerLogSearchHandler.java | 3 +-
.../daemon/logviewer/utils/LogFileDownloader.java | 3 +-
.../daemon/logviewer/utils/ResourceAuthorizer.java | 35 +++++++
.../handler/LogviewerLogDownloadHandlerTest.java | 56 +++++++++-
.../handler/LogviewerLogPageHandlerTest.java | 43 +++++++-
.../handler/LogviewerLogSearchHandlerTest.java | 51 +++++++++
.../logviewer/utils/ResourceAuthorizerTest.java | 114 +++++++++++++++++++++
8 files changed, 305 insertions(+), 4 deletions(-)
diff --git
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogPageHandler.java
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogPageHandler.java
index 5917e9746..b1144ca65 100644
---
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogPageHandler.java
+++
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogPageHandler.java
@@ -313,6 +313,10 @@ public class LogviewerLogPageHandler {
return LogviewerResponseBuilder.buildResponsePageNotFound();
}
+ if (!resourceAuthorizer.isUserAllowedToAccessDaemonFile(user)) {
+ return
LogviewerResponseBuilder.buildResponseUnauthorizedUser(user);
+ }
+
if (file.toFile().exists()) {
// all types of files included
List<File> logFiles =
Arrays.stream(daemonLogRoot.toFile().listFiles())
diff --git
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandler.java
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandler.java
index 3c884b08e..99da13fb1 100644
---
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandler.java
+++
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandler.java
@@ -165,7 +165,8 @@ public class LogviewerLogSearchHandler {
}
Response response;
if (absFile.toFile().exists()) {
- if (isDaemon || resourceAuthorizer.isUserAllowedToAccessFile(user,
fileName)) {
+ if (isDaemon ?
resourceAuthorizer.isUserAllowedToAccessDaemonFile(user)
+ : resourceAuthorizer.isUserAllowedToAccessFile(user,
fileName)) {
Integer numMatchesInt = numMatchesStr != null ?
tryParseIntParam("num-matches", numMatchesStr) : null;
Integer offsetInt = offsetStr != null ?
tryParseIntParam("start-byte-offset", offsetStr) : null;
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 919c0df04..04e08bfc4 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
@@ -81,7 +81,8 @@ public class LogFileDownloader {
}
if (file.toFile().exists()) {
- if (isDaemon || resourceAuthorizer.isUserAllowedToAccessFile(user,
fileName)) {
+ if (isDaemon ?
resourceAuthorizer.isUserAllowedToAccessDaemonFile(user)
+ : 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);
diff --git
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/utils/ResourceAuthorizer.java
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/utils/ResourceAuthorizer.java
index e88431cc9..9f321fc19 100644
---
a/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/utils/ResourceAuthorizer.java
+++
b/storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/utils/ResourceAuthorizer.java
@@ -72,6 +72,41 @@ public class ResourceAuthorizer {
return !isLogviewerFilterConfigured() || isAuthorizedLogUser(user,
fileName);
}
+ /**
+ * Checks whether user is allowed to access a daemon log file via UI.
Daemon logs have no owning topology, so only the
+ * cluster level lists are consulted. Always true when the Logviewer
filter is not configured.
+ *
+ * @param user username
+ */
+ public boolean isUserAllowedToAccessDaemonFile(String user) {
+ return !isLogviewerFilterConfigured() ||
isAuthorizedDaemonLogUser(user);
+ }
+
+ /**
+ * Checks whether user is authorized to access daemon log files. Checks
regardless of UI filter.
+ *
+ * @param user username
+ */
+ public boolean isAuthorizedDaemonLogUser(String user) {
+ if (StringUtils.isEmpty(user)) {
+ return false;
+ }
+
+ List<String> logsUsers = new ArrayList<>();
+
logsUsers.addAll(ObjectReader.getStrings(stormConf.get(DaemonConfig.LOGS_USERS)));
+
logsUsers.addAll(ObjectReader.getStrings(stormConf.get(Config.NIMBUS_ADMINS)));
+
+ List<String> logsGroups = new ArrayList<>();
+
logsGroups.addAll(ObjectReader.getStrings(stormConf.get(DaemonConfig.LOGS_GROUPS)));
+
logsGroups.addAll(ObjectReader.getStrings(stormConf.get(Config.NIMBUS_ADMINS_GROUPS)));
+
+ String userName = principalToLocal.toLocal(user);
+ Set<String> groups = getUserGroups(userName);
+
+ return logsUsers.stream().anyMatch(u -> u.equals(userName))
+ || Sets.intersection(groups, new HashSet<>(logsGroups)).size() > 0;
+ }
+
/**
* Checks whether user is authorized to access file. Checks regardless of
UI filter.
*
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 5a6f34fda..0d40fce8d 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
@@ -31,11 +31,14 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.net.HttpHeaders;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.StreamingOutput;
import org.apache.storm.daemon.logviewer.utils.ResourceAuthorizer;
import org.apache.storm.daemon.logviewer.utils.WorkerLogs;
import org.apache.storm.metric.StormMetricsRegistry;
@@ -199,7 +202,58 @@ public class LogviewerLogDownloadHandlerTest {
}
}
+ @Test
+ public void testDownloadDaemonLogFileUnauthorizedUser() throws IOException
{
+ try (TmpPath rootPath = new TmpPath()) {
+
+ ResourceAuthorizer resourceAuthorizer =
mock(ResourceAuthorizer.class);
+
when(resourceAuthorizer.isUserAllowedToAccessDaemonFile(anyString())).thenReturn(false);
+ LogviewerLogDownloadHandler handler =
createHandlerTraversalTests(rootPath.getFile().toPath(), resourceAuthorizer);
+
+ Response response = handler.downloadDaemonLogFile("host",
"nimbus.log", "user");
+
+ Utils.forceDelete(rootPath.toString());
+
+ assertThat(response.getStatus(),
is(Response.Status.FORBIDDEN.getStatusCode()));
+ }
+ }
+
+ @Test
+ public void testDownloadDaemonLogFileAuthorizedUser() throws IOException {
+ try (TmpPath rootPath = new TmpPath()) {
+
+ ResourceAuthorizer resourceAuthorizer =
mock(ResourceAuthorizer.class);
+
when(resourceAuthorizer.isUserAllowedToAccessDaemonFile(anyString())).thenReturn(true);
+ LogviewerLogDownloadHandler handler =
createHandlerTraversalTests(rootPath.getFile().toPath(), resourceAuthorizer);
+ //Give the daemon log some content, so that the response is only
empty if the file was not served.
+
Files.writeString(rootPath.getFile().toPath().resolve("logs").resolve("nimbus.log"),
"nimbus log content");
+
+ Response response = handler.downloadDaemonLogFile("host",
"nimbus.log", "user");
+ int status = response.getStatus();
+ String content = status == Response.Status.OK.getStatusCode() ?
readEntity(response) : null;
+
+ Utils.forceDelete(rootPath.toString());
+
+ assertThat(status, is(Response.Status.OK.getStatusCode()));
+ assertThat(content, is("nimbus log content"));
+ String contentDisposition =
response.getHeaderString(HttpHeaders.CONTENT_DISPOSITION);
+ assertThat(contentDisposition, containsString("host-nimbus.log"));
+ verify(resourceAuthorizer).isUserAllowedToAccessDaemonFile("user");
+ }
+ }
+
+ private String readEntity(Response response) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ((StreamingOutput) response.getEntity()).write(out);
+ return out.toString(StandardCharsets.UTF_8);
+ }
+
private LogviewerLogDownloadHandler createHandlerTraversalTests(Path
rootPath) throws IOException {
+ return createHandlerTraversalTests(rootPath, new
ResourceAuthorizer(Utils.readStormConfig()));
+ }
+
+ private LogviewerLogDownloadHandler createHandlerTraversalTests(Path
rootPath, ResourceAuthorizer resourceAuthorizer)
+ throws IOException {
Path daemonLogRoot = rootPath.resolve("logs");
Path fileOutsideDaemonRoot = rootPath.resolve("evil.sh");
Path workerLogRoot = daemonLogRoot.resolve("workers-artifacts");
@@ -221,7 +275,7 @@ public class LogviewerLogDownloadHandlerTest {
Map<String, Object> stormConf = Utils.readStormConfig();
StormMetricsRegistry metricsRegistry = new StormMetricsRegistry();
return new LogviewerLogDownloadHandler(workerLogRoot.toString(),
daemonLogRoot.toString(),
- new WorkerLogs(stormConf, workerLogRoot, metricsRegistry), new
ResourceAuthorizer(stormConf), metricsRegistry);
+ new WorkerLogs(stormConf, workerLogRoot, metricsRegistry),
resourceAuthorizer, metricsRegistry);
}
}
diff --git
a/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogPageHandlerTest.java
b/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogPageHandlerTest.java
index b6de62009..0d277cf8a 100644
---
a/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogPageHandlerTest.java
+++
b/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogPageHandlerTest.java
@@ -18,6 +18,7 @@
package org.apache.storm.daemon.logviewer.handler;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -214,7 +215,47 @@ public class LogviewerLogPageHandlerTest {
}
}
+ @Test
+ public void testDaemonLogPageUnauthorizedUser() throws Exception {
+ try (TmpPath rootPath = new TmpPath()) {
+ ResourceAuthorizer resourceAuthorizer =
mock(ResourceAuthorizer.class);
+
when(resourceAuthorizer.isUserAllowedToAccessDaemonFile(anyString())).thenReturn(false);
+ LogviewerLogPageHandler handler =
createHandlerForTraversalTests(rootPath.getFile().toPath(), resourceAuthorizer);
+ //Give the daemon log some content, so that an unauthorized
request is the only reason not to render the page.
+
Files.writeString(rootPath.getFile().toPath().resolve("logs").resolve("nimbus.log"),
"nimbus log content");
+
+ final Response returned = handler.daemonLogPage("nimbus.log", 0,
100, null, "user");
+
+ Utils.forceDelete(rootPath.toString());
+
+ assertThat(returned.getStatus(),
is(Response.Status.FORBIDDEN.getStatusCode()));
+ }
+ }
+
+ @Test
+ public void testDaemonLogPageAuthorizedUser() throws Exception {
+ try (TmpPath rootPath = new TmpPath()) {
+ ResourceAuthorizer resourceAuthorizer =
mock(ResourceAuthorizer.class);
+
when(resourceAuthorizer.isUserAllowedToAccessDaemonFile(anyString())).thenReturn(true);
+ LogviewerLogPageHandler handler =
createHandlerForTraversalTests(rootPath.getFile().toPath(), resourceAuthorizer);
+
Files.writeString(rootPath.getFile().toPath().resolve("logs").resolve("nimbus.log"),
"nimbus log content");
+
+ final Response returned = handler.daemonLogPage("nimbus.log", 0,
100, null, "user");
+
+ Utils.forceDelete(rootPath.toString());
+
+ assertThat(returned.getStatus(),
is(Response.Status.OK.getStatusCode()));
+ assertThat((String) returned.getEntity(), containsString("nimbus
log content"));
+ verify(resourceAuthorizer).isUserAllowedToAccessDaemonFile("user");
+ }
+ }
+
private LogviewerLogPageHandler createHandlerForTraversalTests(Path
rootPath) throws IOException {
+ return createHandlerForTraversalTests(rootPath, new
ResourceAuthorizer(Utils.readStormConfig()));
+ }
+
+ private LogviewerLogPageHandler createHandlerForTraversalTests(Path
rootPath, ResourceAuthorizer resourceAuthorizer)
+ throws IOException {
Path daemonLogRoot = rootPath.resolve("logs");
Path fileOutsideDaemonRoot = rootPath.resolve("evil.sh");
Path daemonFile = daemonLogRoot.resolve("nimbus.log");
@@ -236,6 +277,6 @@ public class LogviewerLogPageHandlerTest {
Map<String, Object> stormConf = Utils.readStormConfig();
StormMetricsRegistry metricsRegistry = new StormMetricsRegistry();
return new LogviewerLogPageHandler(workerLogRoot.toString(),
daemonLogRoot.toString(),
- new WorkerLogs(stormConf, workerLogRoot, metricsRegistry), new
ResourceAuthorizer(stormConf), metricsRegistry);
+ new WorkerLogs(stormConf, workerLogRoot, metricsRegistry),
resourceAuthorizer, metricsRegistry);
}
}
diff --git
a/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandlerTest.java
b/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandlerTest.java
index 66415b3cf..90c15c861 100644
---
a/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandlerTest.java
+++
b/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandlerTest.java
@@ -34,6 +34,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
@@ -47,12 +49,15 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
+import jakarta.ws.rs.core.Response;
+
import org.apache.storm.DaemonConfig;
import org.apache.storm.daemon.logviewer.LogviewerConstant;
import org.apache.storm.daemon.logviewer.utils.ResourceAuthorizer;
import org.apache.storm.daemon.ui.InvalidRequestException;
import org.apache.storm.metric.StormMetricsRegistry;
import org.apache.storm.streams.tuple.Tuple3;
+import org.apache.storm.testing.TmpPath;
import org.apache.storm.utils.Utils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -863,6 +868,52 @@ public class LogviewerLogSearchHandlerTest {
}
}
+ @Test
+ public void testSearchDaemonLogFileUnauthorizedUser() throws Exception {
+ try (TmpPath rootPath = new TmpPath()) {
+ Path daemonLogRoot = rootPath.getFile().toPath().resolve("logs");
+ Files.createDirectories(daemonLogRoot);
+ Files.createFile(daemonLogRoot.resolve("nimbus.log"));
+
+ Map<String, Object> stormConf = Utils.readStormConfig();
+ ResourceAuthorizer resourceAuthorizer =
mock(ResourceAuthorizer.class);
+
when(resourceAuthorizer.isUserAllowedToAccessDaemonFile(anyString())).thenReturn(false);
+ LogviewerLogSearchHandler handler = new
LogviewerLogSearchHandler(stormConf, Paths.get(""), daemonLogRoot,
+ resourceAuthorizer, new StormMetricsRegistry());
+
+ Response response = handler.searchLogFile("nimbus.log", "user",
true, "needle", null, null, null, null);
+
+ assertEquals(403, response.getStatus());
+ }
+ }
+
+ @Test
+ public void testSearchDaemonLogFileAuthorizedUser() throws Exception {
+ try (TmpPath rootPath = new TmpPath()) {
+ Path daemonLogRoot = rootPath.getFile().toPath().resolve("logs");
+ Files.createDirectories(daemonLogRoot);
+ Files.writeString(daemonLogRoot.resolve("nimbus.log"), "a needle
in the daemon log\n");
+
+ Map<String, Object> stormConf = Utils.readStormConfig();
+ ResourceAuthorizer resourceAuthorizer =
mock(ResourceAuthorizer.class);
+
when(resourceAuthorizer.isUserAllowedToAccessDaemonFile(anyString())).thenReturn(true);
+ LogviewerLogSearchHandler handler = new
LogviewerLogSearchHandler(stormConf, Paths.get(""), daemonLogRoot,
+ resourceAuthorizer, new StormMetricsRegistry());
+
+ Response response = handler.searchLogFile("nimbus.log", "user",
true, "needle", null, null, null, null);
+
+ assertEquals(200, response.getStatus());
+ Map<?, ?> entity = new ObjectMapper().readValue((String)
response.getEntity(), Map.class);
+ assertEquals("needle", entity.get("searchString"));
+ assertEquals("yes", entity.get("isDaemon"));
+ //A match must actually be reported, an empty match list would
mean the file was never read.
+ List<?> matches = (List<?>) entity.get("matches");
+ assertEquals(1, matches.size());
+ assertEquals("needle", ((Map<?, ?>)
matches.get(0)).get("matchString"));
+ verify(resourceAuthorizer).isUserAllowedToAccessDaemonFile("user");
+ }
+ }
+
private static LogviewerLogSearchHandler getSearchHandler() {
Map<String, Object> stormConf = Utils.readStormConfig();
return new LogviewerLogSearchHandler(stormConf, Paths.get(""),
Paths.get(""),
diff --git
a/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/utils/ResourceAuthorizerTest.java
b/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/utils/ResourceAuthorizerTest.java
index 6db742432..96407bca1 100644
---
a/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/utils/ResourceAuthorizerTest.java
+++
b/storm-webapp/src/test/java/org/apache/storm/daemon/logviewer/utils/ResourceAuthorizerTest.java
@@ -19,8 +19,10 @@
package org.apache.storm.daemon.logviewer.utils;
import static org.apache.storm.Config.NIMBUS_ADMINS;
+import static org.apache.storm.Config.NIMBUS_ADMINS_GROUPS;
import static org.apache.storm.Config.TOPOLOGY_GROUPS;
import static org.apache.storm.Config.TOPOLOGY_USERS;
+import static org.apache.storm.DaemonConfig.LOGS_GROUPS;
import static org.apache.storm.DaemonConfig.LOGS_USERS;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -211,4 +213,116 @@ public class ResourceAuthorizerTest {
authorized = authorizer.isUserAllowedToAccessFile("bob", "anyfile");
assertFalse(authorized); // filter configured, should fail all users
}
+
+ /**
+ * daemon logs are allowed for cluster logs users and cluster admins only.
+ */
+ @Test
+ public void
testAuthorizedDaemonLogUserAllowsClusterLogsUserAndClusterAdmin() {
+ Map<String, Object> stormConf = Utils.readStormConfig();
+
+ Map<String, Object> conf = new HashMap<>(stormConf);
+ conf.put(LOGS_USERS, Collections.singletonList("alice"));
+ conf.put(NIMBUS_ADMINS, Collections.singletonList("bob"));
+
+ ResourceAuthorizer authorizer = spy(new ResourceAuthorizer(conf));
+
+
doReturn(Collections.emptySet()).when(authorizer).getUserGroups(anyString());
+
+ assertTrue(authorizer.isAuthorizedDaemonLogUser("alice"));
+ assertTrue(authorizer.isAuthorizedDaemonLogUser("bob"));
+ assertFalse(authorizer.isAuthorizedDaemonLogUser("mallory"));
+ }
+
+ /**
+ * daemon logs are allowed for a user whose groups are listed in
logs.groups.
+ */
+ @Test
+ public void testAuthorizedDaemonLogUserAllowsClusterLogsGroup() {
+ Map<String, Object> stormConf = Utils.readStormConfig();
+
+ Map<String, Object> conf = new HashMap<>(stormConf);
+ conf.put(LOGS_GROUPS, Collections.singletonList("alice-group"));
+
+ ResourceAuthorizer authorizer = spy(new ResourceAuthorizer(conf));
+
+
doReturn(Collections.singleton("alice-group")).when(authorizer).getUserGroups(anyString());
+
+ //alice is not named in logs.users nor in nimbus.admins, she is
authorized purely by her group membership
+ assertTrue(authorizer.isAuthorizedDaemonLogUser("alice"));
+ }
+
+ /**
+ * daemon logs are allowed for a user whose groups are listed in
nimbus.admins.groups.
+ */
+ @Test
+ public void testAuthorizedDaemonLogUserAllowsClusterAdminGroup() {
+ Map<String, Object> stormConf = Utils.readStormConfig();
+
+ Map<String, Object> conf = new HashMap<>(stormConf);
+ conf.put(NIMBUS_ADMINS_GROUPS,
Collections.singletonList("admin-group"));
+
+ ResourceAuthorizer authorizer = spy(new ResourceAuthorizer(conf));
+
+
doReturn(Collections.singleton("admin-group")).when(authorizer).getUserGroups(anyString());
+
+ //alice is not named in logs.users nor in nimbus.admins, she is
authorized purely by her group membership
+ assertTrue(authorizer.isAuthorizedDaemonLogUser("alice"));
+ }
+
+ /**
+ * daemon logs are denied for a user whose groups match neither
logs.groups nor nimbus.admins.groups.
+ */
+ @Test
+ public void testAuthorizedDaemonLogUserDisallowsUnrelatedGroup() {
+ Map<String, Object> stormConf = Utils.readStormConfig();
+
+ Map<String, Object> conf = new HashMap<>(stormConf);
+ conf.put(LOGS_GROUPS, Collections.singletonList("logs-group"));
+ conf.put(NIMBUS_ADMINS_GROUPS,
Collections.singletonList("admin-group"));
+
+ ResourceAuthorizer authorizer = spy(new ResourceAuthorizer(conf));
+
+
doReturn(Collections.singleton("mallory-group")).when(authorizer).getUserGroups(anyString());
+
+ assertFalse(authorizer.isAuthorizedDaemonLogUser("mallory"));
+ }
+
+ /**
+ * daemon log access via the UI filter is granted by group membership
alone.
+ */
+ @Test
+ public void testUserAllowedToAccessDaemonFileByGroupWhenFilterConfigured()
{
+ Map<String, Object> stormConf = Utils.readStormConfig();
+
+ Map<String, Object> conf = new HashMap<>(stormConf);
+ conf.put(LOGS_GROUPS, Collections.singletonList("alice-group"));
+ conf.put(DaemonConfig.LOGVIEWER_FILTER, "someFilter");
+
+ ResourceAuthorizer authorizer = spy(new ResourceAuthorizer(conf));
+
+
doReturn(Collections.singleton("alice-group")).when(authorizer).getUserGroups(anyString());
+
+ assertTrue(authorizer.isUserAllowedToAccessDaemonFile("alice"));
+ }
+
+ /**
+ * daemon log access consults the cluster level lists once a filter is
configured.
+ */
+ @Test
+ public void daemonLogAuthorizationFailsWhenFilterConfigured() {
+ Map<String, Object> stormConf = Utils.readStormConfig();
+ Map<String, Object> conf = new HashMap<>(stormConf);
+ conf.put(LOGS_USERS, Collections.singletonList("alice"));
+
+ ResourceAuthorizer authorizer = spy(new ResourceAuthorizer(conf));
+
+
doReturn(Collections.emptySet()).when(authorizer).getUserGroups(anyString());
+
+ assertTrue(authorizer.isUserAllowedToAccessDaemonFile("bob")); // no
filter configured, allow anyone
+
+ conf.put(DaemonConfig.LOGVIEWER_FILTER, "someFilter");
+ assertTrue(authorizer.isUserAllowedToAccessDaemonFile("alice"));
+ assertFalse(authorizer.isUserAllowedToAccessDaemonFile("bob"));
+ }
}