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

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


The following commit(s) were added to refs/heads/branch-1.3 by this push:
     new e1a37d7214 [Cherry-pick to branch-1.3] [#13859] fix(authz): expose 
inaccessible object tag and policy associations (#13863) (#13878)
e1a37d7214 is described below

commit e1a37d72145c21241a0b78bcba18e33164fbae2c
Author: roryqi <[email protected]>
AuthorDate: Thu Oct 15 20:12:29 2026 +0800

    [Cherry-pick to branch-1.3] [#13859] fix(authz): expose inaccessible object 
tag and policy associations (#13863) (#13878)
    
    ### What changes were proposed in this pull request?
    
    Backport #13863 to branch-1.3.
    
    Add authorization-filtering indicators to metadata object tag and policy
    list responses:
    
    - `hasInaccessibleTags`
    - `hasInaccessiblePolicies`
    
    The indicators are included in both name and detailed responses. Direct
    and inherited associations are aggregated before authorization
    filtering.
    
    ### Why are the changes needed?
    
    When all associated tags or policies are inaccessible, the APIs
    currently return an empty list indistinguishable from an object with no
    associations.
    
    The new fields indicate whether associations were omitted without
    exposing their names, count, details, or inheritance source.
    
    Fix: #13859
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. Metadata object tag and policy list responses add boolean fields
    indicating whether inaccessible associations were omitted.
    
    ### How was this patch tested?
    
    - Common response DTO unit tests
    - Metadata object tag and policy REST tests
    - Metadata authorization helper tests
    - Tag and policy Docker authorization integration tests
    - `./gradlew :docs:build`
    - Spotless checks
---
 .../test/authorization/PolicyAuthorizationIT.java  |  78 +++++++++++++++
 .../TagOperationsAuthorizationIT.java              | 111 +++++++++++++++++++++
 ....java => MetadataObjectPolicyListResponse.java} |  51 ++++------
 ...nse.java => MetadataObjectTagListResponse.java} |  46 ++++-----
 .../gravitino/dto/responses/NameListResponse.java  |   2 +
 .../dto/responses/PolicyListResponse.java          |   2 +
 ...stResponse.java => PolicyNameListResponse.java} |  47 ++++-----
 .../gravitino/dto/responses/TagListResponse.java   |   2 +
 ...gListResponse.java => TagNameListResponse.java} |  47 ++++-----
 .../gravitino/dto/responses/TestResponses.java     |  78 +++++++++++++++
 docs/open-api/policies.yaml                        |  50 ++++++++--
 docs/open-api/tags.yaml                            |  50 ++++++++--
 .../server/authorization/MetadataAuthzHelper.java  |  25 ++---
 .../web/rest/MetadataObjectPolicyOperations.java   |  31 +++---
 .../web/rest/MetadataObjectTagOperations.java      |  37 ++++---
 .../rest/TestMetadataObjectPolicyOperations.java   |   9 +-
 .../web/rest/TestMetadataObjectTagOperations.java  |   9 +-
 17 files changed, 504 insertions(+), 171 deletions(-)

diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/PolicyAuthorizationIT.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/PolicyAuthorizationIT.java
index 5776ce1b9f..5a62a433f5 100644
--- 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/PolicyAuthorizationIT.java
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/PolicyAuthorizationIT.java
@@ -24,6 +24,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import java.io.IOException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -39,6 +40,9 @@ import org.apache.gravitino.authorization.Privileges;
 import org.apache.gravitino.authorization.SecurableObject;
 import org.apache.gravitino.authorization.SecurableObjects;
 import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.client.RESTClient;
+import org.apache.gravitino.dto.responses.MetadataObjectPolicyListResponse;
+import org.apache.gravitino.dto.responses.PolicyNameListResponse;
 import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.integration.test.container.ContainerSuite;
 import org.apache.gravitino.integration.test.container.HiveContainer;
@@ -321,6 +325,22 @@ public class PolicyAuthorizationIT extends 
BaseRestApiAuthorizationIT {
             .supportsPolicies()
             .listPolicies();
     Assertions.assertArrayEquals(new String[] {"policy2"}, policies);
+
+    RESTClient restClient = getNormalUserRestClient();
+    assertPolicyListResponse(restClient, "table1", new String[0], true);
+
+    SupportsPolicies table2Policies =
+        gravitinoMetalake
+            .loadCatalog(CATALOG)
+            .asTableCatalog()
+            .loadTable(NameIdentifier.of(SCHEMA, "table2"))
+            .supportsPolicies();
+    table2Policies.associatePolicies(new String[] {"policy1"}, new String[0]);
+    try {
+      assertPolicyListResponse(restClient, "table2", new String[] {"policy2"}, 
true);
+    } finally {
+      table2Policies.associatePolicies(new String[0], new String[] 
{"policy1"});
+    }
   }
 
   @Test
@@ -433,4 +453,62 @@ public class PolicyAuthorizationIT extends 
BaseRestApiAuthorizationIT {
     gravitinoMetalake.deletePolicy("policy1");
     metalakeLoadByNormalUser.deletePolicy("policy2");
   }
+
+  private RESTClient getNormalUserRestClient() {
+    try {
+      Method restClientMethod =
+          
normalUserClient.getClass().getSuperclass().getDeclaredMethod("restClient");
+      restClientMethod.setAccessible(true);
+      return (RESTClient) restClientMethod.invoke(normalUserClient);
+    } catch (ReflectiveOperationException e) {
+      throw new RuntimeException("Failed to access the normal user's REST 
client", e);
+    }
+  }
+
+  private void assertPolicyListResponse(
+      RESTClient restClient,
+      String tableName,
+      String[] expectedPolicyNames,
+      boolean hasInaccessiblePolicies) {
+    String path =
+        "api/metalakes/"
+            + METALAKE
+            + "/objects/table/"
+            + CATALOG
+            + "."
+            + SCHEMA
+            + "."
+            + tableName
+            + "/policies";
+    PolicyNameListResponse nameListResponse =
+        restClient.get(
+            path,
+            PolicyNameListResponse.class,
+            Map.of(),
+            error -> {
+              throw new AssertionError(error);
+            });
+    String[] actualPolicyNames = nameListResponse.getNames();
+    Arrays.sort(actualPolicyNames);
+    Arrays.sort(expectedPolicyNames);
+    Assertions.assertArrayEquals(expectedPolicyNames, actualPolicyNames);
+    Assertions.assertEquals(hasInaccessiblePolicies, 
nameListResponse.hasInaccessiblePolicies());
+
+    MetadataObjectPolicyListResponse listResponse =
+        restClient.get(
+            path,
+            Map.of("details", "true"),
+            MetadataObjectPolicyListResponse.class,
+            Map.of(),
+            error -> {
+              throw new AssertionError(error);
+            });
+    String[] actualDetailNames =
+        Arrays.stream(listResponse.getPolicies())
+            .map(policy -> policy.name())
+            .toArray(String[]::new);
+    Arrays.sort(actualDetailNames);
+    Assertions.assertArrayEquals(expectedPolicyNames, actualDetailNames);
+    Assertions.assertEquals(hasInaccessiblePolicies, 
listResponse.hasInaccessiblePolicies());
+  }
 }
diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TagOperationsAuthorizationIT.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TagOperationsAuthorizationIT.java
index f1f9111669..d21e327b5e 100644
--- 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TagOperationsAuthorizationIT.java
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TagOperationsAuthorizationIT.java
@@ -39,7 +39,10 @@ import org.apache.gravitino.authorization.Privileges;
 import org.apache.gravitino.authorization.SecurableObject;
 import org.apache.gravitino.authorization.SecurableObjects;
 import org.apache.gravitino.client.GravitinoMetalake;
+import org.apache.gravitino.client.RESTClient;
 import org.apache.gravitino.dto.MetalakeDTO;
+import org.apache.gravitino.dto.responses.MetadataObjectTagListResponse;
+import org.apache.gravitino.dto.responses.TagNameListResponse;
 import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.integration.test.container.ContainerSuite;
 import org.apache.gravitino.integration.test.container.HiveContainer;
@@ -286,6 +289,70 @@ public class TagOperationsAuthorizationIT extends 
BaseRestApiAuthorizationIT {
     assertEquals("tag2", tableSupportTagByNormalUser.getTag("tag2").name());
     assertEquals("tag3", tableSupportTagByNormalUser.getTag("tag3").name());
     assertThrows(ForbiddenException.class, () -> 
tableSupportTagByNormalUser.getTag("tag1"));
+
+    RESTClient restClient = getNormalUserRestClient();
+    String path =
+        "api/metalakes/" + METALAKE + "/objects/table/" + CATALOG + "." + 
SCHEMA + ".table1/tags";
+    TagNameListResponse nameListResponse =
+        restClient.get(
+            path,
+            TagNameListResponse.class,
+            Map.of(),
+            error -> {
+              throw new AssertionError(error);
+            });
+    Assertions.assertEquals(2, nameListResponse.getNames().length);
+    Assertions.assertTrue(nameListResponse.hasInaccessibleTags());
+
+    MetadataObjectTagListResponse listResponse =
+        restClient.get(
+            path,
+            Map.of("details", "true"),
+            MetadataObjectTagListResponse.class,
+            Map.of(),
+            error -> {
+              throw new AssertionError(error);
+            });
+    Assertions.assertEquals(2, listResponse.getTags().length);
+    Assertions.assertTrue(listResponse.hasInaccessibleTags());
+
+    String untaggedCatalog = "untagged_catalog";
+    Map<String, String> properties = Maps.newHashMap();
+    properties.put("metastore.uris", hmsUri);
+    gravitinoMetalake.createCatalog(
+        untaggedCatalog, Catalog.Type.RELATIONAL, "hive", "untagged catalog", 
properties);
+    gravitinoMetalake.grantPrivilegesToRole(
+        role,
+        MetadataObjects.of(ImmutableList.of(untaggedCatalog), 
MetadataObject.Type.CATALOG),
+        ImmutableList.of(Privileges.UseCatalog.allow()));
+
+    String tableWithOnlyInheritedHiddenTag = 
"table_with_only_inherited_hidden_tag";
+    TableCatalog tableCatalog = 
gravitinoMetalake.loadCatalog(CATALOG).asTableCatalog();
+    tableCatalog.createTable(
+        NameIdentifier.of(SCHEMA, tableWithOnlyInheritedHiddenTag),
+        createColumns(),
+        "test visibility indicators",
+        new HashMap<>());
+    try {
+      String untaggedCatalogPath =
+          "api/metalakes/" + METALAKE + "/objects/catalog/" + untaggedCatalog 
+ "/tags";
+      assertTagListResponse(untaggedCatalogPath, new String[0], false);
+
+      String inheritedHiddenTagPath =
+          "api/metalakes/"
+              + METALAKE
+              + "/objects/table/"
+              + CATALOG
+              + "."
+              + SCHEMA
+              + "."
+              + tableWithOnlyInheritedHiddenTag
+              + "/tags";
+      assertTagListResponse(inheritedHiddenTagPath, new String[0], true);
+    } finally {
+      tableCatalog.dropTable(NameIdentifier.of(SCHEMA, 
tableWithOnlyInheritedHiddenTag));
+      gravitinoMetalake.dropCatalog(untaggedCatalog, true);
+    }
   }
 
   @Test
@@ -472,4 +539,48 @@ public class TagOperationsAuthorizationIT extends 
BaseRestApiAuthorizationIT {
   private Column[] createColumns() {
     return new Column[] {Column.of("col1", Types.StringType.get())};
   }
+
+  private RESTClient getNormalUserRestClient() {
+    try {
+      Method restClientMethod =
+          
normalUserClient.getClass().getSuperclass().getDeclaredMethod("restClient");
+      restClientMethod.setAccessible(true);
+      return (RESTClient) restClientMethod.invoke(normalUserClient);
+    } catch (ReflectiveOperationException e) {
+      throw new RuntimeException("Failed to access the normal user's REST 
client", e);
+    }
+  }
+
+  private void assertTagListResponse(
+      String path, String[] expectedTagNames, boolean hasInaccessibleTags) {
+    RESTClient restClient = getNormalUserRestClient();
+    TagNameListResponse nameListResponse =
+        restClient.get(
+            path,
+            TagNameListResponse.class,
+            Map.of(),
+            error -> {
+              throw new AssertionError(error);
+            });
+    String[] actualTagNames = nameListResponse.getNames();
+    Arrays.sort(actualTagNames);
+    Arrays.sort(expectedTagNames);
+    Assertions.assertArrayEquals(expectedTagNames, actualTagNames);
+    Assertions.assertEquals(hasInaccessibleTags, 
nameListResponse.hasInaccessibleTags());
+
+    MetadataObjectTagListResponse listResponse =
+        restClient.get(
+            path,
+            Map.of("details", "true"),
+            MetadataObjectTagListResponse.class,
+            Map.of(),
+            error -> {
+              throw new AssertionError(error);
+            });
+    String[] actualDetailNames =
+        Arrays.stream(listResponse.getTags()).map(tag -> 
tag.name()).toArray(String[]::new);
+    Arrays.sort(actualDetailNames);
+    Assertions.assertArrayEquals(expectedTagNames, actualDetailNames);
+    Assertions.assertEquals(hasInaccessibleTags, 
listResponse.hasInaccessibleTags());
+  }
 }
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
 
b/common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectPolicyListResponse.java
similarity index 50%
copy from 
common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
copy to 
common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectPolicyListResponse.java
index a260171c79..c4e402bd9d 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectPolicyListResponse.java
@@ -19,52 +19,41 @@
 package org.apache.gravitino.dto.responses;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import java.util.Arrays;
 import lombok.EqualsAndHashCode;
-import lombok.Getter;
 import lombok.ToString;
 import org.apache.gravitino.dto.policy.PolicyDTO;
 
-/** Represents a response for a list of policies. */
-@Getter
+/** Represents a response for policies associated with a metadata object. */
 @ToString
 @EqualsAndHashCode(callSuper = true)
-public class PolicyListResponse extends BaseResponse {
+public class MetadataObjectPolicyListResponse extends PolicyListResponse {
 
-  @JsonProperty("policies")
-  private final PolicyDTO[] policies;
+  @JsonProperty("hasInaccessiblePolicies")
+  private final boolean hasInaccessiblePolicies;
 
   /**
-   * Creates a new PolicyListResponse.
+   * Creates a new MetadataObjectPolicyListResponse.
    *
-   * @param policies The list of policies.
+   * @param policies The list of accessible policies.
+   * @param hasInaccessiblePolicies Whether inaccessible policies were omitted 
from the response.
    */
-  public PolicyListResponse(PolicyDTO[] policies) {
-    super(0);
-    this.policies = policies;
+  public MetadataObjectPolicyListResponse(PolicyDTO[] policies, boolean 
hasInaccessiblePolicies) {
+    super(policies);
+    this.hasInaccessiblePolicies = hasInaccessiblePolicies;
   }
 
-  /**
-   * This is the constructor that is used by Jackson deserializer to create an 
instance of
-   * PolicyListResponse.
-   */
-  public PolicyListResponse() {
+  /** Constructor used by Jackson deserializer. */
+  public MetadataObjectPolicyListResponse() {
     super();
-    this.policies = null;
+    this.hasInaccessiblePolicies = false;
   }
 
-  @Override
-  public void validate() throws IllegalArgumentException {
-    super.validate();
-
-    Preconditions.checkArgument(policies != null, "\"policies\" must not be 
null");
-    Arrays.stream(policies)
-        .forEach(
-            t -> {
-              Preconditions.checkArgument(t != null, "policy must not be 
null");
-              Preconditions.checkArgument(t.content() != null, "policy content 
must not be null");
-              t.content().validate();
-            });
+  /**
+   * Returns whether inaccessible policies were omitted from the response.
+   *
+   * @return true if at least one inaccessible policy was omitted, false 
otherwise
+   */
+  public boolean hasInaccessiblePolicies() {
+    return hasInaccessiblePolicies;
   }
 }
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java 
b/common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectTagListResponse.java
similarity index 54%
copy from 
common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
copy to 
common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectTagListResponse.java
index 93c324dfe4..f8dce56b20 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectTagListResponse.java
@@ -19,47 +19,41 @@
 package org.apache.gravitino.dto.responses;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import java.util.Arrays;
 import lombok.EqualsAndHashCode;
-import lombok.Getter;
 import lombok.ToString;
 import org.apache.gravitino.dto.tag.TagDTO;
 
-/** Represents a response for a list of tags. */
-@Getter
+/** Represents a response for tags associated with a metadata object. */
 @ToString
 @EqualsAndHashCode(callSuper = true)
-public class TagListResponse extends BaseResponse {
+public class MetadataObjectTagListResponse extends TagListResponse {
 
-  @JsonProperty("tags")
-  private final TagDTO[] tags;
+  @JsonProperty("hasInaccessibleTags")
+  private final boolean hasInaccessibleTags;
 
   /**
-   * Creates a new TagListResponse.
+   * Creates a new MetadataObjectTagListResponse.
    *
-   * @param tags The list of tags.
+   * @param tags The list of accessible tags.
+   * @param hasInaccessibleTags Whether inaccessible tags were omitted from 
the response.
    */
-  public TagListResponse(TagDTO[] tags) {
-    super(0);
-    this.tags = tags;
+  public MetadataObjectTagListResponse(TagDTO[] tags, boolean 
hasInaccessibleTags) {
+    super(tags);
+    this.hasInaccessibleTags = hasInaccessibleTags;
   }
 
-  /**
-   * This is the constructor that is used by Jackson deserializer to create an 
instance of
-   * TagListResponse.
-   */
-  public TagListResponse() {
+  /** Constructor used by Jackson deserializer. */
+  public MetadataObjectTagListResponse() {
     super();
-    this.tags = null;
+    this.hasInaccessibleTags = false;
   }
 
-  @Override
-  public void validate() throws IllegalArgumentException {
-    super.validate();
-
-    Preconditions.checkArgument(tags != null, "\"tags\" must not be null");
-    Arrays.stream(tags)
-        .forEach(t -> Preconditions.checkArgument(t != null, "tag must not be 
null"));
+  /**
+   * Returns whether inaccessible tags were omitted from the response.
+   *
+   * @return true if at least one inaccessible tag was omitted, false otherwise
+   */
+  public boolean hasInaccessibleTags() {
+    return hasInaccessibleTags;
   }
 }
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/NameListResponse.java 
b/common/src/main/java/org/apache/gravitino/dto/responses/NameListResponse.java
index 0728165c5e..f6128b6b28 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/NameListResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/NameListResponse.java
@@ -18,6 +18,7 @@
  */
 package org.apache.gravitino.dto.responses;
 
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Preconditions;
 import java.util.Arrays;
@@ -27,6 +28,7 @@ import lombok.ToString;
 import org.apache.commons.lang3.StringUtils;
 
 /** Represents a response for a list of entity names. */
+@JsonIgnoreProperties(ignoreUnknown = true)
 @Getter
 @ToString
 @EqualsAndHashCode(callSuper = true)
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
 
b/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
index a260171c79..6d754e8216 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
@@ -18,6 +18,7 @@
  */
 package org.apache.gravitino.dto.responses;
 
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Preconditions;
 import java.util.Arrays;
@@ -27,6 +28,7 @@ import lombok.ToString;
 import org.apache.gravitino.dto.policy.PolicyDTO;
 
 /** Represents a response for a list of policies. */
+@JsonIgnoreProperties(ignoreUnknown = true)
 @Getter
 @ToString
 @EqualsAndHashCode(callSuper = true)
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java 
b/common/src/main/java/org/apache/gravitino/dto/responses/PolicyNameListResponse.java
similarity index 53%
copy from 
common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
copy to 
common/src/main/java/org/apache/gravitino/dto/responses/PolicyNameListResponse.java
index 93c324dfe4..351c9bb99a 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/PolicyNameListResponse.java
@@ -19,47 +19,40 @@
 package org.apache.gravitino.dto.responses;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import java.util.Arrays;
 import lombok.EqualsAndHashCode;
-import lombok.Getter;
 import lombok.ToString;
-import org.apache.gravitino.dto.tag.TagDTO;
 
-/** Represents a response for a list of tags. */
-@Getter
+/** Represents a response for a list of policy names. */
 @ToString
 @EqualsAndHashCode(callSuper = true)
-public class TagListResponse extends BaseResponse {
+public class PolicyNameListResponse extends NameListResponse {
 
-  @JsonProperty("tags")
-  private final TagDTO[] tags;
+  @JsonProperty("hasInaccessiblePolicies")
+  private final boolean hasInaccessiblePolicies;
 
   /**
-   * Creates a new TagListResponse.
+   * Creates a new PolicyNameListResponse.
    *
-   * @param tags The list of tags.
+   * @param names The list of accessible policy names.
+   * @param hasInaccessiblePolicies Whether inaccessible policies were omitted 
from the response.
    */
-  public TagListResponse(TagDTO[] tags) {
-    super(0);
-    this.tags = tags;
+  public PolicyNameListResponse(String[] names, boolean 
hasInaccessiblePolicies) {
+    super(names);
+    this.hasInaccessiblePolicies = hasInaccessiblePolicies;
   }
 
-  /**
-   * This is the constructor that is used by Jackson deserializer to create an 
instance of
-   * TagListResponse.
-   */
-  public TagListResponse() {
+  /** Constructor used by Jackson deserializer. */
+  public PolicyNameListResponse() {
     super();
-    this.tags = null;
+    this.hasInaccessiblePolicies = false;
   }
 
-  @Override
-  public void validate() throws IllegalArgumentException {
-    super.validate();
-
-    Preconditions.checkArgument(tags != null, "\"tags\" must not be null");
-    Arrays.stream(tags)
-        .forEach(t -> Preconditions.checkArgument(t != null, "tag must not be 
null"));
+  /**
+   * Returns whether inaccessible policies were omitted from the response.
+   *
+   * @return true if at least one inaccessible policy was omitted, false 
otherwise
+   */
+  public boolean hasInaccessiblePolicies() {
+    return hasInaccessiblePolicies;
   }
 }
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java 
b/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
index 93c324dfe4..1546cef918 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
@@ -18,6 +18,7 @@
  */
 package org.apache.gravitino.dto.responses;
 
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Preconditions;
 import java.util.Arrays;
@@ -27,6 +28,7 @@ import lombok.ToString;
 import org.apache.gravitino.dto.tag.TagDTO;
 
 /** Represents a response for a list of tags. */
+@JsonIgnoreProperties(ignoreUnknown = true)
 @Getter
 @ToString
 @EqualsAndHashCode(callSuper = true)
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java 
b/common/src/main/java/org/apache/gravitino/dto/responses/TagNameListResponse.java
similarity index 54%
copy from 
common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
copy to 
common/src/main/java/org/apache/gravitino/dto/responses/TagNameListResponse.java
index 93c324dfe4..20c01b8955 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/responses/TagNameListResponse.java
@@ -19,47 +19,40 @@
 package org.apache.gravitino.dto.responses;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import java.util.Arrays;
 import lombok.EqualsAndHashCode;
-import lombok.Getter;
 import lombok.ToString;
-import org.apache.gravitino.dto.tag.TagDTO;
 
-/** Represents a response for a list of tags. */
-@Getter
+/** Represents a response for a list of tag names. */
 @ToString
 @EqualsAndHashCode(callSuper = true)
-public class TagListResponse extends BaseResponse {
+public class TagNameListResponse extends NameListResponse {
 
-  @JsonProperty("tags")
-  private final TagDTO[] tags;
+  @JsonProperty("hasInaccessibleTags")
+  private final boolean hasInaccessibleTags;
 
   /**
-   * Creates a new TagListResponse.
+   * Creates a new TagNameListResponse.
    *
-   * @param tags The list of tags.
+   * @param names The list of accessible tag names.
+   * @param hasInaccessibleTags Whether inaccessible tags were omitted from 
the response.
    */
-  public TagListResponse(TagDTO[] tags) {
-    super(0);
-    this.tags = tags;
+  public TagNameListResponse(String[] names, boolean hasInaccessibleTags) {
+    super(names);
+    this.hasInaccessibleTags = hasInaccessibleTags;
   }
 
-  /**
-   * This is the constructor that is used by Jackson deserializer to create an 
instance of
-   * TagListResponse.
-   */
-  public TagListResponse() {
+  /** Constructor used by Jackson deserializer. */
+  public TagNameListResponse() {
     super();
-    this.tags = null;
+    this.hasInaccessibleTags = false;
   }
 
-  @Override
-  public void validate() throws IllegalArgumentException {
-    super.validate();
-
-    Preconditions.checkArgument(tags != null, "\"tags\" must not be null");
-    Arrays.stream(tags)
-        .forEach(t -> Preconditions.checkArgument(t != null, "tag must not be 
null"));
+  /**
+   * Returns whether inaccessible tags were omitted from the response.
+   *
+   * @return true if at least one inaccessible tag was omitted, false otherwise
+   */
+  public boolean hasInaccessibleTags() {
+    return hasInaccessibleTags;
   }
 }
diff --git 
a/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java 
b/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
index b5bd4dbda7..5bf88c740c 100644
--- a/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
+++ b/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
@@ -47,6 +47,7 @@ import 
org.apache.gravitino.dto.authorization.SecurableObjectDTO;
 import org.apache.gravitino.dto.authorization.UserDTO;
 import org.apache.gravitino.dto.model.ModelDTO;
 import org.apache.gravitino.dto.model.ModelVersionDTO;
+import org.apache.gravitino.dto.policy.PolicyDTO;
 import org.apache.gravitino.dto.rel.ColumnDTO;
 import org.apache.gravitino.dto.rel.TableDTO;
 import org.apache.gravitino.dto.rel.partitioning.Partitioning;
@@ -351,6 +352,46 @@ public class TestResponses {
     assertEquals("\"names\" must not be null", e.getMessage());
   }
 
+  @Test
+  void testTagNameListResponse() throws JsonProcessingException {
+    String[] names = new String[] {"tag1", "tag2"};
+    TagNameListResponse response = new TagNameListResponse(names, true);
+    assertDoesNotThrow(response::validate);
+
+    String serJson = JsonUtils.objectMapper().writeValueAsString(response);
+    TagNameListResponse deserResponse =
+        JsonUtils.objectMapper().readValue(serJson, TagNameListResponse.class);
+    assertEquals(response, deserResponse);
+    assertArrayEquals(names, deserResponse.getNames());
+    assertTrue(deserResponse.hasInaccessibleTags());
+
+    NameListResponse backwardCompatibleResponse =
+        JsonUtils.objectMapper().readValue(serJson, NameListResponse.class);
+    assertArrayEquals(names, backwardCompatibleResponse.getNames());
+
+    assertFalse(new TagNameListResponse(new String[0], 
false).hasInaccessibleTags());
+  }
+
+  @Test
+  void testPolicyNameListResponse() throws JsonProcessingException {
+    String[] names = new String[] {"policy1", "policy2"};
+    PolicyNameListResponse response = new PolicyNameListResponse(names, true);
+    assertDoesNotThrow(response::validate);
+
+    String serJson = JsonUtils.objectMapper().writeValueAsString(response);
+    PolicyNameListResponse deserResponse =
+        JsonUtils.objectMapper().readValue(serJson, 
PolicyNameListResponse.class);
+    assertEquals(response, deserResponse);
+    assertArrayEquals(names, deserResponse.getNames());
+    assertTrue(deserResponse.hasInaccessiblePolicies());
+
+    NameListResponse backwardCompatibleResponse =
+        JsonUtils.objectMapper().readValue(serJson, NameListResponse.class);
+    assertArrayEquals(names, backwardCompatibleResponse.getNames());
+
+    assertFalse(new PolicyNameListResponse(new String[0], 
false).hasInaccessiblePolicies());
+  }
+
   @Test
   void testTagListResponse() throws JsonProcessingException {
     TagDTO tag1 = 
TagDTO.builder().withName("tag1").withComment("comment1").build();
@@ -370,6 +411,43 @@ public class TestResponses {
     assertEquals("\"tags\" must not be null", e.getMessage());
   }
 
+  @Test
+  void testMetadataObjectTagListResponse() throws JsonProcessingException {
+    TagDTO tag = TagDTO.builder().withName("tag1").build();
+    MetadataObjectTagListResponse response =
+        new MetadataObjectTagListResponse(new TagDTO[] {tag}, true);
+    assertDoesNotThrow(response::validate);
+
+    String serJson = JsonUtils.objectMapper().writeValueAsString(response);
+    MetadataObjectTagListResponse deserResponse =
+        JsonUtils.objectMapper().readValue(serJson, 
MetadataObjectTagListResponse.class);
+    assertEquals(response, deserResponse);
+    assertArrayEquals(new TagDTO[] {tag}, deserResponse.getTags());
+    assertTrue(deserResponse.hasInaccessibleTags());
+
+    TagListResponse backwardCompatibleResponse =
+        JsonUtils.objectMapper().readValue(serJson, TagListResponse.class);
+    assertArrayEquals(new TagDTO[] {tag}, 
backwardCompatibleResponse.getTags());
+  }
+
+  @Test
+  void testMetadataObjectPolicyListResponse() throws JsonProcessingException {
+    MetadataObjectPolicyListResponse response =
+        new MetadataObjectPolicyListResponse(new PolicyDTO[0], true);
+    assertDoesNotThrow(response::validate);
+
+    String serJson = JsonUtils.objectMapper().writeValueAsString(response);
+    MetadataObjectPolicyListResponse deserResponse =
+        JsonUtils.objectMapper().readValue(serJson, 
MetadataObjectPolicyListResponse.class);
+    assertEquals(response, deserResponse);
+    assertArrayEquals(new PolicyDTO[0], deserResponse.getPolicies());
+    assertTrue(deserResponse.hasInaccessiblePolicies());
+
+    PolicyListResponse backwardCompatibleResponse =
+        JsonUtils.objectMapper().readValue(serJson, PolicyListResponse.class);
+    assertArrayEquals(new PolicyDTO[0], 
backwardCompatibleResponse.getPolicies());
+  }
+
   @Test
   void testTagResponse() throws JsonProcessingException {
     TagDTO tag = 
TagDTO.builder().withName("tag1").withComment("comment1").build();
diff --git a/docs/open-api/policies.yaml b/docs/open-api/policies.yaml
index 939116ac60..8b6325ff49 100644
--- a/docs/open-api/policies.yaml
+++ b/docs/open-api/policies.yaml
@@ -224,13 +224,13 @@ paths:
             application/vnd.gravitino.v1+json:
               schema:
                 oneOf:
-                  - $ref: "./openapi.yaml#/components/schemas/NameListResponse"
-                  - $ref: "#/components/schemas/PolicyListResponse"
+                  - $ref: "#/components/schemas/PolicyNameListResponse"
+                  - $ref: 
"#/components/schemas/MetadataObjectPolicyListResponse"
               examples:
-                NameListResponse:
-                  $ref: "#/components/examples/NameListResponse"
-                PolicyListResponse:
-                  $ref: "#/components/examples/PolicyListResponse"
+                PolicyNameListResponse:
+                  $ref: "#/components/examples/PolicyNameListResponse"
+                MetadataObjectPolicyListResponse:
+                  $ref: 
"#/components/examples/MetadataObjectPolicyListResponse"
         "400":
           $ref: "./openapi.yaml#/components/responses/BadRequestErrorResponse"
         "404":
@@ -484,6 +484,30 @@ components:
           items:
             $ref: "#/components/schemas/Policy"
 
+    PolicyNameListResponse:
+      allOf:
+        - $ref: "./openapi.yaml#/components/schemas/NameListResponse"
+        - type: object
+          required:
+            - names
+            - hasInaccessiblePolicies
+          properties:
+            hasInaccessiblePolicies:
+              type: boolean
+              description: Whether one or more inaccessible policies were 
omitted from the response
+
+    MetadataObjectPolicyListResponse:
+      allOf:
+        - $ref: "#/components/schemas/PolicyListResponse"
+        - type: object
+          required:
+            - policies
+            - hasInaccessiblePolicies
+          properties:
+            hasInaccessiblePolicies:
+              type: boolean
+              description: Whether one or more inaccessible policies were 
omitted from the response
+
     MetadataObject:
       type: object
       description: A metadata object
@@ -703,6 +727,13 @@ components:
             $ref: "#/components/schemas/MetadataObject"
 
   examples:
+    PolicyNameListResponse:
+      value: {
+        "code": 0,
+        "names": ["my_policy1"],
+        "hasInaccessiblePolicies": true
+      }
+
     NameListResponse:
       value: {
         "code": 0,
@@ -743,6 +774,13 @@ components:
         ]
       }
 
+    MetadataObjectPolicyListResponse:
+      value: {
+        "code": 0,
+        "policies": [],
+        "hasInaccessiblePolicies": true
+      }
+
     PolicyCreate:
       value: {
         "name": "my_policy1",
diff --git a/docs/open-api/tags.yaml b/docs/open-api/tags.yaml
index c2e39cd489..2ff965f5f6 100644
--- a/docs/open-api/tags.yaml
+++ b/docs/open-api/tags.yaml
@@ -197,13 +197,13 @@ paths:
             application/vnd.gravitino.v1+json:
               schema:
                 oneOf:
-                  - $ref: "./openapi.yaml#/components/schemas/NameListResponse"
-                  - $ref: "#/components/responses/TagListResponse"
+                  - $ref: "#/components/responses/TagNameListResponse"
+                  - $ref: 
"#/components/responses/MetadataObjectTagListResponse"
               examples:
-                NameListResponse:
-                  $ref: "#/components/examples/NameListResponse"
-                TagListResponse:
-                  $ref: "#/components/examples/TagListResponse"
+                TagNameListResponse:
+                  $ref: "#/components/examples/TagNameListResponse"
+                MetadataObjectTagListResponse:
+                  $ref: "#/components/examples/MetadataObjectTagListResponse"
         "400":
           $ref: "./openapi.yaml#/components/responses/BadRequestErrorResponse"
         "404":
@@ -540,6 +540,18 @@ components:
           nullable: true
 
   responses:
+    TagNameListResponse:
+      allOf:
+        - $ref: "./openapi.yaml#/components/schemas/NameListResponse"
+        - type: object
+          required:
+            - names
+            - hasInaccessibleTags
+          properties:
+            hasInaccessibleTags:
+              type: boolean
+              description: Whether one or more inaccessible tags were omitted 
from the response
+
     TagListResponse:
       type: object
       properties:
@@ -555,6 +567,18 @@ components:
           items:
             $ref: "#/components/schemas/Tag"
 
+    MetadataObjectTagListResponse:
+      allOf:
+        - $ref: "#/components/responses/TagListResponse"
+        - type: object
+          required:
+            - tags
+            - hasInaccessibleTags
+          properties:
+            hasInaccessibleTags:
+              type: boolean
+              description: Whether one or more inaccessible tags were omitted 
from the response
+
     TagResponse:
       type: object
       properties:
@@ -583,6 +607,13 @@ components:
             $ref: "#/components/schemas/MetadataObject"
 
   examples:
+    TagNameListResponse:
+      value: {
+        "code": 0,
+        "names": ["my_tag1"],
+        "hasInaccessibleTags": true
+      }
+
     NameListResponse:
       value: {
         "code": 0,
@@ -621,6 +652,13 @@ components:
         ]
       }
 
+    MetadataObjectTagListResponse:
+      value: {
+        "code": 0,
+        "tags": [],
+        "hasInaccessibleTags": true
+      }
+
     TagCreate:
       value: {
         "name": "my_tag1",
diff --git 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataAuthzHelper.java
 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataAuthzHelper.java
index 36e0f3d698..c1982b1271 100644
--- 
a/server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataAuthzHelper.java
+++ 
b/server-common/src/main/java/org/apache/gravitino/server/authorization/MetadataAuthzHelper.java
@@ -355,19 +355,20 @@ public class MetadataAuthzHelper {
     NameIdentifier[] nameIdentifiers =
         
Arrays.stream(entities).map(toNameIdentifier).toArray(NameIdentifier[]::new);
     boolean isMetadataObject = 
METADATA_OBJECT_ENTITY_TYPES.contains(entityType);
-    if (enableAuthorization() && nameIdentifiers.length > 0) {
-      if (isMetadataObject) {
-        Arrays.stream(nameIdentifiers)
-            .forEach(
-                identifier -> 
NameIdentifierUtil.checkMetadataObjectName(identifier, entityType));
-      }
+    if (!enableAuthorization() || nameIdentifiers.length == 0) {
+      return entities;
+    }
+    if (isMetadataObject) {
+      Arrays.stream(nameIdentifiers)
+          .forEach(
+              identifier -> 
NameIdentifierUtil.checkMetadataObjectName(identifier, entityType));
+    }
 
-      if (allVisibleViaParentScope(metalake, expression, entityType, 
nameIdentifiers)) {
-        // A privilege granted at a parent scope (metalake/catalog/schema) 
makes every object in
-        // the list visible, and no object-level deny exists, so the 
per-object authorization loop
-        // is skipped entirely. See 
AuthorizationExpressionConstants.*_LIST_PARENT_SCOPE_*.
-        return entities;
-      }
+    if (allVisibleViaParentScope(metalake, expression, entityType, 
nameIdentifiers)) {
+      // A privilege granted at a parent scope (metalake/catalog/schema) makes 
every object in
+      // the list visible, and no object-level deny exists, so the per-object 
authorization loop
+      // is skipped entirely. See 
AuthorizationExpressionConstants.*_LIST_PARENT_SCOPE_*.
+      return entities;
     }
     preloadToCache(entityType, nameIdentifiers);
     // Ownership is defined on metadata objects, independently of the filter 
expression.
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 19ea45ab96..f1febd685e 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
@@ -45,8 +45,9 @@ import org.apache.gravitino.MetadataObject;
 import org.apache.gravitino.MetadataObjects;
 import org.apache.gravitino.dto.policy.PolicyDTO;
 import org.apache.gravitino.dto.requests.PoliciesAssociateRequest;
+import org.apache.gravitino.dto.responses.MetadataObjectPolicyListResponse;
 import org.apache.gravitino.dto.responses.NameListResponse;
-import org.apache.gravitino.dto.responses.PolicyListResponse;
+import org.apache.gravitino.dto.responses.PolicyNameListResponse;
 import org.apache.gravitino.dto.responses.PolicyResponse;
 import org.apache.gravitino.exceptions.NoSuchPolicyException;
 import org.apache.gravitino.meta.PolicyEntity;
@@ -182,13 +183,6 @@ public class MetadataObjectPolicyOperations {
             Set<PolicyDTO> policies = Sets.newHashSet();
             PolicyEntity[] nonInheritedPolicies =
                 policyDispatcher.listPolicyInfosForMetadataObject(metalake, 
object);
-            nonInheritedPolicies =
-                MetadataAuthzHelper.filterByExpression(
-                    metalake,
-                    
AuthorizationExpressionConstants.LOAD_POLICY_AUTHORIZATION_EXPRESSION,
-                    Entity.EntityType.POLICY,
-                    nonInheritedPolicies,
-                    (policyEntity -> NameIdentifierUtil.ofPolicy(metalake, 
policyEntity.name())));
             if (ArrayUtils.isNotEmpty(nonInheritedPolicies)) {
               Collections.addAll(
                   policies,
@@ -210,17 +204,30 @@ public class MetadataObjectPolicyOperations {
               }
             }
 
+            PolicyDTO[] policyDTOs = policies.toArray(new PolicyDTO[0]);
+            int policyCount = policyDTOs.length;
+            policyDTOs =
+                MetadataAuthzHelper.filterByExpression(
+                    metalake,
+                    
AuthorizationExpressionConstants.LOAD_POLICY_AUTHORIZATION_EXPRESSION,
+                    Entity.EntityType.POLICY,
+                    policyDTOs,
+                    policyDTO -> NameIdentifierUtil.ofPolicy(metalake, 
policyDTO.name()));
+            boolean hasInaccessiblePolicies = policyDTOs.length < policyCount;
+
             if (verbose) {
               LOG.info(
                   "List {} policies info for object type: {}, full name: {} 
under metalake: {}",
-                  policies.size(),
+                  policyDTOs.length,
                   type,
                   fullName,
                   metalake);
-              return Utils.ok(new PolicyListResponse(policies.toArray(new 
PolicyDTO[0])));
+              return Utils.ok(
+                  new MetadataObjectPolicyListResponse(policyDTOs, 
hasInaccessiblePolicies));
 
             } else {
-              String[] policyNames = 
policies.stream().map(PolicyDTO::name).toArray(String[]::new);
+              String[] policyNames =
+                  
Arrays.stream(policyDTOs).map(PolicyDTO::name).toArray(String[]::new);
 
               LOG.info(
                   "List {} policies for object type: {}, full name: {} under 
metalake: {}",
@@ -228,7 +235,7 @@ public class MetadataObjectPolicyOperations {
                   type,
                   fullName,
                   metalake);
-              return Utils.ok(new NameListResponse(policyNames));
+              return Utils.ok(new PolicyNameListResponse(policyNames, 
hasInaccessiblePolicies));
             }
           });
 
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 525fe9943e..d0c5ce9a1b 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
@@ -45,8 +45,9 @@ import org.apache.gravitino.Entity;
 import org.apache.gravitino.MetadataObject;
 import org.apache.gravitino.MetadataObjects;
 import org.apache.gravitino.dto.requests.TagsAssociateRequest;
+import org.apache.gravitino.dto.responses.MetadataObjectTagListResponse;
 import org.apache.gravitino.dto.responses.NameListResponse;
-import org.apache.gravitino.dto.responses.TagListResponse;
+import org.apache.gravitino.dto.responses.TagNameListResponse;
 import org.apache.gravitino.dto.responses.TagResponse;
 import org.apache.gravitino.dto.tag.TagDTO;
 import org.apache.gravitino.dto.util.DTOConverters;
@@ -206,40 +207,36 @@ public class MetadataObjectTagOperations {
               }
             }
 
+            TagDTO[] tagDTOs = tags.toArray(new TagDTO[0]);
+            int tagCount = tagDTOs.length;
+            tagDTOs =
+                MetadataAuthzHelper.filterByExpression(
+                    metalake,
+                    
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
+                    Entity.EntityType.TAG,
+                    tagDTOs,
+                    tagDTO -> NameIdentifierUtil.ofTag(metalake, 
tagDTO.name()));
+            boolean hasInaccessibleTags = tagDTOs.length < tagCount;
+
             if (verbose) {
               LOG.info(
                   "List {} tags info for object type: {}, full name: {} under 
metalake: {}",
-                  tags.size(),
+                  tagDTOs.length,
                   type,
                   fullName,
                   metalake);
-              TagDTO[] tagDTOS = tags.toArray(new TagDTO[0]);
-              tagDTOS =
-                  MetadataAuthzHelper.filterByExpression(
-                      metalake,
-                      
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
-                      Entity.EntityType.TAG,
-                      tagDTOS,
-                      tagDTO -> NameIdentifierUtil.ofTag(metalake, 
tagDTO.name()));
-              return Utils.ok(new TagListResponse(tagDTOS));
+              return Utils.ok(new MetadataObjectTagListResponse(tagDTOs, 
hasInaccessibleTags));
 
             } else {
               // We have used Set to avoid duplicate tag names
-              String[] tagNames = 
tags.stream().map(TagDTO::name).toArray(String[]::new);
-              tagNames =
-                  MetadataAuthzHelper.filterByExpression(
-                      metalake,
-                      
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
-                      Entity.EntityType.TAG,
-                      tagNames,
-                      tagName -> NameIdentifierUtil.ofTag(metalake, tagName));
+              String[] tagNames = 
Arrays.stream(tagDTOs).map(TagDTO::name).toArray(String[]::new);
               LOG.info(
                   "List {} tags for object type: {}, full name: {} under 
metalake: {}",
                   tagNames.length,
                   type,
                   fullName,
                   metalake);
-              return Utils.ok(new NameListResponse(tagNames));
+              return Utils.ok(new TagNameListResponse(tagNames, 
hasInaccessibleTags));
             }
           });
 
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectPolicyOperations.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectPolicyOperations.java
index 6ff31e2203..341c541880 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectPolicyOperations.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectPolicyOperations.java
@@ -42,8 +42,10 @@ import org.apache.gravitino.MetadataObjects;
 import org.apache.gravitino.dto.requests.PoliciesAssociateRequest;
 import org.apache.gravitino.dto.responses.ErrorConstants;
 import org.apache.gravitino.dto.responses.ErrorResponse;
+import org.apache.gravitino.dto.responses.MetadataObjectPolicyListResponse;
 import org.apache.gravitino.dto.responses.NameListResponse;
 import org.apache.gravitino.dto.responses.PolicyListResponse;
+import org.apache.gravitino.dto.responses.PolicyNameListResponse;
 import org.apache.gravitino.dto.responses.PolicyResponse;
 import org.apache.gravitino.exceptions.NoSuchPolicyException;
 import org.apache.gravitino.exceptions.PolicyAlreadyAssociatedException;
@@ -137,9 +139,11 @@ public class TestMetadataObjectPolicyOperations extends 
BaseOperationsTest {
 
     Assertions.assertEquals(Response.Status.OK.getStatusCode(), 
response.getStatus());
 
-    PolicyListResponse policyListResponse = 
response.readEntity(PolicyListResponse.class);
+    MetadataObjectPolicyListResponse policyListResponse =
+        response.readEntity(MetadataObjectPolicyListResponse.class);
     Assertions.assertEquals(0, policyListResponse.getCode());
     Assertions.assertEquals(catalogPolicyInfos.length, 
policyListResponse.getPolicies().length);
+    Assertions.assertFalse(policyListResponse.hasInaccessiblePolicies());
 
     Map<String, Policy> resultPolicies =
         Arrays.stream(policyListResponse.getPolicies())
@@ -159,9 +163,10 @@ public class TestMetadataObjectPolicyOperations extends 
BaseOperationsTest {
 
     Assertions.assertEquals(Response.Status.OK.getStatusCode(), 
response1.getStatus());
 
-    NameListResponse nameListResponse = 
response1.readEntity(NameListResponse.class);
+    PolicyNameListResponse nameListResponse = 
response1.readEntity(PolicyNameListResponse.class);
     Assertions.assertEquals(0, nameListResponse.getCode());
     Assertions.assertEquals(catalogPolicyInfos.length, 
nameListResponse.getNames().length);
+    Assertions.assertFalse(nameListResponse.hasInaccessiblePolicies());
     Assertions.assertArrayEquals(
         
Arrays.stream(catalogPolicyInfos).map(PolicyEntity::name).toArray(String[]::new),
         nameListResponse.getNames());
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectTagOperations.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectTagOperations.java
index 93eb9cf288..e41dbc1091 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectTagOperations.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectTagOperations.java
@@ -41,8 +41,10 @@ import org.apache.gravitino.MetadataObjects;
 import org.apache.gravitino.dto.requests.TagsAssociateRequest;
 import org.apache.gravitino.dto.responses.ErrorConstants;
 import org.apache.gravitino.dto.responses.ErrorResponse;
+import org.apache.gravitino.dto.responses.MetadataObjectTagListResponse;
 import org.apache.gravitino.dto.responses.NameListResponse;
 import org.apache.gravitino.dto.responses.TagListResponse;
+import org.apache.gravitino.dto.responses.TagNameListResponse;
 import org.apache.gravitino.dto.responses.TagResponse;
 import org.apache.gravitino.exceptions.NoSuchTagException;
 import org.apache.gravitino.exceptions.TagAlreadyAssociatedException;
@@ -161,9 +163,11 @@ public class TestMetadataObjectTagOperations extends 
BaseOperationsTest {
 
     Assertions.assertEquals(Response.Status.OK.getStatusCode(), 
response.getStatus());
 
-    TagListResponse tagListResponse = 
response.readEntity(TagListResponse.class);
+    MetadataObjectTagListResponse tagListResponse =
+        response.readEntity(MetadataObjectTagListResponse.class);
     Assertions.assertEquals(0, tagListResponse.getCode());
     Assertions.assertEquals(catalogTagInfos.length, 
tagListResponse.getTags().length);
+    Assertions.assertFalse(tagListResponse.hasInaccessibleTags());
 
     Map<String, Tag> resultTags =
         Arrays.stream(tagListResponse.getTags())
@@ -183,9 +187,10 @@ public class TestMetadataObjectTagOperations extends 
BaseOperationsTest {
 
     Assertions.assertEquals(Response.Status.OK.getStatusCode(), 
response1.getStatus());
 
-    NameListResponse nameListResponse = 
response1.readEntity(NameListResponse.class);
+    TagNameListResponse nameListResponse = 
response1.readEntity(TagNameListResponse.class);
     Assertions.assertEquals(0, nameListResponse.getCode());
     Assertions.assertEquals(catalogTagInfos.length, 
nameListResponse.getNames().length);
+    Assertions.assertFalse(nameListResponse.hasInaccessibleTags());
     Assertions.assertArrayEquals(
         Arrays.stream(catalogTagInfos).map(Tag::name).toArray(String[]::new),
         nameListResponse.getNames());

Reply via email to