You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by yz...@apache.org on 2026/04/03 00:42:56 UTC

(polaris) branch yzou-generic-table-credential-vending updated: Parse access delegation mode in GenericTable load and create like Iceberg

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

yzou pushed a commit to branch yzou-generic-table-credential-vending
in repository https://gitbox.apache.org/repos/asf/polaris.git


The following commit(s) were added to refs/heads/yzou-generic-table-credential-vending by this push:
     new ab0f1bf264 Parse access delegation mode in GenericTable load and create like Iceberg
ab0f1bf264 is described below

commit ab0f1bf264cb41ce18062546c0421bd30767ebe0
Author: Yun Zou <yu...@gmail.com>
AuthorDate: Thu Apr 2 17:42:51 2026 -0700

    Parse access delegation mode in GenericTable load and create like Iceberg
    
    Made-with: Cursor
---
 .../generic/GenericTableCatalogAdapter.java        | 24 ++++++++++++++++--
 .../generic/GenericTableCatalogHandler.java        | 29 ++++++++++++++--------
 ...PolarisGenericTableCatalogHandlerAuthzTest.java | 23 ++++++++++++++---
 3 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
index 72a48e3054..c45844a77b 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
@@ -18,18 +18,22 @@
  */
 package org.apache.polaris.service.catalog.generic;
 
+import static org.apache.polaris.service.catalog.AccessDelegationMode.VENDED_CREDENTIALS;
 import static org.apache.polaris.service.catalog.common.CatalogUtils.decodeNamespace;
 
+import com.google.common.base.Preconditions;
 import jakarta.enterprise.context.RequestScoped;
 import jakarta.inject.Inject;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.SecurityContext;
+import java.util.EnumSet;
 import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.polaris.core.auth.PolarisPrincipal;
 import org.apache.polaris.core.config.FeatureConfiguration;
 import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.context.CallContext;
 import org.apache.polaris.core.context.RealmContext;
+import org.apache.polaris.service.catalog.AccessDelegationMode;
 import org.apache.polaris.service.catalog.CatalogPrefixParser;
 import org.apache.polaris.service.catalog.api.PolarisCatalogGenericTableApiService;
 import org.apache.polaris.service.catalog.common.CatalogAdapter;
@@ -67,6 +71,16 @@ public class GenericTableCatalogAdapter
     return handlerFactory.createHandler(catalogName, principal);
   }
 
+  private EnumSet<AccessDelegationMode> parseAccessDelegationModes(String accessDelegationMode) {
+    EnumSet<AccessDelegationMode> delegationModes =
+        AccessDelegationMode.fromProtocolValuesList(accessDelegationMode);
+    Preconditions.checkArgument(
+        delegationModes.isEmpty() || delegationModes.contains(VENDED_CREDENTIALS),
+        "Unsupported access delegation mode: %s",
+        accessDelegationMode);
+    return delegationModes;
+  }
+
   @Override
   public Response createGenericTable(
       String prefix,
@@ -75,6 +89,8 @@ public class GenericTableCatalogAdapter
       String polarisGenericTableAccessDelegation,
       RealmContext realmContext,
       SecurityContext securityContext) {
+    EnumSet<AccessDelegationMode> delegationModes =
+        parseAccessDelegationModes(polarisGenericTableAccessDelegation);
     GenericTableCatalogHandler handler = newHandler(securityContext, prefix);
     LoadGenericTableResponse response =
         handler.createGenericTable(
@@ -82,7 +98,8 @@ public class GenericTableCatalogAdapter
             createGenericTableRequest.getFormat(),
             createGenericTableRequest.getBaseLocation(),
             createGenericTableRequest.getDoc(),
-            reservedProperties.removeReservedProperties(createGenericTableRequest.getProperties()));
+            reservedProperties.removeReservedProperties(createGenericTableRequest.getProperties()),
+            delegationModes);
 
     return Response.ok(response).build();
   }
@@ -120,9 +137,12 @@ public class GenericTableCatalogAdapter
       String polarisGenericTableAccessDelegation,
       RealmContext realmContext,
       SecurityContext securityContext) {
+    EnumSet<AccessDelegationMode> delegationModes =
+        parseAccessDelegationModes(polarisGenericTableAccessDelegation);
     GenericTableCatalogHandler handler = newHandler(securityContext, prefix);
     LoadGenericTableResponse response =
-        handler.loadGenericTable(TableIdentifier.of(decodeNamespace(namespace), genericTable));
+        handler.loadGenericTable(
+            TableIdentifier.of(decodeNamespace(namespace), genericTable), delegationModes);
     return Response.ok(response).build();
   }
 }
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
index 4794642e3e..28a85d7090 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
@@ -18,8 +18,11 @@
  */
 package org.apache.polaris.service.catalog.generic;
 
+import static org.apache.polaris.service.catalog.AccessDelegationMode.VENDED_CREDENTIALS;
+
 import io.smallrye.common.annotation.Identifier;
 import jakarta.enterprise.inject.Instance;
+import java.util.EnumSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -40,6 +43,7 @@ import org.apache.polaris.core.entity.table.GenericTableEntity;
 import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
 import org.apache.polaris.core.storage.PolarisStorageActions;
 import org.apache.polaris.immutables.PolarisImmutable;
+import org.apache.polaris.service.catalog.AccessDelegationMode;
 import org.apache.polaris.service.catalog.common.CatalogHandler;
 import org.apache.polaris.service.catalog.common.CatalogUtils;
 import org.apache.polaris.service.catalog.io.StorageAccessConfigProvider;
@@ -120,7 +124,8 @@ public abstract class GenericTableCatalogHandler extends CatalogHandler {
       String format,
       String baseLocation,
       String doc,
-      Map<String, String> properties) {
+      Map<String, String> properties,
+      EnumSet<AccessDelegationMode> delegationModes) {
     PolarisAuthorizableOperation op = PolarisAuthorizableOperation.CREATE_TABLE_DIRECT;
     authorizeCreateTableLikeUnderNamespaceOperationOrThrow(op, identifier);
 
@@ -137,7 +142,7 @@ public abstract class GenericTableCatalogHandler extends CatalogHandler {
             .build();
 
     List<StorageAccessConfig> storageAccessConfigs =
-        isCredentialVendingEnabled()
+        shouldVendCredentials(delegationModes)
             ? vendCredentials(
                 identifier,
                 createdEntity,
@@ -160,13 +165,14 @@ public abstract class GenericTableCatalogHandler extends CatalogHandler {
     return this.genericTableCatalog.dropGenericTable(identifier);
   }
 
-  public LoadGenericTableResponse loadGenericTable(TableIdentifier identifier) {
+  public LoadGenericTableResponse loadGenericTable(
+      TableIdentifier identifier, EnumSet<AccessDelegationMode> delegationModes) {
     ensureResolutionManifestForTable(identifier);
-    boolean credentialVendingEnabled = isCredentialVendingEnabled();
+    boolean credentialVendingRequested = shouldVendCredentials(delegationModes);
 
     Set<PolarisStorageActions> actionsRequested =
         authorizeLoadTableLike(
-            identifier, PolarisEntitySubType.GENERIC_TABLE, credentialVendingEnabled);
+            identifier, PolarisEntitySubType.GENERIC_TABLE, credentialVendingRequested);
 
     GenericTableEntity loadedEntity = this.genericTableCatalog.loadGenericTable(identifier);
     GenericTable loadedTable =
@@ -179,7 +185,7 @@ public abstract class GenericTableCatalogHandler extends CatalogHandler {
             .build();
 
     List<StorageAccessConfig> storageAccessConfigs =
-        credentialVendingEnabled
+        credentialVendingRequested
             ? vendCredentials(identifier, loadedEntity, actionsRequested)
             : List.of();
 
@@ -189,11 +195,12 @@ public abstract class GenericTableCatalogHandler extends CatalogHandler {
         .build();
   }
 
-  private boolean isCredentialVendingEnabled() {
-    return realmConfig()
-        .getConfig(
-            FeatureConfiguration.ENABLE_GENERIC_TABLES_CREDENTIAL_VENDING,
-            resolutionManifest.getResolvedCatalogEntity());
+  private boolean shouldVendCredentials(EnumSet<AccessDelegationMode> delegationModes) {
+    return delegationModes.contains(VENDED_CREDENTIALS)
+        && realmConfig()
+            .getConfig(
+                FeatureConfiguration.ENABLE_GENERIC_TABLES_CREDENTIAL_VENDING,
+                resolutionManifest.getResolvedCatalogEntity());
   }
 
   private List<StorageAccessConfig> vendCredentials(
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalogHandlerAuthzTest.java b/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalogHandlerAuthzTest.java
index 0dceebe8c2..dfaeec776d 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalogHandlerAuthzTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalogHandlerAuthzTest.java
@@ -21,6 +21,7 @@ package org.apache.polaris.service.catalog.generic;
 import io.quarkus.test.junit.QuarkusTest;
 import io.quarkus.test.junit.TestProfile;
 import jakarta.inject.Inject;
+import java.util.EnumSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Stream;
@@ -28,6 +29,7 @@ import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.polaris.core.auth.PolarisPrincipal;
 import org.apache.polaris.core.entity.PolarisPrivilege;
 import org.apache.polaris.service.admin.PolarisAuthzTestBase;
+import org.apache.polaris.service.catalog.AccessDelegationMode;
 import org.junit.jupiter.api.DynamicNode;
 import org.junit.jupiter.api.TestFactory;
 
@@ -84,7 +86,13 @@ public class PolarisGenericTableCatalogHandlerAuthzTest extends PolarisAuthzTest
         .action(
             () ->
                 newWrapper(Set.of(PRINCIPAL_ROLE1))
-                    .createGenericTable(newtable, "format", "file:///temp/", "doc", Map.of()))
+                    .createGenericTable(
+                        newtable,
+                        "format",
+                        "file:///temp/",
+                        "doc",
+                        Map.of(),
+                        EnumSet.noneOf(AccessDelegationMode.class)))
         .cleanupAction(() -> newWrapper(Set.of(PRINCIPAL_ROLE2)).dropGenericTable(newtable))
         .shouldPassWith(PolarisPrivilege.TABLE_CREATE)
         .shouldPassWith(PolarisPrivilege.TABLE_FULL_METADATA)
@@ -96,7 +104,11 @@ public class PolarisGenericTableCatalogHandlerAuthzTest extends PolarisAuthzTest
   @TestFactory
   Stream<DynamicNode> testLoadGenericTablePrivileges() {
     return authzTestsBuilder("loadGenericTable")
-        .action(() -> newWrapper().loadGenericTable(TABLE_NS1_1_GENERIC))
+        .action(
+            () ->
+                newWrapper()
+                    .loadGenericTable(
+                        TABLE_NS1_1_GENERIC, EnumSet.noneOf(AccessDelegationMode.class)))
         .shouldPassWith(PolarisPrivilege.TABLE_READ_PROPERTIES)
         .shouldPassWith(PolarisPrivilege.TABLE_WRITE_PROPERTIES)
         .shouldPassWith(PolarisPrivilege.TABLE_READ_DATA)
@@ -119,7 +131,12 @@ public class PolarisGenericTableCatalogHandlerAuthzTest extends PolarisAuthzTest
             () ->
                 newWrapper(Set.of(PRINCIPAL_ROLE2))
                     .createGenericTable(
-                        TABLE_NS1_1_GENERIC, "format", "file:///temp/", "doc", Map.of()))
+                        TABLE_NS1_1_GENERIC,
+                        "format",
+                        "file:///temp/",
+                        "doc",
+                        Map.of(),
+                        EnumSet.noneOf(AccessDelegationMode.class)))
         .shouldPassWith(PolarisPrivilege.TABLE_DROP)
         .shouldPassWith(PolarisPrivilege.TABLE_FULL_METADATA)
         .shouldPassWith(PolarisPrivilege.CATALOG_MANAGE_CONTENT)