This is an automated email from the ASF dual-hosted git repository.
abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new abac9e3 Revert permission changes to Supervisor and Task APIs (#11819)
abac9e3 is described below
commit abac9e39ed878daa06dde1483319c3b9f47ef33a
Author: Kashif Faraz <[email protected]>
AuthorDate: Mon Oct 25 14:50:38 2021 +0530
Revert permission changes to Supervisor and Task APIs (#11819)
* Revert "Require Datasource WRITE authorization for Supervisor and Task
access (#11718)"
This reverts commit f2d6100124dbe7cbc92ad91d28bd12a1800a1f2a.
* Revert "Require DATASOURCE WRITE access in SupervisorResourceFilter and
TaskResourceFilter (#11680)"
This reverts commit 6779c4652d531b4d2c7056a69660f4e318f4aef6.
* Fix docs for the reverted commits
* Fix and restore deleted tests
* Fix and restore SystemSchemaTest
---
docs/operations/security-overview.md | 2 +-
docs/operations/security-user-auth.md | 4 +-
.../druid/indexing/common/task/AbstractTask.java | 16 --
.../task/AppenderatorDriverRealtimeIndexTask.java | 5 +-
.../indexing/common/task/HadoopIndexTask.java | 3 +-
.../druid/indexing/common/task/IndexTask.java | 7 +-
.../druid/indexing/common/task/IndexTaskUtils.java | 13 +-
.../parallel/ParallelIndexSupervisorTask.java | 38 +++--
.../task/batch/parallel/SinglePhaseSubTask.java | 7 +-
.../indexing/overlord/http/OverlordResource.java | 6 +-
.../http/security/SupervisorResourceFilter.java | 11 +-
.../overlord/http/security/TaskResourceFilter.java | 5 +-
.../overlord/supervisor/SupervisorResource.java | 8 +-
.../SeekableStreamIndexTaskRunner.java | 32 ++--
.../druid/indexing/common/task/IndexTaskTest.java | 84 ----------
.../overlord/http/OverlordResourceTest.java | 38 +++--
.../security/SupervisorResourceFilterTest.java | 8 +-
.../supervisor/SupervisorResourceTest.java | 9 --
.../SeekableStreamIndexTaskRunnerAuthTest.java | 33 ++--
.../docker/ldap-configs/bootstrap.ldif | 74 ++++-----
.../security/AbstractAuthConfigurationTest.java | 175 ++++++---------------
.../security/ITBasicAuthConfigurationTest.java | 36 ++---
.../security/ITBasicAuthLdapConfigurationTest.java | 27 ++--
.../druid/sql/calcite/schema/SystemSchema.java | 4 +-
.../druid/sql/calcite/schema/SystemSchemaTest.java | 22 +--
25 files changed, 238 insertions(+), 429 deletions(-)
diff --git a/docs/operations/security-overview.md
b/docs/operations/security-overview.md
index 236b942..39cb0ca 100644
--- a/docs/operations/security-overview.md
+++ b/docs/operations/security-overview.md
@@ -51,7 +51,7 @@ The following recommendations apply to the network where
Druid runs:
* When possible, use firewall and other network layer filtering to only expose
Druid services and ports specifically required for your use case. For example,
only expose Broker ports to downstream applications that execute queries. You
can limit access to a specific IP address or IP range to further tighten and
enhance security.
The following recommendation applies to Druid's authorization and
authentication model:
-* Only grant `WRITE` permissions to any `DATASOURCE` to trusted users. Druid's
trust model assumes those users have the same privileges as the operating
system user that runs the Druid Console process. Additionally, users with
`WRITE` permissions can make changes to datasources and they have access to
both task and supervisor APIs which may return sensitive information.
+* Only grant `WRITE` permissions to any `DATASOURCE` to trusted users. Druid's
trust model assumes those users have the same privileges as the operating
system user that runs the Druid Console process. Additionally, users with
`WRITE` permissions can make changes to datasources and they have access to
both task and supervisor update (POST) APIs which may affect ingestion.
* Only grant `STATE READ`, `STATE WRITE`, `CONFIG WRITE`, and `DATASOURCE
WRITE` permissions to highly-trusted users. These permissions allow users to
access resources on behalf of the Druid server process regardless of the
datasource.
* If your Druid client application allows less-trusted users to control the
input source or firehose of an ingestion task, validate the URLs from the
users. It is possible to point unchecked URLs to other locations and resources
within your network or local file system.
diff --git a/docs/operations/security-user-auth.md
b/docs/operations/security-user-auth.md
index dad2a6b..7a49e21 100644
--- a/docs/operations/security-user-auth.md
+++ b/docs/operations/security-user-auth.md
@@ -142,8 +142,8 @@ Queries on the [system schema
tables](../querying/sql.md#system-schema) require
- `segments`: Druid filters segments according to DATASOURCE READ permissions.
- `servers`: The user requires STATE READ permissions.
- `server_segments`: The user requires STATE READ permissions. Druid filters
segments according to DATASOURCE READ permissions.
-- `tasks`: Druid filters tasks according to DATASOURCE WRITE permissions.
-- `supervisors`: Druid filters supervisors according to DATASOURCE WRITE
permissions.
+- `tasks`: Druid filters tasks according to DATASOURCE READ permissions.
+- `supervisors`: Druid filters supervisors according to DATASOURCE READ
permissions.
When the Broker property `druid.sql.planner.authorizeSystemTablesDirectly` is
true, users also require `SYSTEM_TABLE` authorization on a system schema table
to query it.
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractTask.java
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractTask.java
index e31270c..8964a1e 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractTask.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractTask.java
@@ -30,12 +30,9 @@ import
org.apache.druid.indexing.common.actions.LockListAction;
import org.apache.druid.indexing.common.actions.TaskActionClient;
import org.apache.druid.query.Query;
import org.apache.druid.query.QueryRunner;
-import org.apache.druid.server.security.AuthorizerMapper;
-import org.apache.druid.server.security.ForbiddenException;
import org.joda.time.Interval;
import javax.annotation.Nullable;
-import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
@@ -167,19 +164,6 @@ public abstract class AbstractTask implements Task
return TaskStatus.success(getId());
}
- /**
- * Authorizes WRITE action on a task's datasource
- *
- * @throws ForbiddenException if not authorized
- */
- public void authorizeRequestForDatasourceWrite(
- HttpServletRequest request,
- AuthorizerMapper authorizerMapper
- ) throws ForbiddenException
- {
- IndexTaskUtils.authorizeRequestForDatasourceWrite(request, dataSource,
authorizerMapper);
- }
-
@Override
public boolean equals(Object o)
{
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AppenderatorDriverRealtimeIndexTask.java
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AppenderatorDriverRealtimeIndexTask.java
index 30382ea..6712624 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AppenderatorDriverRealtimeIndexTask.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AppenderatorDriverRealtimeIndexTask.java
@@ -83,6 +83,7 @@ import
org.apache.druid.segment.realtime.firehose.ClippedFirehoseFactory;
import org.apache.druid.segment.realtime.firehose.EventReceiverFirehoseFactory;
import org.apache.druid.segment.realtime.firehose.TimedShutoffFirehoseFactory;
import org.apache.druid.segment.realtime.plumber.Committers;
+import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthorizerMapper;
import org.apache.druid.timeline.partition.NumberedPartialShardSpec;
import org.apache.druid.utils.CloseableUtils;
@@ -529,7 +530,7 @@ public class AppenderatorDriverRealtimeIndexTask extends
AbstractTask implements
@Context final HttpServletRequest req
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
Map<String, Object> returnMap = new HashMap<>();
Map<String, Object> totalsMap = new HashMap<>();
Map<String, Object> averagesMap = new HashMap<>();
@@ -555,7 +556,7 @@ public class AppenderatorDriverRealtimeIndexTask extends
AbstractTask implements
@Context final HttpServletRequest req
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
List<String> events = IndexTaskUtils.getMessagesFromSavedParseExceptions(
parseExceptionHandler.getSavedParseExceptions()
);
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/HadoopIndexTask.java
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/HadoopIndexTask.java
index 97e5ec0..b04097c 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/HadoopIndexTask.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/HadoopIndexTask.java
@@ -63,6 +63,7 @@ import
org.apache.druid.segment.indexing.granularity.ArbitraryGranularitySpec;
import org.apache.druid.segment.indexing.granularity.GranularitySpec;
import org.apache.druid.segment.realtime.firehose.ChatHandler;
import org.apache.druid.segment.realtime.firehose.ChatHandlerProvider;
+import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthorizerMapper;
import org.apache.druid.timeline.DataSegment;
import org.apache.hadoop.mapred.JobClient;
@@ -633,7 +634,7 @@ public class HadoopIndexTask extends HadoopTask implements
ChatHandler
@QueryParam("windows") List<Integer> windows
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
Map<String, Object> returnMap = new HashMap<>();
Map<String, Object> totalsMap = new HashMap<>();
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/IndexTask.java
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/IndexTask.java
index c68a2b4..a993b53 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/IndexTask.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/IndexTask.java
@@ -95,6 +95,7 @@ import
org.apache.druid.segment.realtime.appenderator.SegmentsAndCommitMetadata;
import
org.apache.druid.segment.realtime.appenderator.TransactionalSegmentPublisher;
import org.apache.druid.segment.realtime.firehose.ChatHandler;
import org.apache.druid.segment.writeout.SegmentWriteOutMediumFactory;
+import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthorizerMapper;
import org.apache.druid.timeline.DataSegment;
import org.apache.druid.timeline.partition.HashBasedNumberedShardSpec;
@@ -284,7 +285,7 @@ public class IndexTask extends AbstractBatchIndexTask
implements ChatHandler
@QueryParam("full") String full
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
return Response.ok(doGetUnparseableEvents(full)).build();
}
@@ -393,7 +394,7 @@ public class IndexTask extends AbstractBatchIndexTask
implements ChatHandler
@QueryParam("full") String full
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
return Response.ok(doGetRowStats(full)).build();
}
@@ -405,7 +406,7 @@ public class IndexTask extends AbstractBatchIndexTask
implements ChatHandler
@QueryParam("full") String full
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
Map<String, Object> returnMap = new HashMap<>();
Map<String, Object> ingestionStatsAndErrors = new HashMap<>();
Map<String, Object> payload = new HashMap<>();
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/IndexTaskUtils.java
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/IndexTaskUtils.java
index 5be50b6..abc6b92 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/IndexTaskUtils.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/IndexTaskUtils.java
@@ -56,25 +56,28 @@ public class IndexTaskUtils
}
/**
- * Authorizes WRITE action on a task's datasource
+ * Authorizes action to be performed on a task's datasource
*
- * @throws ForbiddenException if not authorized
+ * @return authorization result
*/
- public static void authorizeRequestForDatasourceWrite(
+ public static Access datasourceAuthorizationCheck(
final HttpServletRequest req,
+ Action action,
String datasource,
AuthorizerMapper authorizerMapper
- ) throws ForbiddenException
+ )
{
ResourceAction resourceAction = new ResourceAction(
new Resource(datasource, ResourceType.DATASOURCE),
- Action.WRITE
+ action
);
Access access = AuthorizationUtils.authorizeResourceAction(req,
resourceAction, authorizerMapper);
if (!access.isAllowed()) {
throw new ForbiddenException(access.toString());
}
+
+ return access;
}
public static void setTaskDimensions(final ServiceMetricEvent.Builder
metricBuilder, final Task task)
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/ParallelIndexSupervisorTask.java
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/ParallelIndexSupervisorTask.java
index 3dfc9c7..201a48e 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/ParallelIndexSupervisorTask.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/ParallelIndexSupervisorTask.java
@@ -53,6 +53,7 @@ import
org.apache.druid.indexing.common.task.CurrentSubTaskHolder;
import org.apache.druid.indexing.common.task.IndexTask;
import org.apache.druid.indexing.common.task.IndexTask.IndexIngestionSpec;
import org.apache.druid.indexing.common.task.IndexTask.IndexTuningConfig;
+import org.apache.druid.indexing.common.task.IndexTaskUtils;
import org.apache.druid.indexing.common.task.Task;
import org.apache.druid.indexing.common.task.TaskResource;
import org.apache.druid.indexing.common.task.Tasks;
@@ -74,6 +75,8 @@ import
org.apache.druid.segment.indexing.granularity.GranularitySpec;
import org.apache.druid.segment.realtime.appenderator.SegmentIdWithShardSpec;
import
org.apache.druid.segment.realtime.appenderator.TransactionalSegmentPublisher;
import org.apache.druid.segment.realtime.firehose.ChatHandler;
+import org.apache.druid.segment.realtime.firehose.ChatHandlers;
+import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthorizerMapper;
import org.apache.druid.timeline.DataSegment;
import org.apache.druid.timeline.partition.BuildingShardSpec;
@@ -1173,7 +1176,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Context final HttpServletRequest req
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ ChatHandlers.authorizationCheck(req, Action.READ, getDataSource(),
authorizerMapper);
if (toolbox == null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
@@ -1252,7 +1255,12 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Context final HttpServletRequest req
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ ChatHandlers.authorizationCheck(
+ req,
+ Action.WRITE,
+ getDataSource(),
+ authorizerMapper
+ );
if (currentSubTaskHolder == null || currentSubTaskHolder.getTask() ==
null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
} else {
@@ -1270,7 +1278,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getMode(@Context final HttpServletRequest req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
return Response.ok(isParallelMode() ? "parallel" : "sequential").build();
}
@@ -1279,7 +1287,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getPhaseName(@Context final HttpServletRequest req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
if (isParallelMode()) {
final ParallelIndexTaskRunner runner = getCurrentRunner();
if (runner == null) {
@@ -1297,7 +1305,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getProgress(@Context final HttpServletRequest req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
final ParallelIndexTaskRunner currentRunner = getCurrentRunner();
if (currentRunner == null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
@@ -1311,7 +1319,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getRunningTasks(@Context final HttpServletRequest req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
final ParallelIndexTaskRunner currentRunner = getCurrentRunner();
if (currentRunner == null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
@@ -1325,7 +1333,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getSubTaskSpecs(@Context final HttpServletRequest req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
final ParallelIndexTaskRunner currentRunner = getCurrentRunner();
if (currentRunner == null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
@@ -1339,7 +1347,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getRunningSubTaskSpecs(@Context final HttpServletRequest req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
final ParallelIndexTaskRunner currentRunner = getCurrentRunner();
if (currentRunner == null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
@@ -1353,7 +1361,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getCompleteSubTaskSpecs(@Context final HttpServletRequest
req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
final ParallelIndexTaskRunner currentRunner = getCurrentRunner();
if (currentRunner == null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
@@ -1367,7 +1375,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getSubTaskSpec(@PathParam("id") String id, @Context final
HttpServletRequest req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
final ParallelIndexTaskRunner currentRunner = getCurrentRunner();
if (currentRunner == null) {
@@ -1387,7 +1395,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Produces(MediaType.APPLICATION_JSON)
public Response getSubTaskState(@PathParam("id") String id, @Context final
HttpServletRequest req)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
final ParallelIndexTaskRunner currentRunner = getCurrentRunner();
if (currentRunner == null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
@@ -1409,7 +1417,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@Context final HttpServletRequest req
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
final ParallelIndexTaskRunner currentRunner = getCurrentRunner();
if (currentRunner == null) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("task
is not running yet").build();
@@ -1561,7 +1569,7 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@QueryParam("full") String full
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
return Response.ok(doGetRowStatsAndUnparseableEvents(full,
false).lhs).build();
}
@@ -1606,8 +1614,8 @@ public class ParallelIndexSupervisorTask extends
AbstractBatchIndexTask implemen
@QueryParam("full") String full
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
+
return Response.ok(doGetLiveReports(full)).build();
}
-
}
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/SinglePhaseSubTask.java
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/SinglePhaseSubTask.java
index f979bc8..267df48 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/SinglePhaseSubTask.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/SinglePhaseSubTask.java
@@ -67,6 +67,7 @@ import
org.apache.druid.segment.realtime.appenderator.BaseAppenderatorDriver;
import org.apache.druid.segment.realtime.appenderator.BatchAppenderatorDriver;
import
org.apache.druid.segment.realtime.appenderator.SegmentsAndCommitMetadata;
import org.apache.druid.segment.realtime.firehose.ChatHandler;
+import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthorizerMapper;
import org.apache.druid.timeline.DataSegment;
import org.apache.druid.timeline.TimelineObjectHolder;
@@ -487,7 +488,7 @@ public class SinglePhaseSubTask extends
AbstractBatchSubtask implements ChatHand
@QueryParam("full") String full
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
Map<String, List<String>> events = new HashMap<>();
boolean needsBuildSegments = false;
@@ -562,7 +563,7 @@ public class SinglePhaseSubTask extends
AbstractBatchSubtask implements ChatHand
@QueryParam("full") String full
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
return Response.ok(doGetRowStats(full)).build();
}
@@ -594,7 +595,7 @@ public class SinglePhaseSubTask extends
AbstractBatchSubtask implements ChatHand
@QueryParam("full") String full
)
{
- authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ IndexTaskUtils.datasourceAuthorizationCheck(req, Action.READ,
getDataSource(), authorizerMapper);
return Response.ok(doGetLiveReports(full)).build();
}
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/OverlordResource.java
b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/OverlordResource.java
index 1f596dd..0076eb0 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/OverlordResource.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/OverlordResource.java
@@ -575,11 +575,11 @@ public class OverlordResource
}
}
// early authorization check if datasource != null
- // fail fast if user not authorized to write to datasource
+ // fail fast if user not authorized to access datasource
if (dataSource != null) {
final ResourceAction resourceAction = new ResourceAction(
new Resource(dataSource, ResourceType.DATASOURCE),
- Action.WRITE
+ Action.READ
);
final Access authResult = AuthorizationUtils.authorizeResourceAction(
req,
@@ -987,7 +987,7 @@ public class OverlordResource
);
}
return Collections.singletonList(
- new ResourceAction(new Resource(taskDatasource,
ResourceType.DATASOURCE), Action.WRITE)
+ new ResourceAction(new Resource(taskDatasource,
ResourceType.DATASOURCE), Action.READ)
);
};
List<TaskStatusPlus> optionalTypeFilteredList = collectionToFilter;
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/security/SupervisorResourceFilter.java
b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/security/SupervisorResourceFilter.java
index 08d286e..e834c2e 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/security/SupervisorResourceFilter.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/security/SupervisorResourceFilter.java
@@ -19,6 +19,7 @@
package org.apache.druid.indexing.overlord.http.security;
+import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
@@ -30,9 +31,11 @@ import
org.apache.druid.indexing.overlord.supervisor.SupervisorSpec;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.server.http.security.AbstractResourceFilter;
import org.apache.druid.server.security.Access;
+import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthorizationUtils;
import org.apache.druid.server.security.AuthorizerMapper;
import org.apache.druid.server.security.ForbiddenException;
+import org.apache.druid.server.security.ResourceAction;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.PathSegment;
@@ -88,11 +91,13 @@ public class SupervisorResourceFilter extends
AbstractResourceFilter
"No dataSources found to perform authorization checks"
);
- // Supervisor APIs should always require DATASOURCE WRITE access
- // as they deal with ingestion related information
+ Function<String, ResourceAction> resourceActionFunction =
getAction(request) == Action.READ ?
+
AuthorizationUtils.DATASOURCE_READ_RA_GENERATOR :
+
AuthorizationUtils.DATASOURCE_WRITE_RA_GENERATOR;
+
Access authResult = AuthorizationUtils.authorizeAllResourceActions(
getReq(),
- Iterables.transform(spec.getDataSources(),
AuthorizationUtils.DATASOURCE_WRITE_RA_GENERATOR),
+ Iterables.transform(spec.getDataSources(), resourceActionFunction),
getAuthorizerMapper()
);
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/security/TaskResourceFilter.java
b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/security/TaskResourceFilter.java
index 028977c..da1e5c5 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/security/TaskResourceFilter.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/security/TaskResourceFilter.java
@@ -30,7 +30,6 @@ import
org.apache.druid.indexing.overlord.TaskStorageQueryAdapter;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.server.http.security.AbstractResourceFilter;
import org.apache.druid.server.security.Access;
-import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthorizationUtils;
import org.apache.druid.server.security.AuthorizerMapper;
import org.apache.druid.server.security.ForbiddenException;
@@ -86,11 +85,9 @@ public class TaskResourceFilter extends
AbstractResourceFilter
}
final String dataSourceName =
Preconditions.checkNotNull(taskOptional.get().getDataSource());
- // Task APIs should always require DATASOURCE WRITE access
- // as they deal with ingestion related information
final ResourceAction resourceAction = new ResourceAction(
new Resource(dataSourceName, ResourceType.DATASOURCE),
- Action.WRITE
+ getAction(request)
);
final Access authResult = AuthorizationUtils.authorizeResourceAction(
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java
b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java
index 26baed3..d5289f4 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java
@@ -65,7 +65,7 @@ import java.util.stream.Collectors;
@Path("/druid/indexer/v1/supervisor")
public class SupervisorResource
{
- private static final Function<VersionedSupervisorSpec,
Iterable<ResourceAction>> SPEC_DATASOURCE_WRITE_RA_GENERATOR =
+ private static final Function<VersionedSupervisorSpec,
Iterable<ResourceAction>> SPEC_DATASOURCE_READ_RA_GENERATOR =
supervisorSpec -> {
if (supervisorSpec.getSpec() == null) {
return null;
@@ -75,7 +75,7 @@ public class SupervisorResource
}
return Iterables.transform(
supervisorSpec.getSpec().getDataSources(),
- AuthorizationUtils.DATASOURCE_WRITE_RA_GENERATOR
+ AuthorizationUtils.DATASOURCE_READ_RA_GENERATOR
);
};
@@ -376,7 +376,7 @@ public class SupervisorResource
AuthorizationUtils.filterAuthorizedResources(
req,
manager.getSupervisorHistory(),
- SPEC_DATASOURCE_WRITE_RA_GENERATOR,
+ SPEC_DATASOURCE_READ_RA_GENERATOR,
authorizerMapper
)
).build()
@@ -400,7 +400,7 @@ public class SupervisorResource
AuthorizationUtils.filterAuthorizedResources(
req,
historyForId,
- SPEC_DATASOURCE_WRITE_RA_GENERATOR,
+ SPEC_DATASOURCE_READ_RA_GENERATOR,
authorizerMapper
)
);
diff --git
a/indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunner.java
b/indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunner.java
index 50bf440..fba9352 100644
---
a/indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunner.java
+++
b/indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunner.java
@@ -81,6 +81,8 @@ import
org.apache.druid.segment.realtime.appenderator.AppenderatorDriverAddResul
import
org.apache.druid.segment.realtime.appenderator.SegmentsAndCommitMetadata;
import org.apache.druid.segment.realtime.appenderator.StreamAppenderatorDriver;
import org.apache.druid.segment.realtime.firehose.ChatHandler;
+import org.apache.druid.server.security.Access;
+import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthorizerMapper;
import org.apache.druid.timeline.DataSegment;
import org.apache.druid.utils.CollectionUtils;
@@ -1359,10 +1361,12 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
/**
* Authorizes action to be performed on this task's datasource
+ *
+ * @return authorization result
*/
- private void authorizeRequest(final HttpServletRequest req)
+ private Access authorizationCheck(final HttpServletRequest req, Action
action)
{
- task.authorizeRequestForDatasourceWrite(req, authorizerMapper);
+ return IndexTaskUtils.datasourceAuthorizationCheck(req, action,
task.getDataSource(), authorizerMapper);
}
public Appenderator getAppenderator()
@@ -1439,7 +1443,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Path("/stop")
public Response stop(@Context final HttpServletRequest req)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.WRITE);
stopGracefully();
return Response.status(Response.Status.OK).build();
}
@@ -1449,7 +1453,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Produces(MediaType.APPLICATION_JSON)
public Status getStatusHTTP(@Context final HttpServletRequest req)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.READ);
return status;
}
@@ -1464,7 +1468,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Produces(MediaType.APPLICATION_JSON)
public Map<PartitionIdType, SequenceOffsetType> getCurrentOffsets(@Context
final HttpServletRequest req)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.READ);
return getCurrentOffsets();
}
@@ -1478,7 +1482,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Produces(MediaType.APPLICATION_JSON)
public Map<PartitionIdType, SequenceOffsetType> getEndOffsetsHTTP(@Context
final HttpServletRequest req)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.READ);
return getEndOffsets();
}
@@ -1498,7 +1502,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Context final HttpServletRequest req
) throws InterruptedException
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.WRITE);
return setEndOffsets(sequences, finish);
}
@@ -1548,7 +1552,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Context final HttpServletRequest req
)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.READ);
return Response.ok(doGetRowStats()).build();
}
@@ -1559,7 +1563,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Context final HttpServletRequest req
)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.READ);
return Response.ok(doGetLiveReports()).build();
}
@@ -1571,7 +1575,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Context final HttpServletRequest req
)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.READ);
List<String> events = IndexTaskUtils.getMessagesFromSavedParseExceptions(
parseExceptionHandler.getSavedParseExceptions()
);
@@ -1722,7 +1726,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Context final HttpServletRequest req
)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.READ);
return getCheckpoints();
}
@@ -1749,7 +1753,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Context final HttpServletRequest req
) throws InterruptedException
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.WRITE);
return pause();
}
@@ -1804,7 +1808,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Path("/resume")
public Response resumeHTTP(@Context final HttpServletRequest req) throws
InterruptedException
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.WRITE);
resume();
return Response.status(Response.Status.OK).build();
}
@@ -1837,7 +1841,7 @@ public abstract class
SeekableStreamIndexTaskRunner<PartitionIdType, SequenceOff
@Produces(MediaType.APPLICATION_JSON)
public DateTime getStartTime(@Context final HttpServletRequest req)
{
- authorizeRequest(req);
+ authorizationCheck(req, Action.WRITE);
return startTime;
}
diff --git
a/indexing-service/src/test/java/org/apache/druid/indexing/common/task/IndexTaskTest.java
b/indexing-service/src/test/java/org/apache/druid/indexing/common/task/IndexTaskTest.java
index 5ff9d4f..f805b2c 100644
---
a/indexing-service/src/test/java/org/apache/druid/indexing/common/task/IndexTaskTest.java
+++
b/indexing-service/src/test/java/org/apache/druid/indexing/common/task/IndexTaskTest.java
@@ -90,14 +90,6 @@ import
org.apache.druid.segment.realtime.firehose.WindowedStorageAdapter;
import
org.apache.druid.segment.realtime.plumber.NoopSegmentHandoffNotifierFactory;
import org.apache.druid.segment.transform.ExpressionTransform;
import org.apache.druid.segment.transform.TransformSpec;
-import org.apache.druid.server.security.Access;
-import org.apache.druid.server.security.Action;
-import org.apache.druid.server.security.AuthConfig;
-import org.apache.druid.server.security.AuthenticationResult;
-import org.apache.druid.server.security.Authorizer;
-import org.apache.druid.server.security.AuthorizerMapper;
-import org.apache.druid.server.security.ForbiddenException;
-import org.apache.druid.server.security.ResourceType;
import org.apache.druid.timeline.DataSegment;
import org.apache.druid.timeline.SegmentId;
import org.apache.druid.timeline.partition.HashBasedNumberedShardSpec;
@@ -119,7 +111,6 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import javax.annotation.Nullable;
-import javax.servlet.http.HttpServletRequest;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
@@ -2614,81 +2605,6 @@ public class IndexTaskTest extends IngestionTestBase
}
@Test
- public void testAuthorizeRequestForDatasourceWrite() throws Exception
- {
- // Need to run this only once
- if (lockGranularity == LockGranularity.SEGMENT) {
- return;
- }
-
- // Create auth mapper which allows datasourceReadUser to read datasource
- // and datasourceWriteUser to write to datasource
- final String datasourceWriteUser = "datasourceWriteUser";
- final String datasourceReadUser = "datasourceReadUser";
- AuthorizerMapper authorizerMapper = new AuthorizerMapper(null) {
- @Override
- public Authorizer getAuthorizer(String name)
- {
- return (authenticationResult, resource, action) -> {
- final String username = authenticationResult.getIdentity();
- if (!resource.getType().equals(ResourceType.DATASOURCE) || username
== null) {
- return new Access(false);
- } else if (action == Action.WRITE) {
- return new Access(username.equals(datasourceWriteUser));
- } else {
- return new Access(username.equals(datasourceReadUser));
- }
- };
- }
- };
-
- // Create test target
- final IndexTask indexTask = new IndexTask(
- null,
- null,
- createDefaultIngestionSpec(
- jsonMapper,
- temporaryFolder.newFolder(),
- null,
- null,
- createTuningConfigWithMaxRowsPerSegment(2, true),
- false,
- false
- ),
- null
- );
-
- // Verify that datasourceWriteUser is successfully authorized
- HttpServletRequest writeUserRequest =
EasyMock.mock(HttpServletRequest.class);
- expectAuthorizationTokenCheck(datasourceWriteUser, writeUserRequest);
- EasyMock.replay(writeUserRequest);
- indexTask.authorizeRequestForDatasourceWrite(writeUserRequest,
authorizerMapper);
-
- // Verify that datasourceReadUser is not successfully authorized
- HttpServletRequest readUserRequest =
EasyMock.mock(HttpServletRequest.class);
- expectAuthorizationTokenCheck(datasourceReadUser, readUserRequest);
- EasyMock.replay(readUserRequest);
- expectedException.expect(ForbiddenException.class);
- indexTask.authorizeRequestForDatasourceWrite(readUserRequest,
authorizerMapper);
- }
-
- private void expectAuthorizationTokenCheck(String username,
HttpServletRequest request)
- {
- AuthenticationResult authenticationResult = new
AuthenticationResult(username, "druid", null, null);
-
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_ALLOW_UNSECURED_PATH)).andReturn(null).anyTimes();
-
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).atLeastOnce();
-
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT))
- .andReturn(authenticationResult)
- .atLeastOnce();
-
- request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, false);
- EasyMock.expectLastCall().anyTimes();
-
- request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
- EasyMock.expectLastCall().anyTimes();
- }
-
- @Test
public void testEqualsAndHashCode()
{
EqualsVerifier.forClass(IndexTuningConfig.class)
diff --git
a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/OverlordResourceTest.java
b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/OverlordResourceTest.java
index ae494ee..b919706 100644
---
a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/OverlordResourceTest.java
+++
b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/OverlordResourceTest.java
@@ -122,16 +122,14 @@ public class OverlordResourceTest
case "allow":
return new Access(true);
case Datasources.WIKIPEDIA:
- // All users can read wikipedia but only writer can write
+ // Only "Wiki Reader" can read "wikipedia"
return new Access(
- action == Action.READ
- || (action == Action.WRITE &&
Users.WIKI_WRITER.equals(username))
+ action == Action.READ && Users.WIKI_READER.equals(username)
);
case Datasources.BUZZFEED:
- // All users can read buzzfeed but only writer can write
+ // Only "Buzz Reader" can read "buzzfeed"
return new Access(
- action == Action.READ
- || (action == Action.WRITE &&
Users.BUZZ_WRITER.equals(username))
+ action == Action.READ && Users.BUZZ_READER.equals(username)
);
default:
return new Access(false);
@@ -857,11 +855,11 @@ public class OverlordResourceTest
}
@Test
- public void testGetTasksRequiresDatasourceWrite()
+ public void testGetTasksRequiresDatasourceRead()
{
- // Setup mocks for a user who has write access to "wikipedia"
- // and read access to "buzzfeed"
- expectAuthorizationTokenCheck(Users.WIKI_WRITER);
+ // Setup mocks for a user who has read access to "wikipedia"
+ // and no access to "buzzfeed"
+ expectAuthorizationTokenCheck(Users.WIKI_READER);
// Setup mocks to return completed, active, known, pending and running
tasks
EasyMock.expect(taskStorageQueryAdapter.getCompletedTaskInfoByCreatedTimeDuration(null,
null, null)).andStubReturn(
@@ -907,7 +905,7 @@ public class OverlordResourceTest
workerTaskRunnerQueryAdapter
);
- // Verify that only the tasks of write access datasource are returned
+ // Verify that only the tasks of read access datasource are returned
List<TaskStatusPlus> responseObjects = (List<TaskStatusPlus>)
overlordResource
.getTasks(null, null, null, null, null, req)
.getEntity();
@@ -918,11 +916,11 @@ public class OverlordResourceTest
}
@Test
- public void testGetTasksFilterByDatasourceRequiresWrite()
+ public void testGetTasksFilterByDatasourceRequiresReadAccess()
{
- // Setup mocks for a user who has write access to "wikipedia"
- // and read access to "buzzfeed"
- expectAuthorizationTokenCheck(Users.WIKI_WRITER);
+ // Setup mocks for a user who has read access to "wikipedia"
+ // and no access to "buzzfeed"
+ expectAuthorizationTokenCheck(Users.WIKI_READER);
// Setup mocks to return completed, active, known, pending and running
tasks
EasyMock.expect(taskStorageQueryAdapter.getCompletedTaskInfoByCreatedTimeDuration(null,
null, null)).andStubReturn(
@@ -949,7 +947,7 @@ public class OverlordResourceTest
workerTaskRunnerQueryAdapter
);
- // Verify that only the tasks of write access datasource are returned
+ // Verify that only the tasks of read access datasource are returned
expectedException.expect(WebApplicationException.class);
overlordResource.getTasks(null, Datasources.BUZZFEED, null, null, null,
req);
}
@@ -1042,7 +1040,7 @@ public class OverlordResourceTest
@Test
public void testTaskPostDeniesDatasourceReadUser()
{
- expectAuthorizationTokenCheck(Users.WIKI_WRITER);
+ expectAuthorizationTokenCheck(Users.WIKI_READER);
EasyMock.replay(
taskRunner,
@@ -1054,7 +1052,7 @@ public class OverlordResourceTest
);
// Verify that taskPost fails for user who has only datasource read access
- Task task = NoopTask.create(Datasources.BUZZFEED);
+ Task task = NoopTask.create(Datasources.WIKIPEDIA);
expectedException.expect(ForbiddenException.class);
expectedException.expect(ForbiddenException.class);
overlordResource.taskPost(task, req);
@@ -1516,8 +1514,8 @@ public class OverlordResourceTest
private static class Users
{
private static final String DRUID = "druid";
- private static final String WIKI_WRITER = "Wiki Writer";
- private static final String BUZZ_WRITER = "Buzz Writer";
+ private static final String WIKI_READER = "Wiki Reader";
+ private static final String BUZZ_READER = "Buzz Reader";
}
/**
diff --git
a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/security/SupervisorResourceFilterTest.java
b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/security/SupervisorResourceFilterTest.java
index 118b8b5..21485a8 100644
---
a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/security/SupervisorResourceFilterTest.java
+++
b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/http/security/SupervisorResourceFilterTest.java
@@ -72,18 +72,18 @@ public class SupervisorResourceFilterTest
}
@Test
- public void testGetWhenUserHasWriteAccess()
+ public void testGetWhenUserHasReadAccess()
{
- setExpectations("/druid/indexer/v1/supervisor/datasource1", "GET",
"datasource1", Action.WRITE, true);
+ setExpectations("/druid/indexer/v1/supervisor/datasource1", "GET",
"datasource1", Action.READ, true);
ContainerRequest filteredRequest = resourceFilter.filter(containerRequest);
Assert.assertNotNull(filteredRequest);
verifyMocks();
}
@Test
- public void testGetWhenUserHasNoWriteAccess()
+ public void testGetWhenUserHasNoReadAccess()
{
- setExpectations("/druid/indexer/v1/supervisor/datasource1", "GET",
"datasource1", Action.WRITE, false);
+ setExpectations("/druid/indexer/v1/supervisor/datasource1", "GET",
"datasource1", Action.READ, false);
ForbiddenException expected = null;
try {
diff --git
a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResourceTest.java
b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResourceTest.java
index f3d794a..e15c43c 100644
---
a/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResourceTest.java
+++
b/indexing-service/src/test/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResourceTest.java
@@ -30,12 +30,10 @@ import
org.apache.druid.indexing.overlord.supervisor.autoscaler.SupervisorTaskAu
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.segment.TestHelper;
import org.apache.druid.server.security.Access;
-import org.apache.druid.server.security.Action;
import org.apache.druid.server.security.AuthConfig;
import org.apache.druid.server.security.AuthenticationResult;
import org.apache.druid.server.security.Authorizer;
import org.apache.druid.server.security.AuthorizerMapper;
-import org.apache.druid.server.security.ResourceType;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;
@@ -94,14 +92,7 @@ public class SupervisorResourceTest extends EasyMockSupport
@Override
public Authorizer getAuthorizer(String name)
{
- // Create an Authorizer that only allows Datasource WRITE requests
- // because all SupervisorResource APIs must only check Datasource
WRITE access
return (authenticationResult, resource, action) -> {
- if (!resource.getType().equals(ResourceType.DATASOURCE)
- || action != Action.WRITE) {
- return new Access(false);
- }
-
if (authenticationResult.getIdentity().equals("druid")) {
return Access.OK;
} else {
diff --git
a/indexing-service/src/test/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunnerAuthTest.java
b/indexing-service/src/test/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunnerAuthTest.java
index 3eba53f..db51a41 100644
---
a/indexing-service/src/test/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunnerAuthTest.java
+++
b/indexing-service/src/test/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunnerAuthTest.java
@@ -92,11 +92,11 @@ public class SeekableStreamIndexTaskRunnerAuthTest
final String username = authenticationResult.getIdentity();
// Allow access to a Datasource if
- // - any user requests Read access
+ // - Datasource Read User requests Read access
// - or, Datasource Write User requests Write access
if (resource.getType().equals(ResourceType.DATASOURCE)) {
return new Access(
- action == Action.READ
+ (action == Action.READ &&
username.equals(Users.DATASOURCE_READ))
|| (action == Action.WRITE &&
username.equals(Users.DATASOURCE_WRITE))
);
}
@@ -118,13 +118,6 @@ public class SeekableStreamIndexTaskRunnerAuthTest
null
);
SeekableStreamIndexTaskTuningConfig tuningConfig =
mock(SeekableStreamIndexTaskTuningConfig.class);
-
/*expect(tuningConfig.getIntermediateHandoffPeriod()).andReturn(Period.minutes(10));
- expect(tuningConfig.isLogParseExceptions()).andReturn(false);
- expect(tuningConfig.getMaxParseExceptions()).andReturn(1000);
- expect(tuningConfig.getMaxSavedParseExceptions()).andReturn(100);
-
- replay(tuningConfig);*/
-
SeekableStreamIndexTaskIOConfig<String, String> ioConfig = new
TestSeekableStreamIndexTaskIOConfig();
// Initiliaze task and task runner
@@ -136,7 +129,7 @@ public class SeekableStreamIndexTaskRunnerAuthTest
@Test
public void testGetStatusHttp()
{
- verifyOnlyDatasourceWriteUserCanAccess(taskRunner::getStatusHTTP);
+ verifyOnlyDatasourceReadUserCanAccess(taskRunner::getStatusHTTP);
}
@Test
@@ -180,7 +173,7 @@ public class SeekableStreamIndexTaskRunnerAuthTest
@Test
public void testGetEndOffsets()
{
- verifyOnlyDatasourceWriteUserCanAccess(taskRunner::getCurrentOffsets);
+ verifyOnlyDatasourceReadUserCanAccess(taskRunner::getCurrentOffsets);
}
@Test
@@ -199,7 +192,7 @@ public class SeekableStreamIndexTaskRunnerAuthTest
@Test
public void testGetCheckpointsHttp()
{
- verifyOnlyDatasourceWriteUserCanAccess(taskRunner::getCheckpointsHTTP);
+ verifyOnlyDatasourceReadUserCanAccess(taskRunner::getCheckpointsHTTP);
}
@@ -219,6 +212,22 @@ public class SeekableStreamIndexTaskRunnerAuthTest
method.accept(blockedRequest);
}
+ private void verifyOnlyDatasourceReadUserCanAccess(
+ Consumer<HttpServletRequest> method
+ )
+ {
+ // Verify that datasource read user can access
+ HttpServletRequest allowedRequest = createRequest(Users.DATASOURCE_READ);
+ replay(allowedRequest);
+ method.accept(allowedRequest);
+
+ // Verify that no other user can access
+ HttpServletRequest blockedRequest = createRequest(Users.DATASOURCE_WRITE);
+ replay(blockedRequest);
+ expectedException.expect(ForbiddenException.class);
+ method.accept(blockedRequest);
+ }
+
private HttpServletRequest createRequest(String username)
{
HttpServletRequest request = mock(HttpServletRequest.class);
diff --git a/integration-tests/docker/ldap-configs/bootstrap.ldif
b/integration-tests/docker/ldap-configs/bootstrap.ldif
index d88265f..9614a78 100644
--- a/integration-tests/docker/ldap-configs/bootstrap.ldif
+++ b/integration-tests/docker/ldap-configs/bootstrap.ldif
@@ -53,41 +53,41 @@ description: Admin users
uniqueMember: uid=admin,ou=Users,dc=example,dc=org
uniqueMember: uid=druid_system,ou=Users,dc=example,dc=org
-dn: uid=datasourceReadOnlyUser,ou=Users,dc=example,dc=org
-uid: datasourceReadOnlyUser
-cn: datasourceReadOnlyUser
-sn: datasourceReadOnlyUser
+dn: uid=datasourceOnlyUser,ou=Users,dc=example,dc=org
+uid: datasourceOnlyUser
+cn: datasourceOnlyUser
+sn: datasourceOnlyUser
objectClass: top
objectClass: posixAccount
objectClass: inetOrgPerson
-homeDirectory: /home/datasourceReadOnlyUser
+homeDirectory: /home/datasourceOnlyUser
uidNumber: 3
gidNumber: 3
userPassword: helloworld
-dn: cn=datasourceReadOnlyGroup,ou=Groups,dc=example,dc=org
+dn: cn=datasourceOnlyGroup,ou=Groups,dc=example,dc=org
objectClass: groupOfUniqueNames
-cn: datasourceReadOnlyGroup
-description: datasourceReadOnlyGroup users
-uniqueMember: uid=datasourceReadOnlyUser,ou=Users,dc=example,dc=org
-
-dn: uid=datasourceReadWithStateUser,ou=Users,dc=example,dc=org
-uid: datasourceReadWithStateUser
-cn: datasourceReadWithStateUser
-sn: datasourceReadWithStateUser
+cn: datasourceOnlyGroup
+description: datasourceOnlyGroup users
+uniqueMember: uid=datasourceOnlyUser,ou=Users,dc=example,dc=org
+
+dn: uid=datasourceWithStateUser,ou=Users,dc=example,dc=org
+uid: datasourceWithStateUser
+cn: datasourceWithStateUser
+sn: datasourceWithStateUser
objectClass: top
objectClass: posixAccount
objectClass: inetOrgPerson
-homeDirectory: /home/datasourceReadWithStateUser
+homeDirectory: /home/datasourceWithStateUser
uidNumber: 4
gidNumber: 4
userPassword: helloworld
-dn: cn=datasourceReadWithStateGroup,ou=Groups,dc=example,dc=org
+dn: cn=datasourceWithStateGroup,ou=Groups,dc=example,dc=org
objectClass: groupOfUniqueNames
-cn: datasourceReadWithStateGroup
-description: datasourceReadWithStateGroup users
-uniqueMember: uid=datasourceReadWithStateUser,ou=Users,dc=example,dc=org
+cn: datasourceWithStateGroup
+description: datasourceWithStateGroup users
+uniqueMember: uid=datasourceWithStateUser,ou=Users,dc=example,dc=org
dn: uid=stateOnlyUser,ou=Users,dc=example,dc=org
uid: stateOnlyUser
@@ -137,38 +137,20 @@ uidNumber: 7
gidNumber: 7
userPassword: helloworld
-dn: uid=datasourceReadAndSysUser,ou=Users,dc=example,dc=org
-uid: datasourceReadAndSysUser
-cn: datasourceReadAndSysUser
-sn: datasourceReadAndSysUser
-objectClass: top
-objectClass: posixAccount
-objectClass: inetOrgPerson
-homeDirectory: /home/datasourceReadAndSysUser
-uidNumber: 8
-gidNumber: 8
-userPassword: helloworld
-
-dn: cn=datasourceReadWithSysGroup,ou=Groups,dc=example,dc=org
-objectClass: groupOfUniqueNames
-cn: datasourceReadWithSysGroup
-description: datasourceReadWithSysGroup users
-uniqueMember: uid=datasourceReadAndSysUser,ou=Users,dc=example,dc=org
-
-dn: uid=datasourceWriteAndSysUser,ou=Users,dc=example,dc=org
-uid: datasourceWriteAndSysUser
-cn: datasourceWriteAndSysUser
-sn: datasourceWriteAndSysUser
+dn: uid=datasourceAndSysUser,ou=Users,dc=example,dc=org
+uid: datasourceAndSysUser
+cn: datasourceAndSysUser
+sn: datasourceAndSysUser
objectClass: top
objectClass: posixAccount
objectClass: inetOrgPerson
-homeDirectory: /home/datasourceWriteAndSysUser
+homeDirectory: /home/datasourceAndSysUser
uidNumber: 8
gidNumber: 8
userPassword: helloworld
-dn: cn=datasourceWriteWithSysGroup,ou=Groups,dc=example,dc=org
+dn: cn=datasourceWithSysGroup,ou=Groups,dc=example,dc=org
objectClass: groupOfUniqueNames
-cn: datasourceWriteWithSysGroup
-description: datasourceWriteWithSysGroup users
-uniqueMember: uid=datasourceWriteAndSysUser,ou=Users,dc=example,dc=org
+cn: datasourceWithSysGroup
+description: datasourceWithSysGroup users
+uniqueMember: uid=datasourceAndSysUser,ou=Users,dc=example,dc=org
diff --git
a/integration-tests/src/test/java/org/apache/druid/tests/security/AbstractAuthConfigurationTest.java
b/integration-tests/src/test/java/org/apache/druid/tests/security/AbstractAuthConfigurationTest.java
index c29be8d..42556ad 100644
---
a/integration-tests/src/test/java/org/apache/druid/tests/security/AbstractAuthConfigurationTest.java
+++
b/integration-tests/src/test/java/org/apache/druid/tests/security/AbstractAuthConfigurationTest.java
@@ -98,7 +98,7 @@ public abstract class AbstractAuthConfigurationTest
* create a ResourceAction set of permissions that can only read a
'auth_test' datasource, for Authorizer
* implementations which use ResourceAction pattern matching
*/
- protected static final List<ResourceAction> DATASOURCE_READ_ONLY_PERMISSIONS
= Collections.singletonList(
+ protected static final List<ResourceAction> DATASOURCE_ONLY_PERMISSIONS =
Collections.singletonList(
new ResourceAction(
new Resource("auth_test", ResourceType.DATASOURCE),
Action.READ
@@ -109,7 +109,7 @@ public abstract class AbstractAuthConfigurationTest
* create a ResourceAction set of permissions that can only read 'auth_test'
+ partial SYSTEM_TABLE, for Authorizer
* implementations which use ResourceAction pattern matching
*/
- protected static final List<ResourceAction> DATASOURCE_READ_SYS_PERMISSIONS
= ImmutableList.of(
+ protected static final List<ResourceAction> DATASOURCE_SYS_PERMISSIONS =
ImmutableList.of(
new ResourceAction(
new Resource("auth_test", ResourceType.DATASOURCE),
Action.READ
@@ -135,38 +135,10 @@ public abstract class AbstractAuthConfigurationTest
);
/**
- * create a ResourceAction set of permissions that can write datasource
'auth_test'
- */
- protected static final List<ResourceAction> DATASOURCE_WRITE_SYS_PERMISSIONS
= ImmutableList.of(
- new ResourceAction(
- new Resource("auth_test", ResourceType.DATASOURCE),
- Action.WRITE
- ),
- new ResourceAction(
- new Resource("segments", ResourceType.SYSTEM_TABLE),
- Action.READ
- ),
- // test missing state permission but having servers permission
- new ResourceAction(
- new Resource("servers", ResourceType.SYSTEM_TABLE),
- Action.READ
- ),
- // test missing state permission but having server_segments permission
- new ResourceAction(
- new Resource("server_segments", ResourceType.SYSTEM_TABLE),
- Action.READ
- ),
- new ResourceAction(
- new Resource("tasks", ResourceType.SYSTEM_TABLE),
- Action.READ
- )
- );
-
- /**
* create a ResourceAction set of permissions that can only read 'auth_test'
+ STATE + SYSTEM_TABLE read access, for
* Authorizer implementations which use ResourceAction pattern matching
*/
- protected static final List<ResourceAction>
DATASOURCE_READ_SYS_STATE_PERMISSIONS = ImmutableList.of(
+ protected static final List<ResourceAction> DATASOURCE_SYS_STATE_PERMISSIONS
= ImmutableList.of(
new ResourceAction(
new Resource("auth_test", ResourceType.DATASOURCE),
Action.READ
@@ -215,18 +187,16 @@ public abstract class AbstractAuthConfigurationTest
protected CoordinatorResourceTestClient coordinatorClient;
protected HttpClient adminClient;
- protected HttpClient datasourceReadOnlyUserClient;
- protected HttpClient datasourceReadAndSysUserClient;
- protected HttpClient datasourceWriteAndSysUserClient;
- protected HttpClient datasourceReadWithStateUserClient;
+ protected HttpClient datasourceOnlyUserClient;
+ protected HttpClient datasourceAndSysUserClient;
+ protected HttpClient datasourceWithStateUserClient;
protected HttpClient stateOnlyUserClient;
protected HttpClient internalSystemClient;
- protected abstract void setupDatasourceReadOnlyUser() throws Exception;
- protected abstract void setupDatasourceReadAndSysTableUser() throws
Exception;
- protected abstract void setupDatasourceWriteAndSysTableUser() throws
Exception;
- protected abstract void setupDatasourceReadAndSysAndStateUser() throws
Exception;
+ protected abstract void setupDatasourceOnlyUser() throws Exception;
+ protected abstract void setupDatasourceAndSysTableUser() throws Exception;
+ protected abstract void setupDatasourceAndSysAndStateUser() throws Exception;
protected abstract void setupSysTableAndStateOnlyUser() throws Exception;
protected abstract void setupTestSpecificHttpClients() throws Exception;
protected abstract String getAuthenticatorName();
@@ -272,44 +242,44 @@ public abstract class AbstractAuthConfigurationTest
}
@Test
- public void test_systemSchemaAccess_datasourceReadOnlyUser() throws Exception
+ public void test_systemSchemaAccess_datasourceOnlyUser() throws Exception
{
// check that we can access a datasource-permission restricted resource on
the broker
HttpUtil.makeRequest(
- datasourceReadOnlyUserClient,
+ datasourceOnlyUserClient,
HttpMethod.GET,
config.getBrokerUrl() + "/druid/v2/datasources/auth_test",
null
);
// as user that can only read auth_test
- LOG.info("Checking sys.segments query as datasourceReadOnlyUser...");
+ LOG.info("Checking sys.segments query as datasourceOnlyUser...");
verifySystemSchemaQueryFailure(
- datasourceReadOnlyUserClient,
+ datasourceOnlyUserClient,
SYS_SCHEMA_SEGMENTS_QUERY,
HttpResponseStatus.FORBIDDEN,
"{\"Access-Check-Result\":\"Allowed:false, Message:\"}"
);
- LOG.info("Checking sys.servers query as datasourceReadOnlyUser...");
+ LOG.info("Checking sys.servers query as datasourceOnlyUser...");
verifySystemSchemaQueryFailure(
- datasourceReadOnlyUserClient,
+ datasourceOnlyUserClient,
SYS_SCHEMA_SERVERS_QUERY,
HttpResponseStatus.FORBIDDEN,
"{\"Access-Check-Result\":\"Allowed:false, Message:\"}"
);
- LOG.info("Checking sys.server_segments query as
datasourceReadOnlyUser...");
+ LOG.info("Checking sys.server_segments query as datasourceOnlyUser...");
verifySystemSchemaQueryFailure(
- datasourceReadOnlyUserClient,
+ datasourceOnlyUserClient,
SYS_SCHEMA_SERVER_SEGMENTS_QUERY,
HttpResponseStatus.FORBIDDEN,
"{\"Access-Check-Result\":\"Allowed:false, Message:\"}"
);
- LOG.info("Checking sys.tasks query as datasourceReadOnlyUser...");
+ LOG.info("Checking sys.tasks query as datasourceOnlyUser...");
verifySystemSchemaQueryFailure(
- datasourceReadOnlyUserClient,
+ datasourceOnlyUserClient,
SYS_SCHEMA_TASKS_QUERY,
HttpResponseStatus.FORBIDDEN,
"{\"Access-Check-Result\":\"Allowed:false, Message:\"}"
@@ -317,119 +287,83 @@ public abstract class AbstractAuthConfigurationTest
}
@Test
- public void test_systemSchemaAccess_datasourceReadAndSysUser() throws
Exception
+ public void test_systemSchemaAccess_datasourceAndSysUser() throws Exception
{
// check that we can access a datasource-permission restricted resource on
the broker
HttpUtil.makeRequest(
- datasourceReadAndSysUserClient,
+ datasourceAndSysUserClient,
HttpMethod.GET,
config.getBrokerUrl() + "/druid/v2/datasources/auth_test",
null
);
// as user that can only read auth_test
- LOG.info("Checking sys.segments query as datasourceReadAndSysUser...");
+ LOG.info("Checking sys.segments query as datasourceAndSysUser...");
verifySystemSchemaQuery(
- datasourceReadAndSysUserClient,
+ datasourceAndSysUserClient,
SYS_SCHEMA_SEGMENTS_QUERY,
adminSegments.stream()
.filter((segmentEntry) ->
"auth_test".equals(segmentEntry.get("datasource")))
.collect(Collectors.toList())
);
- LOG.info("Checking sys.servers query as datasourceReadAndSysUser...");
- verifySystemSchemaQueryFailure(
- datasourceReadAndSysUserClient,
- SYS_SCHEMA_SERVERS_QUERY,
- HttpResponseStatus.FORBIDDEN,
- "{\"Access-Check-Result\":\"Insufficient permission to view servers :
Allowed:false, Message:\"}"
- );
-
- LOG.info("Checking sys.server_segments query as
datasourceReadAndSysUser...");
- verifySystemSchemaQueryFailure(
- datasourceReadAndSysUserClient,
- SYS_SCHEMA_SERVER_SEGMENTS_QUERY,
- HttpResponseStatus.FORBIDDEN,
- "{\"Access-Check-Result\":\"Insufficient permission to view servers :
Allowed:false, Message:\"}"
- );
-
- // Verify that sys.tasks result is empty as it is filtered by Datasource
WRITE access
- LOG.info("Checking sys.tasks query as datasourceReadAndSysUser...");
- verifySystemSchemaQuery(
- datasourceReadAndSysUserClient,
- SYS_SCHEMA_TASKS_QUERY,
- Collections.emptyList()
- );
- }
-
- @Test
- public void test_systemSchemaAccess_datasourceWriteAndSysUser() throws
Exception
- {
- // Verify that sys.segments result is empty as it is filtered by
Datasource READ access
- LOG.info("Checking sys.segments query as datasourceWriteAndSysUser...");
- verifySystemSchemaQuery(
- datasourceWriteAndSysUserClient,
- SYS_SCHEMA_SEGMENTS_QUERY,
- Collections.emptyList()
- );
-
- LOG.info("Checking sys.servers query as datasourceWriteAndSysUser...");
+ LOG.info("Checking sys.servers query as datasourceAndSysUser...");
verifySystemSchemaQueryFailure(
- datasourceWriteAndSysUserClient,
+ datasourceAndSysUserClient,
SYS_SCHEMA_SERVERS_QUERY,
HttpResponseStatus.FORBIDDEN,
"{\"Access-Check-Result\":\"Insufficient permission to view servers :
Allowed:false, Message:\"}"
);
- LOG.info("Checking sys.server_segments query as
datasourceWriteAndSysUser...");
+ LOG.info("Checking sys.server_segments query as datasourceAndSysUser...");
verifySystemSchemaQueryFailure(
- datasourceWriteAndSysUserClient,
+ datasourceAndSysUserClient,
SYS_SCHEMA_SERVER_SEGMENTS_QUERY,
HttpResponseStatus.FORBIDDEN,
"{\"Access-Check-Result\":\"Insufficient permission to view servers :
Allowed:false, Message:\"}"
);
- LOG.info("Checking sys.tasks query as datasourceWriteAndSysUser...");
+ LOG.info("Checking sys.tasks query as datasourceAndSysUser...");
verifySystemSchemaQuery(
- datasourceWriteAndSysUserClient,
+ datasourceAndSysUserClient,
SYS_SCHEMA_TASKS_QUERY,
adminTasks.stream()
- .filter((segmentEntry) ->
"auth_test".equals(segmentEntry.get("datasource")))
+ .filter((taskEntry) ->
"auth_test".equals(taskEntry.get("datasource")))
.collect(Collectors.toList())
);
}
@Test
- public void test_systemSchemaAccess_datasourceReadAndSysWithStateUser()
throws Exception
+ public void test_systemSchemaAccess_datasourceAndSysWithStateUser() throws
Exception
{
// check that we can access a state-permission restricted resource on the
broker
HttpUtil.makeRequest(
- datasourceReadWithStateUserClient,
+ datasourceWithStateUserClient,
HttpMethod.GET,
config.getBrokerUrl() + "/status",
null
);
// as user that can read auth_test and STATE
- LOG.info("Checking sys.segments query as datasourceReadWithStateUser...");
+ LOG.info("Checking sys.segments query as datasourceWithStateUser...");
verifySystemSchemaQuery(
- datasourceReadWithStateUserClient,
+ datasourceWithStateUserClient,
SYS_SCHEMA_SEGMENTS_QUERY,
adminSegments.stream()
.filter((segmentEntry) ->
"auth_test".equals(segmentEntry.get("datasource")))
.collect(Collectors.toList())
);
- LOG.info("Checking sys.servers query as datasourceReadWithStateUser...");
+ LOG.info("Checking sys.servers query as datasourceWithStateUser...");
verifySystemSchemaServerQuery(
- datasourceReadWithStateUserClient,
+ datasourceWithStateUserClient,
SYS_SCHEMA_SERVERS_QUERY,
adminServers
);
- LOG.info("Checking sys.server_segments query as
datasourceReadWithStateUser...");
+ LOG.info("Checking sys.server_segments query as
datasourceWithStateUser...");
verifySystemSchemaQuery(
- datasourceReadWithStateUserClient,
+ datasourceWithStateUserClient,
SYS_SCHEMA_SERVER_SEGMENTS_QUERY,
adminServerSegments.stream()
.filter((serverSegmentEntry) -> ((String)
serverSegmentEntry.get("segment_id")).contains(
@@ -437,12 +371,13 @@ public abstract class AbstractAuthConfigurationTest
.collect(Collectors.toList())
);
- // Verify that sys.tasks result is empty as it is filtered by Datasource
WRITE access
- LOG.info("Checking sys.tasks query as datasourceReadWithStateUser...");
+ LOG.info("Checking sys.tasks query as datasourceWithStateUser...");
verifySystemSchemaQuery(
- datasourceReadWithStateUserClient,
+ datasourceWithStateUserClient,
SYS_SCHEMA_TASKS_QUERY,
- Collections.emptyList()
+ adminTasks.stream()
+ .filter((taskEntry) ->
"auth_test".equals(taskEntry.get("datasource")))
+ .collect(Collectors.toList())
);
}
@@ -565,10 +500,9 @@ public abstract class AbstractAuthConfigurationTest
protected void setupHttpClientsAndUsers() throws Exception
{
setupHttpClients();
- setupDatasourceReadOnlyUser();
- setupDatasourceReadAndSysTableUser();
- setupDatasourceWriteAndSysTableUser();
- setupDatasourceReadAndSysAndStateUser();
+ setupDatasourceOnlyUser();
+ setupDatasourceAndSysTableUser();
+ setupDatasourceAndSysAndStateUser();
setupSysTableAndStateOnlyUser();
}
@@ -832,23 +766,18 @@ public abstract class AbstractAuthConfigurationTest
httpClient
);
- datasourceReadOnlyUserClient = new CredentialedHttpClient(
- new BasicCredentials("datasourceReadOnlyUser", "helloworld"),
- httpClient
- );
-
- datasourceReadAndSysUserClient = new CredentialedHttpClient(
- new BasicCredentials("datasourceReadAndSysUser", "helloworld"),
+ datasourceOnlyUserClient = new CredentialedHttpClient(
+ new BasicCredentials("datasourceOnlyUser", "helloworld"),
httpClient
);
- datasourceWriteAndSysUserClient = new CredentialedHttpClient(
- new BasicCredentials("datasourceWriteAndSysUser", "helloworld"),
+ datasourceAndSysUserClient = new CredentialedHttpClient(
+ new BasicCredentials("datasourceAndSysUser", "helloworld"),
httpClient
);
- datasourceReadWithStateUserClient = new CredentialedHttpClient(
- new BasicCredentials("datasourceReadWithStateUser", "helloworld"),
+ datasourceWithStateUserClient = new CredentialedHttpClient(
+ new BasicCredentials("datasourceWithStateUser", "helloworld"),
httpClient
);
diff --git
a/integration-tests/src/test/java/org/apache/druid/tests/security/ITBasicAuthConfigurationTest.java
b/integration-tests/src/test/java/org/apache/druid/tests/security/ITBasicAuthConfigurationTest.java
index c87b750..690757f 100644
---
a/integration-tests/src/test/java/org/apache/druid/tests/security/ITBasicAuthConfigurationTest.java
+++
b/integration-tests/src/test/java/org/apache/druid/tests/security/ITBasicAuthConfigurationTest.java
@@ -70,50 +70,38 @@ public class ITBasicAuthConfigurationTest extends
AbstractAuthConfigurationTest
}
@Override
- protected void setupDatasourceReadOnlyUser() throws Exception
+ protected void setupDatasourceOnlyUser() throws Exception
{
createUserAndRoleWithPermissions(
adminClient,
- "datasourceReadOnlyUser",
+ "datasourceOnlyUser",
"helloworld",
- "datasourceReadOnlyRole",
- DATASOURCE_READ_ONLY_PERMISSIONS
+ "datasourceOnlyRole",
+ DATASOURCE_ONLY_PERMISSIONS
);
}
@Override
- protected void setupDatasourceReadAndSysTableUser() throws Exception
+ protected void setupDatasourceAndSysTableUser() throws Exception
{
createUserAndRoleWithPermissions(
adminClient,
- "datasourceReadAndSysUser",
+ "datasourceAndSysUser",
"helloworld",
- "datasourceReadAndSysRole",
- DATASOURCE_READ_SYS_PERMISSIONS
+ "datasourceAndSysRole",
+ DATASOURCE_SYS_PERMISSIONS
);
}
@Override
- protected void setupDatasourceWriteAndSysTableUser() throws Exception
+ protected void setupDatasourceAndSysAndStateUser() throws Exception
{
createUserAndRoleWithPermissions(
adminClient,
- "datasourceWriteAndSysUser",
+ "datasourceWithStateUser",
"helloworld",
- "datasourceWriteAndSysRole",
- DATASOURCE_WRITE_SYS_PERMISSIONS
- );
- }
-
- @Override
- protected void setupDatasourceReadAndSysAndStateUser() throws Exception
- {
- createUserAndRoleWithPermissions(
- adminClient,
- "datasourceReadWithStateUser",
- "helloworld",
- "datasourceReadWithStateRole",
- DATASOURCE_READ_SYS_STATE_PERMISSIONS
+ "datasourceWithStateRole",
+ DATASOURCE_SYS_STATE_PERMISSIONS
);
}
diff --git
a/integration-tests/src/test/java/org/apache/druid/tests/security/ITBasicAuthLdapConfigurationTest.java
b/integration-tests/src/test/java/org/apache/druid/tests/security/ITBasicAuthLdapConfigurationTest.java
index 3469f56..97a7c53 100644
---
a/integration-tests/src/test/java/org/apache/druid/tests/security/ITBasicAuthLdapConfigurationTest.java
+++
b/integration-tests/src/test/java/org/apache/druid/tests/security/ITBasicAuthLdapConfigurationTest.java
@@ -120,38 +120,29 @@ public class ITBasicAuthLdapConfigurationTest extends
AbstractAuthConfigurationT
@Override
- protected void setupDatasourceReadOnlyUser() throws Exception
+ protected void setupDatasourceOnlyUser() throws Exception
{
createRoleWithPermissionsAndGroupMapping(
- "datasourceReadOnlyGroup",
- ImmutableMap.of("datasourceReadOnlyRole",
DATASOURCE_READ_ONLY_PERMISSIONS)
+ "datasourceOnlyGroup",
+ ImmutableMap.of("datasourceOnlyRole", DATASOURCE_ONLY_PERMISSIONS)
);
}
@Override
- protected void setupDatasourceReadAndSysTableUser() throws Exception
+ protected void setupDatasourceAndSysTableUser() throws Exception
{
createRoleWithPermissionsAndGroupMapping(
- "datasourceReadWithSysGroup",
- ImmutableMap.of("datasourceReadWithSysRole",
DATASOURCE_READ_SYS_PERMISSIONS)
+ "datasourceWithSysGroup",
+ ImmutableMap.of("datasourceWithSysRole", DATASOURCE_SYS_PERMISSIONS)
);
}
@Override
- protected void setupDatasourceWriteAndSysTableUser() throws Exception
+ protected void setupDatasourceAndSysAndStateUser() throws Exception
{
createRoleWithPermissionsAndGroupMapping(
- "datasourceWriteWithSysGroup",
- ImmutableMap.of("datasourceWriteWithSysRole",
DATASOURCE_WRITE_SYS_PERMISSIONS)
- );
- }
-
- @Override
- protected void setupDatasourceReadAndSysAndStateUser() throws Exception
- {
- createRoleWithPermissionsAndGroupMapping(
- "datasourceReadWithStateGroup",
- ImmutableMap.of("datasourceReadWithStateRole",
DATASOURCE_READ_SYS_STATE_PERMISSIONS)
+ "datasourceWithStateGroup",
+ ImmutableMap.of("datasourceWithStateRole",
DATASOURCE_SYS_STATE_PERMISSIONS)
);
}
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
index f4d03a3..42b707e 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
@@ -872,7 +872,7 @@ public class SystemSchema extends AbstractSchema
);
Function<TaskStatusPlus, Iterable<ResourceAction>> raGenerator = task ->
Collections.singletonList(
-
AuthorizationUtils.DATASOURCE_WRITE_RA_GENERATOR.apply(task.getDataSource()));
+
AuthorizationUtils.DATASOURCE_READ_RA_GENERATOR.apply(task.getDataSource()));
final Iterable<TaskStatusPlus> authorizedTasks =
AuthorizationUtils.filterAuthorizedResources(
authenticationResult,
@@ -1014,7 +1014,7 @@ public class SystemSchema extends AbstractSchema
);
Function<SupervisorStatus, Iterable<ResourceAction>> raGenerator =
supervisor -> Collections.singletonList(
-
AuthorizationUtils.DATASOURCE_WRITE_RA_GENERATOR.apply(supervisor.getSource()));
+
AuthorizationUtils.DATASOURCE_READ_RA_GENERATOR.apply(supervisor.getSource()));
final Iterable<SupervisorStatus> authorizedSupervisors =
AuthorizationUtils.filterAuthorizedResources(
authenticationResult,
diff --git
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java
index 675bb8a..3936855 100644
---
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java
+++
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java
@@ -1244,15 +1244,15 @@ public class SystemSchemaTest extends CalciteTestBase
EasyMock.replay(client, request, responseHandler);
- // Verify that no row is returned for Datasource Read user
+ // Verify that no row is returned for Datasource Write user
List<Object[]> rows = tasksTable
- .scan(createDataContext(Users.DATASOURCE_READ))
+ .scan(createDataContext(Users.DATASOURCE_WRITE))
.toList();
Assert.assertTrue(rows.isEmpty());
- // Verify that 2 rows are is returned for Datasource Write user
+ // Verify that 2 rows are returned for Datasource Read user
rows = tasksTable
- .scan(createDataContext(Users.DATASOURCE_WRITE))
+ .scan(createDataContext(Users.DATASOURCE_READ))
.toList();
Assert.assertEquals(2, rows.size());
@@ -1363,15 +1363,15 @@ public class SystemSchemaTest extends CalciteTestBase
EasyMock.replay(client, request, responseHandler);
- // Verify that no row is returned for Datasource Read user
+ // Verify that no row is returned for Datasource Write user
List<Object[]> rows = supervisorTable
- .scan(createDataContext(Users.DATASOURCE_READ))
+ .scan(createDataContext(Users.DATASOURCE_WRITE))
.toList();
Assert.assertTrue(rows.isEmpty());
// Verify that 1 row is returned for Datasource Write user
rows = supervisorTable
- .scan(createDataContext(Users.DATASOURCE_WRITE))
+ .scan(createDataContext(Users.DATASOURCE_READ))
.toList();
Assert.assertEquals(1, rows.size());
@@ -1451,13 +1451,13 @@ public class SystemSchemaTest extends CalciteTestBase
final String username = authenticationResult.getIdentity();
// Allow access to a Datasource if
- // - any user requests Read access
// - Super User or Datasource Write User requests Write access
+ // - Super User or Datasource Read User requests Read access
if (resource.getType().equals(ResourceType.DATASOURCE)) {
return new Access(
- action == Action.READ
- || username.equals(Users.SUPER)
- || username.equals(Users.DATASOURCE_WRITE)
+ username.equals(Users.SUPER)
+ || (action == Action.READ &&
username.equals(Users.DATASOURCE_READ))
+ || (action == Action.WRITE &&
username.equals(Users.DATASOURCE_WRITE))
);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]