Vamsi-klu commented on code in PR #18975:
URL: https://github.com/apache/pinot/pull/18975#discussion_r3755549903


##########
pinot-controller/src/main/java/org/apache/pinot/controller/api/access/BasicAuthAccessControlFactory.java:
##########
@@ -87,15 +88,58 @@ public boolean hasAccess(String tableName, AccessType 
accessType, HttpHeaders ht
 
     @Override
     public boolean hasAccess(AccessType accessType, HttpHeaders httpHeaders, 
String endpointUrl) {
-      if (getPrincipal(httpHeaders).isEmpty()) {
+      Optional<BasicAuthPrincipal> principal = getPrincipal(httpHeaders);
+      if (principal.isEmpty()) {
         throw new NotAuthorizedException("Basic");
       }
-      return true;
+      return hasClusterAccess(principal.get(), Objects.toString(accessType));
     }
 
     @Override
     public boolean hasAccess(HttpHeaders httpHeaders, TargetType targetType) {
-      return getPrincipal(httpHeaders).isPresent();
+      return getPrincipal(httpHeaders)
+          .filter(p -> targetType == TargetType.TABLE || 
p.hasUnrestrictedTableAccess())
+          .isPresent();
+    }
+
+    @Override
+    public boolean hasAccess(HttpHeaders httpHeaders, TargetType targetType, 
String targetId, String action) {
+      Optional<BasicAuthPrincipal> principal = getPrincipal(httpHeaders);
+      if (targetType == TargetType.TABLE) {
+        return principal
+            .filter(p -> 
p.hasTable(TableNameBuilder.extractRawTableName(targetId)) && 
hasActionPermission(p, action))
+            .isPresent();
+      }
+      if (targetType == TargetType.CLUSTER) {
+        return principal.filter(p -> hasClusterAccess(p, action)).isPresent();
+      }
+      return false;
+    }
+
+    private static boolean hasClusterAccess(BasicAuthPrincipal principal, 
String action) {
+      return principal.hasUnrestrictedTableAccess() && 
hasActionPermission(principal, action);
+    }
+
+    private static boolean hasActionPermission(BasicAuthPrincipal principal, 
String action) {
+      if (action != null && principal.hasPermission(action)) {
+        return true;
+      }
+      return 
principal.hasPermission(Objects.toString(getAccessTypeForAction(action)));
+    }
+
+    private static AccessType getAccessTypeForAction(String action) {
+      if (action == null || action.startsWith("Get") || 
action.startsWith("List") || action.startsWith("Query")
+          || action.startsWith("Debug") || action.startsWith("Estimate") || 
action.startsWith("Recommend")) {
+        return AccessType.READ;
+      }
+      if (action.startsWith("Create") || action.startsWith("Ingest") || 
action.startsWith("Commit")
+          || action.startsWith("Upload")) {
+        return AccessType.CREATE;
+      }
+      if (action.startsWith("Delete") || action.startsWith("Cancel")) {
+        return AccessType.DELETE;
+      }
+      return AccessType.UPDATE;
     }

Review Comment:
   Fixed in `552a472`. Rather than patching the two copies separately I pulled 
the mapping into a single `AccessControlUtils.getAccessTypeForAction` that both 
factories call, so they cannot drift apart later.
   
   `Download` maps to READ now, and `CancelRebalance` is an exact match 
returning UPDATE evaluated before the `Cancel` prefix, which stays DELETE so 
`CancelQuery` is unaffected.
   
   While auditing the rest of `Actions` against the endpoint annotations I 
found `Validate` has the same defect you flagged: `ValidateSchema` and 
`ValidateTableConfigs` are READ endpoints but the prefix fell through to the 
default UPDATE branch, so that moved to READ as well. Tests cover all of these 
for both factories, plus null still mapping to READ.



##########
pinot-controller/src/main/java/org/apache/pinot/controller/api/access/ZkBasicAuthAccessControlFactory.java:
##########
@@ -90,12 +90,54 @@ public boolean hasAccess(String tableName, AccessType 
accessType, HttpHeaders ht
 
     @Override
     public boolean hasAccess(HttpHeaders httpHeaders, TargetType targetType) {
-      return getPrincipal(httpHeaders).isPresent();
+      return getPrincipal(httpHeaders)
+          .filter(p -> targetType == TargetType.TABLE || 
p.hasUnrestrictedTableAccess())
+          .isPresent();
     }
 
     @Override
     public boolean hasAccess(AccessType accessType, HttpHeaders httpHeaders, 
String endpointUrl) {
-      return getPrincipal(httpHeaders).isPresent();
+      return getPrincipal(httpHeaders).filter(p -> hasClusterAccess(p, 
Objects.toString(accessType))).isPresent();
+    }
+
+    @Override
+    public boolean hasAccess(HttpHeaders httpHeaders, TargetType targetType, 
String targetId, String action) {
+      Optional<ZkBasicAuthPrincipal> principal = getPrincipal(httpHeaders);
+      if (targetType == TargetType.TABLE) {
+        return principal
+            .filter(p -> 
p.hasTable(TableNameBuilder.extractRawTableName(targetId)) && 
hasActionPermission(p, action))
+            .isPresent();
+      }
+      if (targetType == TargetType.CLUSTER) {
+        return principal.filter(p -> hasClusterAccess(p, action)).isPresent();
+      }
+      return false;
+    }
+
+    private static boolean hasClusterAccess(ZkBasicAuthPrincipal principal, 
String action) {
+      return principal.hasUnrestrictedTableAccess() && 
hasActionPermission(principal, action);
+    }
+
+    private static boolean hasActionPermission(ZkBasicAuthPrincipal principal, 
String action) {
+      if (action != null && principal.hasPermission(action)) {
+        return true;
+      }
+      return 
principal.hasPermission(Objects.toString(getAccessTypeForAction(action)));
+    }
+
+    private static AccessType getAccessTypeForAction(String action) {
+      if (action == null || action.startsWith("Get") || 
action.startsWith("List") || action.startsWith("Query")
+          || action.startsWith("Debug") || action.startsWith("Estimate") || 
action.startsWith("Recommend")) {
+        return AccessType.READ;
+      }
+      if (action.startsWith("Create") || action.startsWith("Ingest") || 
action.startsWith("Commit")
+          || action.startsWith("Upload")) {
+        return AccessType.CREATE;
+      }
+      if (action.startsWith("Delete") || action.startsWith("Cancel")) {
+        return AccessType.DELETE;
+      }
+      return AccessType.UPDATE;
     }

Review Comment:
   Same fix, see the reply on the other thread. Both factories now delegate to 
one shared `AccessControlUtils.getAccessTypeForAction`, so the two copies 
cannot drift.



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to