This is an automated email from the ASF dual-hosted git repository.

roryqi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new fbffe05e39 [#9583] improvement(authz): loadTable should indicate if 
it's for writing (#9585)
fbffe05e39 is described below

commit fbffe05e39113c9f21fcc1d55106aeb3e2459107
Author: roryqi <[email protected]>
AuthorDate: Wed Jan 7 17:51:55 2026 +0800

    [#9583] improvement(authz): loadTable should indicate if it's for writing 
(#9585)
    
    ### What changes were proposed in this pull request?
    
    loadTable should indicate if it's for writing
    
    ### Why are the changes needed?
    
    Fix: #9583
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Add new test cases.
---
 .../org/apache/gravitino/rel/TableCatalog.java     | 15 ++++
 .../apache/gravitino/client/RelationalCatalog.java | 26 +++++++
 .../test/authorization/TableAuthorizationIT.java   | 23 ++++++
 .../dispatcher/IcebergTableOperationExecutor.java  |  2 +-
 .../service/rest/IcebergNamespaceOperations.java   |  4 +-
 .../service/rest/IcebergTableOperations.java       |  4 +-
 .../annotations/AuthorizationExpression.java       | 14 ++++
 .../annotations/AuthorizationRequest.java          |  3 +-
 .../AuthorizationExpressionConstants.java          | 45 ++++++------
 .../AuthorizationExpressionConverter.java          | 50 ++++++-------
 .../web/filter/GravitinoInterceptionService.java   | 11 +--
 .../AssociatePolicyAuthorizationExecutor.java      |  4 +-
 .../AssociateTagAuthorizationExecutor.java         |  4 +-
 .../authorization/AuthorizeExecutorFactory.java    | 32 ++++-----
 .../authorization/CommonAuthorizerExecutor.java    |  3 +-
 .../LoadTableAuthorizationExecutor.java            | 81 ++++++++++++++++++++++
 .../authorization/RunJobAuthorizationExecutor.java |  4 +-
 .../server/web/rest/CatalogOperations.java         |  4 +-
 .../server/web/rest/FilesetOperations.java         | 10 +--
 .../gravitino/server/web/rest/JobOperations.java   |  8 +--
 .../rest/MetadataObjectCredentialOperations.java   |  3 +-
 .../web/rest/MetadataObjectPolicyOperations.java   |  2 +-
 .../web/rest/MetadataObjectTagOperations.java      |  4 +-
 .../server/web/rest/MetalakeOperations.java        |  4 +-
 .../gravitino/server/web/rest/ModelOperations.java | 20 +++---
 .../server/web/rest/PartitionOperations.java       |  8 +--
 .../server/web/rest/PolicyOperations.java          |  8 +--
 .../gravitino/server/web/rest/RoleOperations.java  |  4 +-
 .../server/web/rest/SchemaOperations.java          |  6 +-
 .../gravitino/server/web/rest/TableOperations.java | 17 +++--
 .../gravitino/server/web/rest/TagOperations.java   |  8 +--
 .../gravitino/server/web/rest/TopicOperations.java |  6 +-
 .../TestCatalogAuthorizationExpression.java        |  2 +-
 .../TestFilesetAuthorizationExpression.java        |  2 +-
 .../TestModelAuthorizationExpression.java          |  3 +-
 .../TestSchemaAuthorizationExpression.java         |  2 +-
 .../TestTableAuthorizationExpression.java          |  5 +-
 .../TestTopicAuthorizationExpression.java          |  2 +-
 38 files changed, 307 insertions(+), 146 deletions(-)

diff --git a/api/src/main/java/org/apache/gravitino/rel/TableCatalog.java 
b/api/src/main/java/org/apache/gravitino/rel/TableCatalog.java
index f2eaafb764..888526ffd5 100644
--- a/api/src/main/java/org/apache/gravitino/rel/TableCatalog.java
+++ b/api/src/main/java/org/apache/gravitino/rel/TableCatalog.java
@@ -21,9 +21,11 @@
 package org.apache.gravitino.rel;
 
 import java.util.Map;
+import java.util.Set;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.annotation.Evolving;
+import org.apache.gravitino.authorization.Privilege;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.NoSuchTableException;
 import org.apache.gravitino.exceptions.TableAlreadyExistsException;
@@ -60,6 +62,19 @@ public interface TableCatalog {
    */
   Table loadTable(NameIdentifier ident) throws NoSuchTableException;
 
+  /**
+   * Load table metadata by {@link NameIdentifier} from the catalog with 
required privileges.
+   *
+   * @param ident A table identifier.
+   * @param requiredPrivilegeNames The required privilege names to access the 
table.
+   * @return The table metadata.
+   * @throws NoSuchTableException If the table does not exist.
+   */
+  default Table loadTable(NameIdentifier ident, Set<Privilege.Name> 
requiredPrivilegeNames)
+      throws NoSuchTableException {
+    return loadTable(ident);
+  }
+
   /**
    * Check if a table exists using an {@link NameIdentifier} from the catalog.
    *
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalCatalog.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalCatalog.java
index de48ca7555..d587ad9e67 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalCatalog.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalCatalog.java
@@ -22,17 +22,21 @@ import static 
org.apache.gravitino.dto.util.DTOConverters.toDTO;
 import static org.apache.gravitino.dto.util.DTOConverters.toDTOs;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.gravitino.Catalog;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
+import org.apache.gravitino.authorization.Privilege;
 import org.apache.gravitino.dto.AuditDTO;
 import org.apache.gravitino.dto.CatalogDTO;
 import org.apache.gravitino.dto.requests.TableCreateRequest;
@@ -61,6 +65,8 @@ import org.apache.gravitino.rest.RESTUtils;
  */
 class RelationalCatalog extends BaseSchemaCatalog implements TableCatalog {
 
+  public static final String PRIVILEGES = "privileges";
+
   RelationalCatalog(
       Namespace namespace,
       String name,
@@ -127,6 +133,26 @@ class RelationalCatalog extends BaseSchemaCatalog 
implements TableCatalog {
     return RelationalTable.from(fullNamespace, resp.getTable(), restClient);
   }
 
+  @Override
+  public Table loadTable(NameIdentifier ident, Set<Privilege.Name> 
requiredPrivilegeNames)
+      throws NoSuchTableException {
+    checkTableNameIdentifier(ident);
+
+    Namespace fullNamespace = getTableFullNamespace(ident.namespace());
+    Map<String, String> queryParams = Maps.newHashMap();
+    queryParams.put(PRIVILEGES, Joiner.on(",").join(requiredPrivilegeNames));
+    TableResponse resp =
+        restClient.get(
+            formatTableRequestPath(fullNamespace) + "/" + 
RESTUtils.encodeString(ident.name()),
+            queryParams,
+            TableResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.tableErrorHandler());
+    resp.validate();
+
+    return RelationalTable.from(fullNamespace, resp.getTable(), restClient);
+  }
+
   /**
    * Create a new table with specified identifier, columns, comment and 
properties.
    *
diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TableAuthorizationIT.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TableAuthorizationIT.java
index 0df6a82dc4..80973f7304 100644
--- 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TableAuthorizationIT.java
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TableAuthorizationIT.java
@@ -23,7 +23,9 @@ import static 
org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -35,6 +37,7 @@ import org.apache.gravitino.MetadataObjects;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.authorization.Owner;
+import org.apache.gravitino.authorization.Privilege;
 import org.apache.gravitino.authorization.Privileges;
 import org.apache.gravitino.authorization.SecurableObject;
 import org.apache.gravitino.authorization.SecurableObjects;
@@ -231,6 +234,15 @@ public class TableAuthorizationIT extends 
BaseRestApiAuthorizationIT {
         MetadataObjects.of(ImmutableList.of(CATALOG, SCHEMA), 
MetadataObject.Type.SCHEMA),
         ImmutableList.of(Privileges.SelectTable.allow()));
     tableCatalogNormalUser.loadTable(NameIdentifier.of(SCHEMA, "table1"));
+
+    assertThrows(
+        String.format("Can not access metadata {%s.%s.%s}.", CATALOG, SCHEMA, 
"table1"),
+        ForbiddenException.class,
+        () -> {
+          tableCatalogNormalUser.loadTable(
+              NameIdentifier.of(SCHEMA, "table1"), 
Sets.newHashSet(Privilege.Name.MODIFY_TABLE));
+        });
+
     gravitinoMetalake.grantPrivilegesToRole(
         role,
         MetadataObjects.of(ImmutableList.of(CATALOG, SCHEMA, "table1"), 
MetadataObject.Type.TABLE),
@@ -241,6 +253,17 @@ public class TableAuthorizationIT extends 
BaseRestApiAuthorizationIT {
         () -> {
           tableCatalogNormalUser.loadTable(NameIdentifier.of(SCHEMA, 
"table1"));
         });
+
+    gravitinoMetalake.grantPrivilegesToRole(
+        role,
+        MetadataObjects.of(ImmutableList.of(CATALOG, SCHEMA, "table1"), 
MetadataObject.Type.TABLE),
+        ImmutableList.of(Privileges.ModifyTable.allow()));
+    tableCatalogNormalUser.loadTable(
+        NameIdentifier.of(SCHEMA, "table1"), 
Sets.newHashSet(Privilege.Name.MODIFY_TABLE));
+    gravitinoMetalake.revokePrivilegesFromRole(
+        role,
+        MetadataObjects.of(ImmutableList.of(CATALOG, SCHEMA, "table1"), 
MetadataObject.Type.TABLE),
+        ImmutableSet.of(Privileges.SelectTable.deny(), 
Privileges.ModifyTable.allow()));
   }
 
   @Test
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java
index 6d23c89360..ad0ee7f077 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java
@@ -166,7 +166,7 @@ public class IcebergTableOperationExecutor implements 
IcebergTableOperationDispa
         MetadataAuthzHelper.checkAccess(
             identifier,
             Entity.EntityType.TABLE,
-            
AuthorizationExpressionConstants.filterModifyTableAuthorizationExpression);
+            
AuthorizationExpressionConstants.FILTER_MODIFY_TABLE_AUTHORIZATION_EXPRESSION);
 
     return writable ? CredentialPrivilege.WRITE : CredentialPrivilege.READ;
   }
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergNamespaceOperations.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergNamespaceOperations.java
index b9b526bb64..1c669b86b6 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergNamespaceOperations.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergNamespaceOperations.java
@@ -93,7 +93,7 @@ public class IcebergNamespaceOperations {
   @Timed(name = "list-namespace." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "list-namespace", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadCatalogAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_CATALOG_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.CATALOG)
   public Response listNamespaces(
       @DefaultValue("") @Encoded() @QueryParam("parent") String parent,
@@ -343,7 +343,7 @@ public class IcebergNamespaceOperations {
     NameIdentifier[] idents =
         MetadataAuthzHelper.filterByExpression(
             metalake,
-            
AuthorizationExpressionConstants.filterSchemaAuthorizationExpression,
+            
AuthorizationExpressionConstants.FILTER_SCHEMA_AUTHORIZATION_EXPRESSION,
             Entity.EntityType.SCHEMA,
             toNameIdentifiers(listNamespacesResponse, metalake, catalogName));
     List<Namespace> filteredNamespaces = new ArrayList<>();
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
index 429a3e0d28..e499dd8c62 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
@@ -107,7 +107,7 @@ public class IcebergTableOperations {
   @Timed(name = "list-table." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "list-table", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadSchemaAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_SCHEMA_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.SCHEMA)
   public Response listTable(
       @AuthorizationMetadata(type = Entity.EntityType.CATALOG) 
@PathParam("prefix") String prefix,
@@ -535,7 +535,7 @@ public class IcebergTableOperations {
     NameIdentifier[] idents =
         MetadataAuthzHelper.filterByExpression(
             metalake,
-            
AuthorizationExpressionConstants.filterTableAuthorizationExpression,
+            
AuthorizationExpressionConstants.FILTER_TABLE_AUTHORIZATION_EXPRESSION,
             Entity.EntityType.TABLE,
             toNameIdentifiers(listTablesResponse, metalake, catalogName));
     List<TableIdentifier> filteredIdentifiers = new ArrayList<>();
diff --git 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationExpression.java
 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationExpression.java
index 3e22593313..2e772b4ce3 100644
--- 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationExpression.java
+++ 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationExpression.java
@@ -51,4 +51,18 @@ public @interface AuthorizationExpression {
    * @return error message
    */
   String errorMessage() default "";
+
+  /**
+   * The secondary expression to evaluate for authorization, which represents 
multiple privileges.
+   *
+   * @return the secondary expression to evaluate for authorization.
+   */
+  String secondaryExpression() default "";
+
+  /**
+   * The condition under which the secondary expression is evaluated.
+   *
+   * @return the condition for evaluating the secondary expression.
+   */
+  String secondaryExpressionCondition() default "";
 }
diff --git 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationRequest.java
 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationRequest.java
index 325cecfe08..93105922eb 100644
--- 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationRequest.java
+++ 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/annotations/AuthorizationRequest.java
@@ -32,6 +32,7 @@ public @interface AuthorizationRequest {
     COMMON,
     ASSOCIATE_TAG,
     ASSOCIATE_POLICY,
-    RUN_JOB
+    RUN_JOB,
+    LOAD_TABLE
   }
 }
diff --git 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConstants.java
 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConstants.java
index 85ee8541a1..6230cb109b 100644
--- 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConstants.java
+++ 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConstants.java
@@ -17,90 +17,90 @@
 package org.apache.gravitino.server.authorization.expression;
 
 public class AuthorizationExpressionConstants {
-  public static final String loadCatalogAuthorizationExpression =
+  public static final String LOAD_CATALOG_AUTHORIZATION_EXPRESSION =
       "ANY_USE_CATALOG || ANY(OWNER, METALAKE, CATALOG)";
 
-  public static final String loadSchemaAuthorizationExpression =
+  public static final String LOAD_SCHEMA_AUTHORIZATION_EXPRESSION =
       """
           ANY(OWNER, METALAKE, CATALOG) ||
           ANY_USE_CATALOG && (SCHEMA::OWNER || ANY_USE_SCHEMA)
            """;
 
-  public static final String loadModelAuthorizationExpression =
+  public static final String LOAD_MODEL_AUTHORIZATION_EXPRESSION =
       """
             ANY(OWNER, METALAKE, CATALOG) ||
              SCHEMA_OWNER_WITH_USE_CATALOG ||
               ANY_USE_CATALOG && ANY_USE_SCHEMA && (MODEL::OWNER || 
ANY_USE_MODEL)
                   """;
 
-  public static final String loadTableAuthorizationExpression =
+  public static final String LOAD_TABLE_AUTHORIZATION_EXPRESSION =
       """
                   ANY(OWNER, METALAKE, CATALOG) ||
                   SCHEMA_OWNER_WITH_USE_CATALOG ||
                   ANY_USE_CATALOG && ANY_USE_SCHEMA  && (TABLE::OWNER || 
ANY_SELECT_TABLE || ANY_MODIFY_TABLE)
                   """;
 
-  public static final String alterTableAuthorizationExpression =
+  public static final String MODIFY_TABLE_AUTHORIZATION_EXPRESSION =
       """
                   ANY(OWNER, METALAKE, CATALOG) ||
                   SCHEMA_OWNER_WITH_USE_CATALOG ||
                   ANY_USE_CATALOG && ANY_USE_SCHEMA && (TABLE::OWNER || 
ANY_MODIFY_TABLE)
                   """;
 
-  public static final String loadTopicsAuthorizationExpression =
+  public static final String LOAD_TOPICS_AUTHORIZATION_EXPRESSION =
       """
           ANY(OWNER, METALAKE, CATALOG) ||
           SCHEMA_OWNER_WITH_USE_CATALOG ||
           ANY_USE_CATALOG && ANY_USE_SCHEMA && (TOPIC::OWNER || 
ANY_CONSUME_TOPIC || ANY_PRODUCE_TOPIC)
           """;
 
-  public static final String loadFilesetAuthorizationExpression =
+  public static final String LOAD_FILESET_AUTHORIZATION_EXPRESSION =
       """
                  ANY(OWNER, METALAKE, CATALOG) ||
                  SCHEMA_OWNER_WITH_USE_CATALOG ||
                  ANY_USE_CATALOG && ANY_USE_SCHEMA && (FILESET::OWNER || 
ANY_READ_FILESET || ANY_WRITE_FILESET)
                   """;
 
-  public static final String filterSchemaAuthorizationExpression =
+  public static final String FILTER_SCHEMA_AUTHORIZATION_EXPRESSION =
       "ANY(OWNER, METALAKE, CATALOG, SCHEMA) || ANY_USE_SCHEMA";
 
-  public static final String filterModelAuthorizationExpression =
+  public static final String FILTER_MODEL_AUTHORIZATION_EXPRESSION =
       "ANY(OWNER, METALAKE, CATALOG, SCHEMA, MODEL) || ANY_USE_MODEL";
 
-  public static final String filterTableAuthorizationExpression =
+  public static final String FILTER_TABLE_AUTHORIZATION_EXPRESSION =
       """
                   ANY(OWNER, METALAKE, CATALOG, SCHEMA, TABLE) ||
                   ANY_SELECT_TABLE ||
                   ANY_MODIFY_TABLE
                   """;
 
-  public static final String filterModifyTableAuthorizationExpression =
+  public static final String FILTER_MODIFY_TABLE_AUTHORIZATION_EXPRESSION =
       """
                   ANY(OWNER, METALAKE, CATALOG, SCHEMA, TABLE) ||
                   ANY_MODIFY_TABLE
                   """;
 
-  public static final String filterWriteFilesetAuthorizationExpression =
+  public static final String FILTER_WRITE_FILESET_AUTHORIZATION_EXPRESSION =
       """
                   ANY(OWNER, METALAKE, CATALOG, SCHEMA, FILESET) ||
                   ANY_WRITE_FILESET
                   """;
 
-  public static final String filterTopicsAuthorizationExpression =
+  public static final String FILTER_TOPICS_AUTHORIZATION_EXPRESSION =
       """
               ANY(OWNER, METALAKE, CATALOG, SCHEMA, TOPIC) ||
               ANY_CONSUME_TOPIC ||
               ANY_PRODUCE_TOPIC
        """;
 
-  public static final String filterFilesetAuthorizationExpression =
+  public static final String FILTER_FILESET_AUTHORIZATION_EXPRESSION =
       """
               ANY(OWNER, METALAKE, CATALOG, SCHEMA, FILESET) ||
               ANY_READ_FILESET ||
               ANY_WRITE_FILESET
                   """;
 
-  public static final String loadRoleAuthorizationExpression =
+  public static final String LOAD_ROLE_AUTHORIZATION_EXPRESSION =
       """
           METALAKE::OWNER || METALAKE::MANAGE_GRANTS
           || ROLE::OWNER || ROLE::SELF
@@ -114,13 +114,13 @@ public class AuthorizationExpressionConstants {
           ((CAN_ACCESS_METADATA) && (TAG::OWNER || ANY_APPLY_TAG))
           """;
 
-  public static final String loadTagAuthorizationExpression =
+  public static final String LOAD_TAG_AUTHORIZATION_EXPRESSION =
       "METALAKE::OWNER || TAG::OWNER || ANY_APPLY_TAG";
 
-  public static final String applyTagAuthorizationExpression =
+  public static final String APPLY_TAG_AUTHORIZATION_EXPRESSION =
       "METALAKE::OWNER || TAG::OWNER || ANY_APPLY_TAG";
 
-  public static final String loadPolicyAuthorizationExpression =
+  public static final String LOAD_POLICY_AUTHORIZATION_EXPRESSION =
       """
           METALAKE::OWNER || POLICY::OWNER || ANY_APPLY_POLICY
           """;
@@ -131,10 +131,13 @@ public class AuthorizationExpressionConstants {
    * authorization checks {@link
    * 
org.apache.gravitino.authorization.GravitinoAuthorizer#isMetalakeUser(String)}.
    */
-  public static final String loadMetalakeAuthorizationExpression = 
"METALAKE_USER";
+  public static final String LOAD_METALAKE_AUTHORIZATION_EXPRESSION = 
"METALAKE_USER";
 
-  public static final String loadJobAuthorizationExpression = "METALAKE::OWNER 
|| JOB::OWNER";
+  public static final String LOAD_JOB_AUTHORIZATION_EXPRESSION = 
"METALAKE::OWNER || JOB::OWNER";
 
-  public static final String loadJobTemplateAuthorizationExpression =
+  public static final String LOAD_JOB_TEMPLATE_AUTHORIZATION_EXPRESSION =
       "METALAKE::OWNER || JOB_TEMPLATE::OWNER || ANY_USE_JOB_TEMPLATE";
+
+  public static final String REQUEST_REQUIRED_PRIVILEGES_CONTAINS_MODIFY_TABLE 
=
+      "REQUEST::REQUIRED_PRIVILEGES_CONTAINS_MODIFY_TABLE";
 }
diff --git 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java
 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java
index 34648782b4..4c1b36a4e0 100644
--- 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java
+++ 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java
@@ -17,18 +17,18 @@
 
 package org.apache.gravitino.server.authorization.expression;
 
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadCatalogAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadFilesetAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadJobAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadJobTemplateAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadMetalakeAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadModelAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadPolicyAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadRoleAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadSchemaAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadTableAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadTagAuthorizationExpression;
-import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.loadTopicsAuthorizationExpression;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_CATALOG_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_FILESET_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_JOB_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_JOB_TEMPLATE_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_METALAKE_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_MODEL_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_POLICY_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_ROLE_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_SCHEMA_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_TABLE_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION;
+import static 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants.LOAD_TOPICS_AUTHORIZATION_EXPRESSION;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -183,19 +183,19 @@ public class AuthorizationExpressionConverter {
               ( entityType == 'COLUMN' && (%s))
               """
             .formatted(
-                loadCatalogAuthorizationExpression,
-                loadSchemaAuthorizationExpression,
-                loadTableAuthorizationExpression,
-                loadModelAuthorizationExpression,
-                loadFilesetAuthorizationExpression,
-                loadTopicsAuthorizationExpression,
-                loadRoleAuthorizationExpression,
-                loadMetalakeAuthorizationExpression,
-                loadPolicyAuthorizationExpression,
-                loadTagAuthorizationExpression,
-                loadJobAuthorizationExpression,
-                loadJobTemplateAuthorizationExpression,
-                loadTableAuthorizationExpression));
+                LOAD_CATALOG_AUTHORIZATION_EXPRESSION,
+                LOAD_SCHEMA_AUTHORIZATION_EXPRESSION,
+                LOAD_TABLE_AUTHORIZATION_EXPRESSION,
+                LOAD_MODEL_AUTHORIZATION_EXPRESSION,
+                LOAD_FILESET_AUTHORIZATION_EXPRESSION,
+                LOAD_TOPICS_AUTHORIZATION_EXPRESSION,
+                LOAD_ROLE_AUTHORIZATION_EXPRESSION,
+                LOAD_METALAKE_AUTHORIZATION_EXPRESSION,
+                LOAD_POLICY_AUTHORIZATION_EXPRESSION,
+                LOAD_TAG_AUTHORIZATION_EXPRESSION,
+                LOAD_JOB_AUTHORIZATION_EXPRESSION,
+                LOAD_JOB_TEMPLATE_AUTHORIZATION_EXPRESSION,
+                LOAD_TABLE_AUTHORIZATION_EXPRESSION));
   }
 
   /**
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/filter/GravitinoInterceptionService.java
 
b/server/src/main/java/org/apache/gravitino/server/web/filter/GravitinoInterceptionService.java
index e974c19492..0ed9ed9cf9 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/filter/GravitinoInterceptionService.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/filter/GravitinoInterceptionService.java
@@ -45,7 +45,6 @@ import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
 import 
org.apache.gravitino.server.authorization.annotations.AuthorizationExpression;
 import 
org.apache.gravitino.server.authorization.annotations.AuthorizationRequest;
-import 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionEvaluator;
 import org.apache.gravitino.server.web.Utils;
 import 
org.apache.gravitino.server.web.filter.authorization.AuthorizationExecutor;
 import 
org.apache.gravitino.server.web.filter.authorization.AuthorizeExecutorFactory;
@@ -182,20 +181,22 @@ public class GravitinoInterceptionService implements 
InterceptionService {
 
           // If expression is empty, skip authorization check (method handles 
its own filtering)
           if (StringUtils.isNotBlank(expression)) {
-            AuthorizationExpressionEvaluator authorizationExpressionEvaluator =
-                new AuthorizationExpressionEvaluator(expression);
             AuthorizationRequest.RequestType requestType =
                 extractAuthorizationRequestTypeFromParameters(parameters);
+            String secondaryExpression = 
expressionAnnotation.secondaryExpression();
+            String secondaryExpressionCondition =
+                expressionAnnotation.secondaryExpressionCondition();
             executor =
                 AuthorizeExecutorFactory.create(
                     expression,
                     requestType,
                     metadataContext,
-                    authorizationExpressionEvaluator,
                     pathParams,
                     entityType,
                     parameters,
-                    args);
+                    args,
+                    secondaryExpression,
+                    secondaryExpressionCondition);
             boolean authorizeResult = executor.execute();
             if (!authorizeResult) {
               return buildNoAuthResponse(expressionAnnotation, 
metadataContext, method, expression);
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AssociatePolicyAuthorizationExecutor.java
 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AssociatePolicyAuthorizationExecutor.java
index 0f170efb0f..d9f4de8805 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AssociatePolicyAuthorizationExecutor.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AssociatePolicyAuthorizationExecutor.java
@@ -29,7 +29,6 @@ import org.apache.gravitino.Entity;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.authorization.AuthorizationRequestContext;
 import org.apache.gravitino.dto.requests.PoliciesAssociateRequest;
-import 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionEvaluator;
 
 /**
  * Metadata object authorization for {@link
@@ -47,10 +46,9 @@ public class AssociatePolicyAuthorizationExecutor extends 
CommonAuthorizerExecut
       Parameter[] parameters,
       Object[] args,
       Map<Entity.EntityType, NameIdentifier> metadataContext,
-      AuthorizationExpressionEvaluator authorizationExpressionEvaluator,
       Map<String, Object> pathParams,
       Optional<String> entityType) {
-    super(expression, metadataContext, authorizationExpressionEvaluator, 
pathParams, entityType);
+    super(expression, metadataContext, pathParams, entityType);
     this.parameters = parameters;
     this.args = args;
   }
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AssociateTagAuthorizationExecutor.java
 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AssociateTagAuthorizationExecutor.java
index af445fa82d..8d5080e800 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AssociateTagAuthorizationExecutor.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AssociateTagAuthorizationExecutor.java
@@ -29,7 +29,6 @@ import org.apache.gravitino.Entity;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.authorization.AuthorizationRequestContext;
 import org.apache.gravitino.dto.requests.TagsAssociateRequest;
-import 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionEvaluator;
 import org.apache.gravitino.server.web.rest.MetadataObjectTagOperations;
 
 /**
@@ -47,10 +46,9 @@ public class AssociateTagAuthorizationExecutor extends 
CommonAuthorizerExecutor
       Parameter[] parameters,
       Object[] args,
       Map<Entity.EntityType, NameIdentifier> metadataContext,
-      AuthorizationExpressionEvaluator authorizationExpressionEvaluator,
       Map<String, Object> pathParams,
       Optional<String> entityType) {
-    super(expression, metadataContext, authorizationExpressionEvaluator, 
pathParams, entityType);
+    super(expression, metadataContext, pathParams, entityType);
     this.parameters = parameters;
     this.args = args;
   }
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AuthorizeExecutorFactory.java
 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AuthorizeExecutorFactory.java
index a32b2a93ab..7b13d63c2f 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AuthorizeExecutorFactory.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/AuthorizeExecutorFactory.java
@@ -23,7 +23,6 @@ import java.util.Optional;
 import org.apache.gravitino.Entity;
 import org.apache.gravitino.NameIdentifier;
 import 
org.apache.gravitino.server.authorization.annotations.AuthorizationRequest;
-import 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionEvaluator;
 
 public class AuthorizeExecutorFactory {
 
@@ -31,37 +30,30 @@ public class AuthorizeExecutorFactory {
       String expression,
       AuthorizationRequest.RequestType requestType,
       Map<Entity.EntityType, NameIdentifier> metadataContext,
-      AuthorizationExpressionEvaluator authorizationExpressionEvaluator,
       Map<String, Object> pathParams,
       Optional<String> entityType,
       Parameter[] parameters,
-      Object[] args) {
+      Object[] args,
+      String secondaryExpression,
+      String secondaryExpressionCondition) {
     return switch (requestType) {
       case COMMON -> new CommonAuthorizerExecutor(
-          expression, metadataContext, authorizationExpressionEvaluator, 
pathParams, entityType);
+          expression, metadataContext, pathParams, entityType);
       case ASSOCIATE_TAG -> new AssociateTagAuthorizationExecutor(
-          expression,
-          parameters,
-          args,
-          metadataContext,
-          authorizationExpressionEvaluator,
-          pathParams,
-          entityType);
+          expression, parameters, args, metadataContext, pathParams, 
entityType);
       case ASSOCIATE_POLICY -> new AssociatePolicyAuthorizationExecutor(
-          expression,
-          parameters,
-          args,
-          metadataContext,
-          authorizationExpressionEvaluator,
-          pathParams,
-          entityType);
+          expression, parameters, args, metadataContext, pathParams, 
entityType);
       case RUN_JOB -> new RunJobAuthorizationExecutor(
+          parameters, args, expression, metadataContext, pathParams, 
entityType);
+      case LOAD_TABLE -> new LoadTableAuthorizationExecutor(
           parameters,
           args,
+          expression,
           metadataContext,
-          authorizationExpressionEvaluator,
           pathParams,
-          entityType);
+          entityType,
+          secondaryExpression,
+          secondaryExpressionCondition);
     };
   }
 }
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/CommonAuthorizerExecutor.java
 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/CommonAuthorizerExecutor.java
index 3ea84933cb..b03bdeaa58 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/CommonAuthorizerExecutor.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/CommonAuthorizerExecutor.java
@@ -35,12 +35,11 @@ public class CommonAuthorizerExecutor implements 
AuthorizationExecutor {
   public CommonAuthorizerExecutor(
       String expression,
       Map<Entity.EntityType, NameIdentifier> metadataContext,
-      AuthorizationExpressionEvaluator authorizationExpressionEvaluator,
       Map<String, Object> pathParams,
       Optional<String> entityType) {
     this.expression = expression;
     this.metadataContext = metadataContext;
-    this.authorizationExpressionEvaluator = authorizationExpressionEvaluator;
+    this.authorizationExpressionEvaluator = new 
AuthorizationExpressionEvaluator(expression);
     this.pathParams = pathParams;
     this.entityType = entityType;
   }
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/LoadTableAuthorizationExecutor.java
 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/LoadTableAuthorizationExecutor.java
new file mode 100644
index 0000000000..caa6a7b312
--- /dev/null
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/LoadTableAuthorizationExecutor.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.server.web.filter.authorization;
+
+import java.lang.reflect.Parameter;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.authorization.Privilege;
+import 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants;
+import 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionEvaluator;
+import org.apache.gravitino.server.web.filter.ParameterUtil;
+
+/**
+ * Authorization executor for load table operations.
+ *
+ * <p>This executor uses secondaryExpression and secondaryExpressionCondition 
from the annotation to
+ * determine authorization: if the condition is met (e.g., client requests 
MODIFY_TABLE privilege),
+ * the secondaryExpression is used for stricter authorization, otherwise the 
default expression is
+ * used (e.g., SELECT_TABLE).
+ *
+ * <p><b>Security Limitation:</b> This is a trust-based model. The client 
declares intended
+ * privileges, and the server trusts this declaration without validation. A 
malicious or modified
+ * client could request only SELECT_TABLE privileges to bypass MODIFY_TABLE 
authorization checks.
+ * Legacy clients without the `privileges` parameter will use default 
authorization.
+ */
+public class LoadTableAuthorizationExecutor extends CommonAuthorizerExecutor {
+  public LoadTableAuthorizationExecutor(
+      Parameter[] parameters,
+      Object[] args,
+      String expression,
+      Map<Entity.EntityType, NameIdentifier> metadataContext,
+      Map<String, Object> pathParams,
+      Optional<String> entityType,
+      String secondaryExpression,
+      String secondaryExpressionCondition) {
+    super(expression, metadataContext, pathParams, entityType);
+
+    // If secondaryExpression and condition are provided, evaluate the 
condition
+    if (StringUtils.isNotBlank(secondaryExpression)
+        && StringUtils.isNotBlank(secondaryExpressionCondition)) {
+      String privileges = (String) 
ParameterUtil.extractFromParameters(parameters, args);
+
+      // Evaluate the condition: does the request contain MODIFY_TABLE 
privilege?
+      if (privileges != null
+          && secondaryExpressionCondition.equals(
+              
AuthorizationExpressionConstants.REQUEST_REQUIRED_PRIVILEGES_CONTAINS_MODIFY_TABLE))
 {
+        Set<Privilege.Name> privilegeNames =
+            Arrays.stream(privileges.split(","))
+                .map(Privilege.Name::valueOf)
+                .collect(Collectors.toSet());
+
+        if (privilegeNames.contains(Privilege.Name.MODIFY_TABLE)) {
+          // Use the secondary expression for stricter authorization
+          this.expression = secondaryExpression;
+          this.authorizationExpressionEvaluator =
+              new AuthorizationExpressionEvaluator(secondaryExpression);
+        }
+      }
+    }
+  }
+}
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/RunJobAuthorizationExecutor.java
 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/RunJobAuthorizationExecutor.java
index 05e8308696..55a15835d0 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/RunJobAuthorizationExecutor.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/filter/authorization/RunJobAuthorizationExecutor.java
@@ -40,14 +40,14 @@ public class RunJobAuthorizationExecutor implements 
AuthorizationExecutor {
   public RunJobAuthorizationExecutor(
       Parameter[] parameters,
       Object[] args,
+      String expression,
       Map<Entity.EntityType, NameIdentifier> metadataContext,
-      AuthorizationExpressionEvaluator authorizationExpressionEvaluator,
       Map<String, Object> pathParams,
       Optional<String> entityType) {
     this.parameters = parameters;
     this.args = args;
     this.metadataContext = metadataContext;
-    this.authorizationExpressionEvaluator = authorizationExpressionEvaluator;
+    this.authorizationExpressionEvaluator = new 
AuthorizationExpressionEvaluator(expression);
     this.pathParams = pathParams;
     this.entityType = entityType;
   }
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/CatalogOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/CatalogOperations.java
index 43d7a6f779..7c66b4a852 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/CatalogOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/CatalogOperations.java
@@ -104,7 +104,7 @@ public class CatalogOperations {
               catalogs =
                   MetadataAuthzHelper.filterByExpression(
                       metalake,
-                      
AuthorizationExpressionConstants.loadCatalogAuthorizationExpression,
+                      
AuthorizationExpressionConstants.LOAD_CATALOG_AUTHORIZATION_EXPRESSION,
                       Entity.EntityType.CATALOG,
                       catalogs,
                       (catalogEntity) ->
@@ -117,7 +117,7 @@ public class CatalogOperations {
               idents =
                   MetadataAuthzHelper.filterByExpression(
                       metalake,
-                      
AuthorizationExpressionConstants.loadCatalogAuthorizationExpression,
+                      
AuthorizationExpressionConstants.LOAD_CATALOG_AUTHORIZATION_EXPRESSION,
                       Entity.EntityType.CATALOG,
                       idents);
               Response response = Utils.ok(new EntityListResponse(idents));
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/FilesetOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/FilesetOperations.java
index 6b654433c1..45a000ede8 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/FilesetOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/FilesetOperations.java
@@ -90,7 +90,7 @@ public class FilesetOperations {
   @Timed(name = "list-fileset." + MetricNames.HTTP_PROCESS_DURATION, absolute 
= true)
   @ResponseMetered(name = "list-fileset", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadSchemaAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_SCHEMA_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.SCHEMA)
   public Response listFilesets(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -108,7 +108,7 @@ public class FilesetOperations {
             idents =
                 MetadataAuthzHelper.filterByExpression(
                     metalake,
-                    
AuthorizationExpressionConstants.filterFilesetAuthorizationExpression,
+                    
AuthorizationExpressionConstants.FILTER_FILESET_AUTHORIZATION_EXPRESSION,
                     Entity.EntityType.FILESET,
                     idents);
             Response response = Utils.ok(new EntityListResponse(idents));
@@ -191,7 +191,7 @@ public class FilesetOperations {
   @Timed(name = "load-fileset." + MetricNames.HTTP_PROCESS_DURATION, absolute 
= true)
   @ResponseMetered(name = "load-fileset", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadFilesetAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_FILESET_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.FILESET)
   public Response loadFileset(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -222,7 +222,7 @@ public class FilesetOperations {
   @Timed(name = "list-fileset-files." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "list-fileset-files", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadFilesetAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_FILESET_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.FILESET)
   public Response listFiles(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -357,7 +357,7 @@ public class FilesetOperations {
   @Timed(name = "get-file-location." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "get-file-location", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadFilesetAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_FILESET_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.FILESET)
   public Response getFileLocation(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/JobOperations.java 
b/server/src/main/java/org/apache/gravitino/server/web/rest/JobOperations.java
index c4aad17a7b..77fe02e9d7 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/JobOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/JobOperations.java
@@ -112,7 +112,7 @@ public class JobOperations {
                 Lists.newArrayList(
                     MetadataAuthzHelper.filterByExpression(
                         metalake,
-                        
AuthorizationExpressionConstants.loadJobTemplateAuthorizationExpression,
+                        
AuthorizationExpressionConstants.LOAD_JOB_TEMPLATE_AUTHORIZATION_EXPRESSION,
                         Entity.EntityType.JOB_TEMPLATE,
                         jobOperationDispatcher
                             .listJobTemplates(metalake)
@@ -183,7 +183,7 @@ public class JobOperations {
   @Timed(name = "get-job-template." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "get-job-template", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadJobTemplateAuthorizationExpression)
+      expression = 
AuthorizationExpressionConstants.LOAD_JOB_TEMPLATE_AUTHORIZATION_EXPRESSION)
   public Response getJobTemplate(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
           String metalake,
@@ -299,7 +299,7 @@ public class JobOperations {
                 Lists.newArrayList(
                     MetadataAuthzHelper.filterByExpression(
                         metalake,
-                        
AuthorizationExpressionConstants.loadJobAuthorizationExpression,
+                        
AuthorizationExpressionConstants.LOAD_JOB_AUTHORIZATION_EXPRESSION,
                         Entity.EntityType.JOB,
                         jobOperationDispatcher
                             .listJobs(metalake, 
Optional.ofNullable(jobTemplateName))
@@ -322,7 +322,7 @@ public class JobOperations {
   @Timed(name = "get-job." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "get-job", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadJobAuthorizationExpression)
+      expression = 
AuthorizationExpressionConstants.LOAD_JOB_AUTHORIZATION_EXPRESSION)
   public Response getJob(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
           String metalake,
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectCredentialOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectCredentialOperations.java
index 2206574672..b597464b1d 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectCredentialOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectCredentialOperations.java
@@ -121,7 +121,8 @@ public class MetadataObjectCredentialOperations {
                 MetadataAuthzHelper.checkAccess(
                         identifier,
                         MetadataObjectUtil.toEntityType(object),
-                        
AuthorizationExpressionConstants.filterWriteFilesetAuthorizationExpression)
+                        AuthorizationExpressionConstants
+                            .FILTER_WRITE_FILESET_AUTHORIZATION_EXPRESSION)
                     ? CredentialPrivilege.WRITE
                     : CredentialPrivilege.READ;
             List<Credential> credentials =
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java
index 1ee876d665..defc9335e0 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java
@@ -182,7 +182,7 @@ public class MetadataObjectPolicyOperations {
             nonInheritedPolicies =
                 MetadataAuthzHelper.filterByExpression(
                     metalake,
-                    
AuthorizationExpressionConstants.loadPolicyAuthorizationExpression,
+                    
AuthorizationExpressionConstants.LOAD_POLICY_AUTHORIZATION_EXPRESSION,
                     Entity.EntityType.POLICY,
                     nonInheritedPolicies,
                     (policyEntity -> NameIdentifierUtil.ofPolicy(metalake, 
policyEntity.name())));
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectTagOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectTagOperations.java
index abaa0e72ec..c6cd5c6340 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectTagOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectTagOperations.java
@@ -215,7 +215,7 @@ public class MetadataObjectTagOperations {
               tagDTOS =
                   MetadataAuthzHelper.filterByExpression(
                       metalake,
-                      
AuthorizationExpressionConstants.loadTagAuthorizationExpression,
+                      
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
                       Entity.EntityType.TAG,
                       tagDTOS,
                       tagDTO -> NameIdentifierUtil.ofTag(metalake, 
tagDTO.name()));
@@ -227,7 +227,7 @@ public class MetadataObjectTagOperations {
               tagNames =
                   MetadataAuthzHelper.filterByExpression(
                       metalake,
-                      
AuthorizationExpressionConstants.loadTagAuthorizationExpression,
+                      
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
                       Entity.EntityType.TAG,
                       tagNames,
                       tagName -> NameIdentifierUtil.ofTag(metalake, tagName));
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetalakeOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetalakeOperations.java
index c1c7b62a8b..8b4e20934b 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetalakeOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetalakeOperations.java
@@ -93,7 +93,7 @@ public class MetalakeOperations {
             metalakes =
                 MetadataAuthzHelper.filterMetalakes(
                     metalakes,
-                    
AuthorizationExpressionConstants.loadMetalakeAuthorizationExpression);
+                    
AuthorizationExpressionConstants.LOAD_METALAKE_AUTHORIZATION_EXPRESSION);
             MetalakeDTO[] metalakeDTOs =
                 
Arrays.stream(metalakes).map(DTOConverters::toDTO).toArray(MetalakeDTO[]::new);
             Response response = Utils.ok(new 
MetalakeListResponse(metalakeDTOs));
@@ -143,7 +143,7 @@ public class MetalakeOperations {
   @Timed(name = "load-metalake." + MetricNames.HTTP_PROCESS_DURATION, absolute 
= true)
   @ResponseMetered(name = "load-metalake", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadMetalakeAuthorizationExpression)
+      expression = 
AuthorizationExpressionConstants.LOAD_METALAKE_AUTHORIZATION_EXPRESSION)
   public Response loadMetalake(
       @PathParam("name") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
           String metalakeName) {
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
index 9d8b041ed7..66b292b2cf 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
@@ -92,7 +92,7 @@ public class ModelOperations {
   @Timed(name = "list-model." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "list-model", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadSchemaAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_SCHEMA_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.SCHEMA)
   public Response listModels(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -111,7 +111,7 @@ public class ModelOperations {
             modelIds =
                 MetadataAuthzHelper.filterByExpression(
                     metalake,
-                    
AuthorizationExpressionConstants.filterModelAuthorizationExpression,
+                    
AuthorizationExpressionConstants.FILTER_MODEL_AUTHORIZATION_EXPRESSION,
                     Entity.EntityType.MODEL,
                     modelIds);
             LOG.info("List {} models under schema {}", modelIds.length, 
modelNs);
@@ -129,7 +129,7 @@ public class ModelOperations {
   @Timed(name = "get-model." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "get-model", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadModelAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_MODEL_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.MODEL)
   public Response getModel(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -247,7 +247,7 @@ public class ModelOperations {
   @Timed(name = "list-model-versions." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "list-model-versions", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadModelAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_MODEL_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.MODEL)
   public Response listModelVersions(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -278,7 +278,7 @@ public class ModelOperations {
                             return MetadataAuthzHelper.filterByExpression(
                                         metalake,
                                         AuthorizationExpressionConstants
-                                            .loadModelAuthorizationExpression,
+                                            
.LOAD_MODEL_AUTHORIZATION_EXPRESSION,
                                         Entity.EntityType.MODEL_VERSION,
                                         nameIdentifiers)
                                     .length
@@ -303,7 +303,7 @@ public class ModelOperations {
                             return MetadataAuthzHelper.filterByExpression(
                                         metalake,
                                         AuthorizationExpressionConstants
-                                            .loadModelAuthorizationExpression,
+                                            
.LOAD_MODEL_AUTHORIZATION_EXPRESSION,
                                         Entity.EntityType.MODEL_VERSION,
                                         nameIdentifiers)
                                     .length
@@ -326,7 +326,7 @@ public class ModelOperations {
   @Timed(name = "get-model-version." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "get-model-version", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadModelAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_MODEL_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.MODEL)
   public Response getModelVersion(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -365,7 +365,7 @@ public class ModelOperations {
   @Timed(name = "get-model-alias." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "get-model-alias", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadModelAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_MODEL_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.MODEL)
   public Response getModelVersionByAlias(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -704,7 +704,7 @@ public class ModelOperations {
   @Timed(name = "get-model-version-uri." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "get-model-version-uri", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadModelAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_MODEL_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.MODEL)
   public Response getModelVersionUri(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -744,7 +744,7 @@ public class ModelOperations {
   @Timed(name = "get-model-alias-uri." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "get-model-alias-uri", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadModelAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_MODEL_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.MODEL)
   public Response getModelVersionUriByAlias(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/PartitionOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/PartitionOperations.java
index 654f401e33..4e7b12a935 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/PartitionOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/PartitionOperations.java
@@ -73,7 +73,7 @@ public class PartitionOperations {
   @Timed(name = "list-partition-name." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "list-partition-name", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadTableAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_TABLE_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.TABLE)
   public Response listPartitionNames(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -129,7 +129,7 @@ public class PartitionOperations {
   @Timed(name = "get-partition." + MetricNames.HTTP_PROCESS_DURATION, absolute 
= true)
   @ResponseMetered(name = "get-partition", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadTableAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_TABLE_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.TABLE)
   public Response getPartition(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -171,7 +171,7 @@ public class PartitionOperations {
   @Timed(name = "add-partitions." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "add-partitions", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.alterTableAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.MODIFY_TABLE_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.TABLE)
   public Response addPartitions(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -218,7 +218,7 @@ public class PartitionOperations {
   @Timed(name = "drop-partition." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "drop-partition", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.alterTableAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.MODIFY_TABLE_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.TABLE)
   public Response dropPartition(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/PolicyOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/PolicyOperations.java
index 946ede3e16..e1202e5c18 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/PolicyOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/PolicyOperations.java
@@ -107,7 +107,7 @@ public class PolicyOperations {
               policyDTOs =
                   MetadataAuthzHelper.filterByExpression(
                       metalake,
-                      
AuthorizationExpressionConstants.loadPolicyAuthorizationExpression,
+                      
AuthorizationExpressionConstants.LOAD_POLICY_AUTHORIZATION_EXPRESSION,
                       Entity.EntityType.POLICY,
                       policyDTOs,
                       (policyDTO -> NameIdentifierUtil.ofPolicy(metalake, 
policyDTO.name())));
@@ -120,7 +120,7 @@ public class PolicyOperations {
               policyNames =
                   MetadataAuthzHelper.filterByExpression(
                       metalake,
-                      
AuthorizationExpressionConstants.loadPolicyAuthorizationExpression,
+                      
AuthorizationExpressionConstants.LOAD_POLICY_AUTHORIZATION_EXPRESSION,
                       Entity.EntityType.POLICY,
                       policyNames,
                       (policyName -> NameIdentifierUtil.ofPolicy(metalake, 
policyName)));
@@ -173,7 +173,7 @@ public class PolicyOperations {
   @Timed(name = "get-policy." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "get-policy", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadPolicyAuthorizationExpression)
+      expression = 
AuthorizationExpressionConstants.LOAD_POLICY_AUTHORIZATION_EXPRESSION)
   public Response getPolicy(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
           String metalake,
@@ -300,7 +300,7 @@ public class PolicyOperations {
   @Timed(name = "list-objects-for-policy." + 
MetricNames.HTTP_PROCESS_DURATION, absolute = true)
   @ResponseMetered(name = "list-objects-for-policy", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadPolicyAuthorizationExpression)
+      expression = 
AuthorizationExpressionConstants.LOAD_POLICY_AUTHORIZATION_EXPRESSION)
   public Response listMetadataObjectsForPolicy(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
           String metalake,
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/RoleOperations.java 
b/server/src/main/java/org/apache/gravitino/server/web/rest/RoleOperations.java
index 844ed4ece3..91981ab973 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/RoleOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/RoleOperations.java
@@ -93,7 +93,7 @@ public class RoleOperations {
             names =
                 MetadataAuthzHelper.filterByExpression(
                     metalake,
-                    
AuthorizationExpressionConstants.loadRoleAuthorizationExpression,
+                    
AuthorizationExpressionConstants.LOAD_ROLE_AUTHORIZATION_EXPRESSION,
                     Entity.EntityType.ROLE,
                     names,
                     roleName -> NameIdentifierUtil.ofRole(metalake, roleName));
@@ -110,7 +110,7 @@ public class RoleOperations {
   @Timed(name = "get-role." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "get-role", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadRoleAuthorizationExpression)
+      expression = 
AuthorizationExpressionConstants.LOAD_ROLE_AUTHORIZATION_EXPRESSION)
   public Response getRole(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
           String metalake,
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/SchemaOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/SchemaOperations.java
index 61015099f9..4eede74191 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/SchemaOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/SchemaOperations.java
@@ -81,7 +81,7 @@ public class SchemaOperations {
   @Timed(name = "list-schema." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "list-schema", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadCatalogAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_CATALOG_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.CATALOG)
   public Response listSchemas(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -98,7 +98,7 @@ public class SchemaOperations {
             idents =
                 MetadataAuthzHelper.filterByExpression(
                     metalake,
-                    
AuthorizationExpressionConstants.filterSchemaAuthorizationExpression,
+                    
AuthorizationExpressionConstants.FILTER_SCHEMA_AUTHORIZATION_EXPRESSION,
                     Entity.EntityType.SCHEMA,
                     idents);
             Response response = Utils.ok(new EntityListResponse(idents));
@@ -149,7 +149,7 @@ public class SchemaOperations {
   @Timed(name = "load-schema." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "load-schema", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadSchemaAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_SCHEMA_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.SCHEMA)
   public Response loadSchema(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/TableOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/TableOperations.java
index 803d097e19..e0c807bd52 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/TableOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/TableOperations.java
@@ -54,6 +54,7 @@ import org.apache.gravitino.rel.TableChange;
 import org.apache.gravitino.server.authorization.MetadataAuthzHelper;
 import 
org.apache.gravitino.server.authorization.annotations.AuthorizationExpression;
 import 
org.apache.gravitino.server.authorization.annotations.AuthorizationMetadata;
+import 
org.apache.gravitino.server.authorization.annotations.AuthorizationRequest;
 import 
org.apache.gravitino.server.authorization.expression.AuthorizationExpressionConstants;
 import org.apache.gravitino.server.web.Utils;
 import org.apache.gravitino.utils.NameIdentifierUtil;
@@ -80,7 +81,7 @@ public class TableOperations {
   @Timed(name = "list-table." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "list-table", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadSchemaAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_SCHEMA_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.SCHEMA)
   public Response listTables(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -97,7 +98,7 @@ public class TableOperations {
             idents =
                 MetadataAuthzHelper.filterByExpression(
                     metalake,
-                    
AuthorizationExpressionConstants.filterTableAuthorizationExpression,
+                    
AuthorizationExpressionConstants.FILTER_TABLE_AUTHORIZATION_EXPRESSION,
                     Entity.EntityType.TABLE,
                     idents);
             Response response = Utils.ok(new EntityListResponse(idents));
@@ -164,14 +165,20 @@ public class TableOperations {
   @Timed(name = "load-table." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "load-table", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadTableAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_TABLE_AUTHORIZATION_EXPRESSION,
+      secondaryExpression = 
AuthorizationExpressionConstants.MODIFY_TABLE_AUTHORIZATION_EXPRESSION,
+      secondaryExpressionCondition =
+          
AuthorizationExpressionConstants.REQUEST_REQUIRED_PRIVILEGES_CONTAINS_MODIFY_TABLE,
       accessMetadataType = MetadataObject.Type.TABLE)
   public Response loadTable(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
           String metalake,
       @PathParam("catalog") @AuthorizationMetadata(type = 
Entity.EntityType.CATALOG) String catalog,
       @PathParam("schema") @AuthorizationMetadata(type = 
Entity.EntityType.SCHEMA) String schema,
-      @PathParam("table") @AuthorizationMetadata(type = 
Entity.EntityType.TABLE) String table) {
+      @PathParam("table") @AuthorizationMetadata(type = 
Entity.EntityType.TABLE) String table,
+      @QueryParam("privileges")
+          @AuthorizationRequest(type = 
AuthorizationRequest.RequestType.LOAD_TABLE)
+          String requiredPrivileges) {
     LOG.info(
         "Received load table request for table: {}.{}.{}.{}", metalake, 
catalog, schema, table);
     try {
@@ -195,7 +202,7 @@ public class TableOperations {
   @Timed(name = "alter-table." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "alter-table", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.alterTableAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.MODIFY_TABLE_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.TABLE)
   public Response alterTable(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/TagOperations.java 
b/server/src/main/java/org/apache/gravitino/server/web/rest/TagOperations.java
index 71c4e869dd..c69b3a3432 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/TagOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/TagOperations.java
@@ -113,7 +113,7 @@ public class TagOperations {
               tagDTOs =
                   MetadataAuthzHelper.filterByExpression(
                       metalake,
-                      
AuthorizationExpressionConstants.loadTagAuthorizationExpression,
+                      
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
                       Entity.EntityType.TAG,
                       tagDTOs,
                       tagDTO -> NameIdentifierUtil.ofTag(metalake, 
tagDTO.name()));
@@ -126,7 +126,7 @@ public class TagOperations {
               tagNames =
                   MetadataAuthzHelper.filterByExpression(
                       metalake,
-                      
AuthorizationExpressionConstants.loadTagAuthorizationExpression,
+                      
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
                       Entity.EntityType.TAG,
                       tagNames,
                       tagName -> NameIdentifierUtil.ofTag(metalake, tagName));
@@ -174,7 +174,7 @@ public class TagOperations {
   @Timed(name = "get-tag." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "get-tag", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadTagAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.TAG)
   public Response getTag(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -264,7 +264,7 @@ public class TagOperations {
   @Timed(name = "list-objects-for-tag." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
   @ResponseMetered(name = "list-objects-for-tag", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadTagAuthorizationExpression)
+      expression = 
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION)
   public Response listMetadataObjectsForTag(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
           String metalake,
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/TopicOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/TopicOperations.java
index b4483042f1..dfa8f322e2 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/TopicOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/TopicOperations.java
@@ -74,7 +74,7 @@ public class TopicOperations {
   @Timed(name = "list-topic." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "list-topic", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadSchemaAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_SCHEMA_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.SCHEMA)
   public Response listTopics(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
@@ -93,7 +93,7 @@ public class TopicOperations {
             topics =
                 MetadataAuthzHelper.filterByExpression(
                     metalake,
-                    
AuthorizationExpressionConstants.filterTopicsAuthorizationExpression,
+                    
AuthorizationExpressionConstants.FILTER_TOPICS_AUTHORIZATION_EXPRESSION,
                     Entity.EntityType.TOPIC,
                     topics);
             Response response = Utils.ok(new EntityListResponse(topics));
@@ -161,7 +161,7 @@ public class TopicOperations {
   @Timed(name = "load-topic." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "load-topic", absolute = true)
   @AuthorizationExpression(
-      expression = 
AuthorizationExpressionConstants.loadTopicsAuthorizationExpression,
+      expression = 
AuthorizationExpressionConstants.LOAD_TOPICS_AUTHORIZATION_EXPRESSION,
       accessMetadataType = MetadataObject.Type.TOPIC)
   public Response loadTopic(
       @PathParam("metalake") @AuthorizationMetadata(type = 
Entity.EntityType.METALAKE)
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestCatalogAuthorizationExpression.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestCatalogAuthorizationExpression.java
index 13ca35bba4..124ce01e6a 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestCatalogAuthorizationExpression.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestCatalogAuthorizationExpression.java
@@ -76,7 +76,7 @@ public class TestCatalogAuthorizationExpression {
   public void testListCatalog() throws NoSuchFieldException, 
IllegalAccessException, OgnlException {
     Field loadTableAuthorizationExpressionField =
         AuthorizationExpressionConstants.class.getDeclaredField(
-            "loadCatalogAuthorizationExpression");
+            "LOAD_CATALOG_AUTHORIZATION_EXPRESSION");
     loadTableAuthorizationExpressionField.setAccessible(true);
     String loadTableAuthExpression = (String) 
loadTableAuthorizationExpressionField.get(null);
     MockAuthorizationExpressionEvaluator mockEvaluator =
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestFilesetAuthorizationExpression.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestFilesetAuthorizationExpression.java
index 6c7383527d..4bd0391ea0 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestFilesetAuthorizationExpression.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestFilesetAuthorizationExpression.java
@@ -83,7 +83,7 @@ public class TestFilesetAuthorizationExpression {
   public void testLoadFileset() throws OgnlException, NoSuchFieldException, 
IllegalAccessException {
     Field loadFilesetAuthorizationExpressionField =
         AuthorizationExpressionConstants.class.getDeclaredField(
-            "loadFilesetAuthorizationExpression");
+            "LOAD_FILESET_AUTHORIZATION_EXPRESSION");
     loadFilesetAuthorizationExpressionField.setAccessible(true);
     String loadFilesetAuthorizationExpression =
         (String) loadFilesetAuthorizationExpressionField.get(null);
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestModelAuthorizationExpression.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestModelAuthorizationExpression.java
index 660e634bcc..9d25905657 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestModelAuthorizationExpression.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestModelAuthorizationExpression.java
@@ -85,7 +85,8 @@ public class TestModelAuthorizationExpression {
   @Test
   public void testLoadModel() throws OgnlException, NoSuchFieldException, 
IllegalAccessException {
     Field loadModelAuthorizationExpressionField =
-        
AuthorizationExpressionConstants.class.getDeclaredField("loadModelAuthorizationExpression");
+        AuthorizationExpressionConstants.class.getDeclaredField(
+            "LOAD_MODEL_AUTHORIZATION_EXPRESSION");
     loadModelAuthorizationExpressionField.setAccessible(true);
     String loadModelAuthExpression = (String) 
loadModelAuthorizationExpressionField.get(null);
     MockAuthorizationExpressionEvaluator mockEvaluator =
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestSchemaAuthorizationExpression.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestSchemaAuthorizationExpression.java
index 62faa45303..d12c463f2a 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestSchemaAuthorizationExpression.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestSchemaAuthorizationExpression.java
@@ -95,7 +95,7 @@ public class TestSchemaAuthorizationExpression {
   public void testListSchema() throws NoSuchFieldException, 
IllegalAccessException, OgnlException {
     Field loadTableAuthorizationExpressionField =
         AuthorizationExpressionConstants.class.getDeclaredField(
-            "loadSchemaAuthorizationExpression");
+            "LOAD_SCHEMA_AUTHORIZATION_EXPRESSION");
     loadTableAuthorizationExpressionField.setAccessible(true);
     String loadTableAuthExpression = (String) 
loadTableAuthorizationExpressionField.get(null);
     MockAuthorizationExpressionEvaluator mockEvaluator =
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestTableAuthorizationExpression.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestTableAuthorizationExpression.java
index b98fa35d45..f115695416 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestTableAuthorizationExpression.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestTableAuthorizationExpression.java
@@ -84,7 +84,8 @@ public class TestTableAuthorizationExpression {
   @Test
   public void testListTable() throws IllegalAccessException, OgnlException, 
NoSuchFieldException {
     Field loadTableAuthorizationExpressionField =
-        
AuthorizationExpressionConstants.class.getDeclaredField("loadTableAuthorizationExpression");
+        AuthorizationExpressionConstants.class.getDeclaredField(
+            "LOAD_TABLE_AUTHORIZATION_EXPRESSION");
     loadTableAuthorizationExpressionField.setAccessible(true);
     String loadTableAuthExpression = (String) 
loadTableAuthorizationExpressionField.get(null);
     MockAuthorizationExpressionEvaluator mockEvaluator =
@@ -128,7 +129,7 @@ public class TestTableAuthorizationExpression {
   public void testLoadTable() throws NoSuchMethodException, OgnlException {
     Method method =
         TableOperations.class.getMethod(
-            "loadTable", String.class, String.class, String.class, 
String.class);
+            "loadTable", String.class, String.class, String.class, 
String.class, String.class);
     AuthorizationExpression authorizationExpressionAnnotation =
         method.getAnnotation(AuthorizationExpression.class);
     String expression = authorizationExpressionAnnotation.expression();
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestTopicAuthorizationExpression.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestTopicAuthorizationExpression.java
index 676be42aeb..03f8761333 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestTopicAuthorizationExpression.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/authorization/TestTopicAuthorizationExpression.java
@@ -77,7 +77,7 @@ public class TestTopicAuthorizationExpression {
   public void testLoadTopics() throws OgnlException, NoSuchFieldException, 
IllegalAccessException {
     Field loadTopicsAuthorizationExpressionField =
         AuthorizationExpressionConstants.class.getDeclaredField(
-            "loadTopicsAuthorizationExpression");
+            "LOAD_TOPICS_AUTHORIZATION_EXPRESSION");
     loadTopicsAuthorizationExpressionField.setAccessible(true);
     String loadTopicsAuthorizationExpression =
         (String) loadTopicsAuthorizationExpressionField.get(null);

Reply via email to