LuciferYang commented on code in PR #13833:
URL: https://github.com/apache/gravitino/pull/13833#discussion_r4268517573


##########
server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataAuthzHelper.java:
##########
@@ -108,58 +108,111 @@ public class MetadataAuthzHelper {
    */
   private static final Map<Entity.EntityType, Map<String, 
List<ParentScopeAccessPath>>>
       LIST_SHORT_CIRCUITS =
-          Map.of(
-              Entity.EntityType.USER,
-              principalListPaths(
-                  
AuthorizationExpressionConstants.LOAD_USER_AUTHORIZATION_EXPRESSION,
-                  Privilege.Name.MANAGE_USERS),
-              Entity.EntityType.GROUP,
-              principalListPaths(
-                  
AuthorizationExpressionConstants.LOAD_GROUP_AUTHORIZATION_EXPRESSION,
-                  Privilege.Name.MANAGE_GROUPS),
-              Entity.EntityType.ROLE,
-              principalListPaths(
-                  
AuthorizationExpressionConstants.LOAD_ROLE_AUTHORIZATION_EXPRESSION,
-                  Privilege.Name.MANAGE_GRANTS),
-              Entity.EntityType.TABLE,
-              Map.of(
-                  
AuthorizationExpressionConstants.FILTER_TABLE_AUTHORIZATION_EXPRESSION,
-                  List.of(
-                      parentOwnerPath(TABLE_PARENT_SCOPES),
-                      parentPrivilegePath(Privilege.Name.SELECT_TABLE, 
TABLE_PARENT_SCOPES),
-                      parentPrivilegePath(Privilege.Name.MODIFY_TABLE, 
TABLE_PARENT_SCOPES)),
-                  
AuthorizationExpressionConstants.LIST_TABLE_LIKE_AUTHORIZATION_EXPRESSION,
-                  List.of(
-                      parentOwnerPath(TABLE_PARENT_SCOPES),
-                      
tableLikeParentPrivilegePath(Privilege.Name.PROBE_TABLE_LIKE),
-                      
tableLikeParentPrivilegePath(Privilege.Name.SELECT_TABLE),
-                      
tableLikeParentPrivilegePath(Privilege.Name.MODIFY_TABLE),
-                      
tableLikeParentPrivilegePath(Privilege.Name.CREATE_TABLE),
-                      
tableLikeParentPrivilegePath(Privilege.Name.CREATE_VIEW))),
-              Entity.EntityType.MODEL,
-              Map.of(
-                  
AuthorizationExpressionConstants.FILTER_MODEL_AUTHORIZATION_EXPRESSION,
-                  List.of(
-                      parentOwnerPath(MODEL_PARENT_SCOPES),
-                      parentPrivilegePath(Privilege.Name.USE_MODEL, 
MODEL_PARENT_SCOPES))),
-              Entity.EntityType.JOB_TEMPLATE,
-              Map.of(
-                  
AuthorizationExpressionConstants.LOAD_JOB_TEMPLATE_AUTHORIZATION_EXPRESSION,
-                  List.of(
-                      parentOwnerPath(METALAKE_ONLY_SCOPE),
-                      parentPrivilegePath(Privilege.Name.USE_JOB_TEMPLATE, 
METALAKE_ONLY_SCOPE))),
-              Entity.EntityType.SCHEMA,
-              Map.of(
-                  
AuthorizationExpressionConstants.FILTER_SCHEMA_AUTHORIZATION_EXPRESSION,
-                  List.of(
-                      parentOwnerPath(SCHEMA_PARENT_SCOPES),
-                      parentPrivilegePath(Privilege.Name.USE_SCHEMA, 
SCHEMA_PARENT_SCOPES))),
-              Entity.EntityType.CATALOG,
-              Map.of(
-                  
AuthorizationExpressionConstants.LOAD_CATALOG_AUTHORIZATION_EXPRESSION,
-                  List.of(
-                      parentOwnerPath(CATALOG_PARENT_SCOPES),
-                      parentPrivilegePath(Privilege.Name.USE_CATALOG, 
CATALOG_PARENT_SCOPES))));
+          Map.ofEntries(
+              Map.entry(
+                  Entity.EntityType.USER,
+                  principalListPaths(
+                      
AuthorizationExpressionConstants.LOAD_USER_AUTHORIZATION_EXPRESSION,
+                      Privilege.Name.MANAGE_USERS)),
+              Map.entry(
+                  Entity.EntityType.GROUP,
+                  principalListPaths(
+                      
AuthorizationExpressionConstants.LOAD_GROUP_AUTHORIZATION_EXPRESSION,
+                      Privilege.Name.MANAGE_GROUPS)),
+              Map.entry(
+                  Entity.EntityType.ROLE,
+                  principalListPaths(
+                      
AuthorizationExpressionConstants.LOAD_ROLE_AUTHORIZATION_EXPRESSION,
+                      Privilege.Name.MANAGE_GRANTS)),
+              Map.entry(
+                  Entity.EntityType.TABLE,
+                  Map.of(
+                      
AuthorizationExpressionConstants.FILTER_TABLE_AUTHORIZATION_EXPRESSION,
+                      List.of(
+                          parentOwnerPath(TABLE_PARENT_SCOPES),
+                          parentPrivilegePath(Privilege.Name.SELECT_TABLE, 
TABLE_PARENT_SCOPES),
+                          parentPrivilegePath(Privilege.Name.MODIFY_TABLE, 
TABLE_PARENT_SCOPES)),
+                      
AuthorizationExpressionConstants.LIST_TABLE_LIKE_AUTHORIZATION_EXPRESSION,
+                      List.of(
+                          parentOwnerPath(TABLE_PARENT_SCOPES),
+                          
tableLikeParentPrivilegePath(Privilege.Name.PROBE_TABLE_LIKE),
+                          
tableLikeParentPrivilegePath(Privilege.Name.SELECT_TABLE),
+                          
tableLikeParentPrivilegePath(Privilege.Name.MODIFY_TABLE),
+                          
tableLikeParentPrivilegePath(Privilege.Name.CREATE_TABLE),
+                          
tableLikeParentPrivilegePath(Privilege.Name.CREATE_VIEW)))),
+              Map.entry(
+                  Entity.EntityType.MODEL,
+                  Map.of(
+                      
AuthorizationExpressionConstants.FILTER_MODEL_AUTHORIZATION_EXPRESSION,
+                      List.of(
+                          parentOwnerPath(MODEL_PARENT_SCOPES),
+                          parentPrivilegePath(Privilege.Name.USE_MODEL, 
MODEL_PARENT_SCOPES)))),
+              Map.entry(
+                  Entity.EntityType.VIEW,
+                  Map.of(
+                      
AuthorizationExpressionConstants.FILTER_VIEW_AUTHORIZATION_EXPRESSION,
+                      List.of(
+                          parentOwnerPath(TABLE_PARENT_SCOPES),
+                          parentPrivilegePath(Privilege.Name.SELECT_VIEW, 
TABLE_PARENT_SCOPES)))),
+              Map.entry(
+                  Entity.EntityType.FUNCTION,
+                  Map.of(
+                      
AuthorizationExpressionConstants.FILTER_FUNCTION_AUTHORIZATION_EXPRESSION,
+                      List.of(
+                          parentOwnerPath(TABLE_PARENT_SCOPES),
+                          parentPrivilegePath(Privilege.Name.EXECUTE_FUNCTION, 
TABLE_PARENT_SCOPES),
+                          parentPrivilegePath(
+                              Privilege.Name.MODIFY_FUNCTION, 
TABLE_PARENT_SCOPES)))),

Review Comment:
   Added SCHEMA_OBJECT_PARENT_SCOPES for the new entries.
   



##########
server-common/src/test/java/org/apache/gravitino/server/authorization/TestMetadataAuthzHelper.java:
##########
@@ -489,6 +489,377 @@ public void testListShortCircuitModelViaSchemaGrant() {
     }
   }
 
+  /** A SELECT_VIEW grant on the schema makes every view visible without 
per-view checks. */
+  @Test
+  public void testListShortCircuitViewViaSchemaGrant() {
+    EntityStore store = mock(EntityStore.class);
+    when(gravitinoEnv.entityStore()).thenReturn(store);
+    when(gravitinoEnv.cacheEnabled()).thenReturn(true);
+    when(gravitinoEnv.internalAccessControlDispatcher())
+        .thenReturn(mock(AccessControlDispatcher.class));
+    GravitinoAuthorizer authorizer =
+        mockParentGrantAuthorizer(MetadataObject.Type.SCHEMA, 
Privilege.Name.SELECT_VIEW);
+    NameIdentifier[] identifiers = views(2000);
+    try {
+      withAuthorizer(
+          authorizer,
+          () -> {
+            NameIdentifier[] filtered =
+                MetadataAuthzHelper.filterByExpression(
+                    "testMetalake",
+                    
AuthorizationExpressionConstants.FILTER_VIEW_AUTHORIZATION_EXPRESSION,
+                    Entity.EntityType.VIEW,
+                    identifiers);
+            Assertions.assertSame(identifiers, filtered);

Review Comment:
   Switched to assertArrayEquals. The never().authorize(X) check could not fail 
either way, since the per-object path stops at the schema term, so the tests 
now verify isOwner is never called on the listed objects, which the per-object 
path does for each of them.
   



##########
server-common/src/test/java/org/apache/gravitino/server/authorization/TestMetadataAuthzHelper.java:
##########
@@ -489,6 +489,377 @@ public void testListShortCircuitModelViaSchemaGrant() {
     }
   }
 
+  /** A SELECT_VIEW grant on the schema makes every view visible without 
per-view checks. */
+  @Test
+  public void testListShortCircuitViewViaSchemaGrant() {
+    EntityStore store = mock(EntityStore.class);
+    when(gravitinoEnv.entityStore()).thenReturn(store);
+    when(gravitinoEnv.cacheEnabled()).thenReturn(true);
+    when(gravitinoEnv.internalAccessControlDispatcher())
+        .thenReturn(mock(AccessControlDispatcher.class));

Review Comment:
   Extracted withPreloadEnv for the fileset and topic tests; views, functions 
and semantic models never preload, so their tests no longer set up the store at 
all.
   



##########
server-common/src/test/java/org/apache/gravitino/server/authorization/TestMetadataAuthzHelper.java:
##########
@@ -489,6 +489,377 @@ public void testListShortCircuitModelViaSchemaGrant() {
     }
   }
 
+  /** A SELECT_VIEW grant on the schema makes every view visible without 
per-view checks. */
+  @Test
+  public void testListShortCircuitViewViaSchemaGrant() {
+    EntityStore store = mock(EntityStore.class);
+    when(gravitinoEnv.entityStore()).thenReturn(store);
+    when(gravitinoEnv.cacheEnabled()).thenReturn(true);
+    when(gravitinoEnv.internalAccessControlDispatcher())
+        .thenReturn(mock(AccessControlDispatcher.class));
+    GravitinoAuthorizer authorizer =
+        mockParentGrantAuthorizer(MetadataObject.Type.SCHEMA, 
Privilege.Name.SELECT_VIEW);
+    NameIdentifier[] identifiers = views(2000);
+    try {
+      withAuthorizer(
+          authorizer,
+          () -> {
+            NameIdentifier[] filtered =
+                MetadataAuthzHelper.filterByExpression(
+                    "testMetalake",
+                    
AuthorizationExpressionConstants.FILTER_VIEW_AUTHORIZATION_EXPRESSION,
+                    Entity.EntityType.VIEW,
+                    identifiers);
+            Assertions.assertSame(identifiers, filtered);
+            verify(authorizer, never())
+                .authorize(
+                    any(),
+                    eq("testMetalake"),
+                    argThat(object -> object.type() == 
MetadataObject.Type.VIEW),
+                    any(),
+                    any());
+            verifyNoInteractions(store);
+          });
+    } finally {
+      when(gravitinoEnv.cacheEnabled()).thenReturn(false);
+      when(gravitinoEnv.entityStore()).thenReturn(null);
+      when(gravitinoEnv.internalAccessControlDispatcher()).thenReturn(null);
+    }

Review Comment:
   Same change as above.
   



##########
server-common/src/test/java/org/apache/gravitino/server/authorization/TestMetadataAuthzHelper.java:
##########
@@ -775,6 +1123,27 @@ private GravitinoAuthorizer mockParentGrantAuthorizer(
     return authorizer;
   }
 
+  /**
+   * Runs {@code body} with the entity cache enabled and the store and schema 
dispatcher that the
+   * list preload uses replaced by the given mocks.
+   */
+  private void withPreloadEnv(EntityStore store, SchemaDispatcher 
schemaDispatcher, Runnable body) {
+    when(schemaDispatcher.schemaExists(any())).thenReturn(true);
+    when(gravitinoEnv.entityStore()).thenReturn(store);
+    when(gravitinoEnv.internalSchemaDispatcher()).thenReturn(schemaDispatcher);
+    when(gravitinoEnv.internalAccessControlDispatcher())
+        .thenReturn(mock(AccessControlDispatcher.class));
+    when(gravitinoEnv.cacheEnabled()).thenReturn(true);
+    try {
+      body.run();
+    } finally {
+      when(gravitinoEnv.cacheEnabled()).thenReturn(false);
+      when(gravitinoEnv.entityStore()).thenReturn(null);
+      when(gravitinoEnv.internalSchemaDispatcher()).thenReturn(null);
+      when(gravitinoEnv.internalAccessControlDispatcher()).thenReturn(null);
+    }
+  }

Review Comment:
   `@BeforeAll` only stubs `config()`, so `false`/`null` is already the default 
for these four methods, and the other tests in this file reset them the same 
way. `Mockito.reset(gravitinoEnv)` would also drop the `config()` stub that the 
rest of the class depends on.
   



##########
server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataAuthzHelper.java:
##########
@@ -96,6 +96,7 @@ public class MetadataAuthzHelper {
 
   private static final String TABLE_PARENT_SCOPES = "METALAKE, CATALOG, 
SCHEMA";
   private static final String MODEL_PARENT_SCOPES = "METALAKE, CATALOG, 
SCHEMA";
+  private static final String SCHEMA_OBJECT_PARENT_SCOPES = "METALAKE, 
CATALOG, SCHEMA";

Review Comment:
   `TABLE_PARENT_SCOPES` and `MODEL_PARENT_SCOPES` already share this value on 
main as separate constants, and the previous round asked for a non-table name 
for the new entries. Folding all three together would rewrite the existing 
table and model entries, so I'd keep that out of this PR.
   



-- 
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]

Reply via email to