vrajat commented on code in PR #16043:
URL: https://github.com/apache/pinot/pull/16043#discussion_r2141774043


##########
pinot-broker/src/main/java/org/apache/pinot/broker/requesthandler/BaseSingleStageBrokerRequestHandler.java:
##########
@@ -919,6 +922,20 @@ private CompileResult compileRequest(long requestId, 
String query, SqlNodeAndOpt
       throwAccessDeniedError(requestId, query, requestContext, tableName, 
authorizationResult);
     }
 
+    //get RLS/CLS filters now

Review Comment:
   This is in the wrong place. This code block should be moved to 
`doHandleRequest`



##########
pinot-broker/src/main/java/org/apache/pinot/broker/broker/BasicAuthAccessControlFactory.java:
##########
@@ -135,6 +138,32 @@ public TableAuthorizationResult 
authorize(RequesterIdentity requesterIdentity, S
       return new TableAuthorizationResult(failedTables);
     }
 
+    @Override
+    public TableRowColAuthResult getRowColFilters(RequesterIdentity 
requesterIdentity, String table) {
+      Optional<BasicAuthPrincipal> principalOpt = 
getPrincipalOpt(requesterIdentity);
+
+      if (principalOpt.isEmpty()) {
+        throw new NotAuthorizedException("Basic");
+      }
+
+      if (table == null) {
+        return TableRowColAuthResultImpl.unrestricted();
+      }
+
+      TableRowColAuthResult tableRowColAuthResult = new 
TableRowColAuthResultImpl();
+
+      BasicAuthPrincipal principal = principalOpt.get();

Review Comment:
   This should be moved earlier in the function.? 



##########
pinot-broker/src/main/java/org/apache/pinot/broker/requesthandler/MultiStageBrokerRequestHandler.java:
##########
@@ -304,6 +304,17 @@ private void checkAuthorization(RequesterIdentity 
requesterIdentity, RequestCont
       if (!tableAuthorizationResult.hasAccess()) {
         throwTableAccessError(tableAuthorizationResult);
       }
+      AccessControl accessControl = _accessControlFactory.create();
+      for (String tableName : tables) {
+        accessControl.getRowColFilters(requesterIdentity, 
tableName).getRLSFilters()
+            .ifPresent(rowFilters -> {
+              String combinedFilters = String.join(" AND ", rowFilters);
+              String key = String.format("%s-%s", CommonConstants.RLS_FILTERS, 
tableName);

Review Comment:
   Is there a better way to store RLS filters for every table instead of 
mangling string keys ? @yashmayya do you have a better suggestion ? 



##########
pinot-broker/src/main/java/org/apache/pinot/broker/broker/BasicAuthAccessControlFactory.java:
##########
@@ -129,12 +132,43 @@ public TableAuthorizationResult 
authorize(RequesterIdentity requesterIdentity, S
           failedTables.add(table);
         }
       }
-      if (failedTables.isEmpty()) {
-        return TableAuthorizationResult.success();
-      }
+//      if (failedTables.isEmpty()) {
+//        return TableAuthorizationResult.success();
+//      }
       return new TableAuthorizationResult(failedTables);
     }
 
+    @Override
+    public TableRowColAuthResult getRowColFilters(RequesterIdentity 
requesterIdentity, String table) {
+      Optional<BasicAuthPrincipal> principalOpt = 
getPrincipalOpt(requesterIdentity);
+
+      if (principalOpt.isEmpty()) {

Review Comment:
   Another option is to check using `Preconditions`.



##########
pinot-core/src/main/java/org/apache/pinot/core/auth/BasicAuthPrincipal.java:
##########
@@ -31,14 +34,17 @@ public class BasicAuthPrincipal {
   private final Set<String> _tables;
   private final Set<String> _excludeTables;
   private final Set<String> _permissions;
+  //key: table name, val: list of RLS filters applicable for that table.
+  private final Map<String, List<String>> _rlsFilters;
 
   public BasicAuthPrincipal(String name, String token, Set<String> tables, 
Set<String> excludeTables,
-      Set<String> permissions) {
+      Set<String> permissions, Map<String, List<String>> rlsFilters) {

Review Comment:
   Can you add a constructor that does not have `rlsFilters` as a param ? 



##########
pinot-core/src/main/java/org/apache/pinot/core/auth/BasicAuthPrincipal.java:
##########
@@ -65,13 +71,27 @@ public boolean hasPermission(String permission) {
     return _permissions.isEmpty() || 
_permissions.contains(permission.toLowerCase());
   }
 
+  /**
+   * Gets the Row-Level Security (RLS) filter configured for the given table.
+   * The RLS filter is applied only if the user has access to the table
+   * (as determined by {@link #hasTable(String)}).
+   *
+   * @param tableName The name of the table.
+   * @return An {@link java.util.Optional} containing the RLS filter string if 
configured for this principal and table,
+   * otherwise {@link java.util.Optional#empty()}.
+   */
+  public Optional<List<String>> getRLSFilters(String tableName) {

Review Comment:
   Nit: Return null instead of `Optional` ? 



##########
pinot-core/src/main/java/org/apache/pinot/core/auth/BasicAuthUtils.java:
##########
@@ -76,8 +79,26 @@ public static List<BasicAuthPrincipal> 
extractBasicAuthPrincipals(PinotConfigura
       Set<String> excludeTables = extractSet(configuration, prefix + "." + 
name + "." + EXCLUDE_TABLES);
       Set<String> permissions = extractSet(configuration, prefix + "." + name 
+ "." + PERMISSIONS);
 
+      // Extract RLS filters

Review Comment:
   Can you add a unit test for this block ? 



##########
pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java:
##########
@@ -76,19 +78,26 @@ private ServerPlanRequestUtils() {
   private static final int DEFAULT_LEAF_NODE_LIMIT = Integer.MAX_VALUE;
   private static final List<String> QUERY_REWRITERS_CLASS_NAMES =
       ImmutableList.of(PredicateComparisonRewriter.class.getName(),
-          NonAggregationGroupByToDistinctQueryRewriter.class.getName());
+          NonAggregationGroupByToDistinctQueryRewriter.class.getName(), 
RlsFiltersRewriter.class.getName());
   private static final List<QueryRewriter> QUERY_REWRITERS =
       new 
ArrayList<>(QueryRewriterFactory.getQueryRewriters(QUERY_REWRITERS_CLASS_NAMES));
   private static final QueryOptimizer QUERY_OPTIMIZER = new QueryOptimizer();
 
+  public static OpChain compileLeafStage(OpChainExecutionContext 
executionContext, StagePlan stagePlan,
+      QueryExecutor leafQueryExecutor, ExecutorService executorService, 
Map<String, String> rowFilters) {
+    return compileLeafStage(executionContext, stagePlan, leafQueryExecutor, 
executorService,
+        (planNode, multiStageOperator) -> {
+        }, false, rowFilters);
+  }
+
   public static OpChain compileLeafStage(
       OpChainExecutionContext executionContext,
       StagePlan stagePlan,
       QueryExecutor leafQueryExecutor,
       ExecutorService executorService) {
     return compileLeafStage(executionContext, stagePlan, leafQueryExecutor, 
executorService,
         (planNode, multiStageOperator) -> {
-        }, false);
+        }, false, Map.of());

Review Comment:
   nit: send null instead of Map.of



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to