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

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


The following commit(s) were added to refs/heads/main by this push:
     new 9957e2477 Extract IcebergCatalog.getAccessConfig to a separate class 
AccessConfigProvider (#2736)
9957e2477 is described below

commit 9957e24779f9cd7a731fb75cd87c637ff1f1de81
Author: Honah (Jonas) J. <[email protected]>
AuthorDate: Wed Oct 8 17:26:46 2025 -0500

    Extract IcebergCatalog.getAccessConfig to a separate class 
AccessConfigProvider (#2736)
    
    This PR extracts credential vending entrypoint getAccessConfig from 
IcebergCatalog into a new centralized AccessConfigProvider class, decoupling 
credential generation from catalog implementations.
    
    The old SupportsCredentialVending is removed in this PR upon discussion
---
 .../service/catalog/common/CatalogUtils.java       |  48 ++++++++++
 .../service/catalog/iceberg/IcebergCatalog.java    |  55 +----------
 .../catalog/iceberg/IcebergCatalogAdapter.java     |   9 +-
 .../catalog/iceberg/IcebergCatalogHandler.java     |  27 ++++--
 .../iceberg/SupportsCredentialDelegation.java      |  41 --------
 .../service/catalog/io/AccessConfigProvider.java   | 104 +++++++++++++++++++++
 .../catalog/PolarisCallContextCatalogFactory.java  |   5 -
 .../service/admin/PolarisAuthzTestBase.java        |   4 +-
 .../AbstractPolarisGenericTableCatalogTest.java    |   1 -
 .../iceberg/AbstractIcebergCatalogTest.java        |   1 -
 .../iceberg/AbstractIcebergCatalogViewTest.java    |   1 -
 .../iceberg/IcebergCatalogHandlerAuthzTest.java    |  13 ++-
 ...ebergCatalogHandlerFineGrainedDisabledTest.java |   3 +-
 .../service/catalog/io/FileIOFactoryTest.java      |   1 -
 .../catalog/policy/AbstractPolicyCatalogTest.java  |   1 -
 .../org/apache/polaris/service/TestServices.java   |  14 ++-
 16 files changed, 204 insertions(+), 124 deletions(-)

diff --git 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogUtils.java
 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogUtils.java
new file mode 100644
index 000000000..6c0d8d82a
--- /dev/null
+++ 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogUtils.java
@@ -0,0 +1,48 @@
+/*
+ * 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.polaris.service.catalog.common;
+
+import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.polaris.core.entity.PolarisEntitySubType;
+import org.apache.polaris.core.entity.PolarisEntityType;
+import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
+import 
org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCatalogView;
+
+/** Utility methods for working with Polaris catalog entities. */
+public class CatalogUtils {
+
+  /**
+   * Find the resolved entity path that may contain storage information
+   *
+   * @param resolvedEntityView The resolved entity view containing catalog 
entities.
+   * @param tableIdentifier The table identifier for which to find storage 
information.
+   * @return The resolved path wrapper that may contain storage information.
+   */
+  public static PolarisResolvedPathWrapper findResolvedStorageEntity(
+      PolarisResolutionManifestCatalogView resolvedEntityView, TableIdentifier 
tableIdentifier) {
+    PolarisResolvedPathWrapper resolvedTableEntities =
+        resolvedEntityView.getResolvedPath(
+            tableIdentifier, PolarisEntityType.TABLE_LIKE, 
PolarisEntitySubType.ICEBERG_TABLE);
+    if (resolvedTableEntities != null) {
+      return resolvedTableEntities;
+    }
+    return resolvedEntityView.getResolvedPath(tableIdentifier.namespace());
+  }
+}
diff --git 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java
 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java
index 0399b0d37..10ac47b43 100644
--- 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java
+++ 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java
@@ -121,14 +121,12 @@ import 
org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCat
 import org.apache.polaris.core.persistence.resolver.ResolverFactory;
 import org.apache.polaris.core.persistence.resolver.ResolverPath;
 import org.apache.polaris.core.persistence.resolver.ResolverStatus;
-import org.apache.polaris.core.storage.AccessConfig;
-import org.apache.polaris.core.storage.PolarisCredentialVendor;
 import org.apache.polaris.core.storage.PolarisStorageActions;
 import org.apache.polaris.core.storage.PolarisStorageConfigurationInfo;
 import org.apache.polaris.core.storage.StorageLocation;
 import org.apache.polaris.core.storage.StorageUtil;
-import org.apache.polaris.core.storage.cache.StorageCredentialCache;
 import org.apache.polaris.service.catalog.SupportsNotifications;
+import org.apache.polaris.service.catalog.common.CatalogUtils;
 import org.apache.polaris.service.catalog.common.LocationUtils;
 import org.apache.polaris.service.catalog.io.FileIOFactory;
 import org.apache.polaris.service.catalog.io.FileIOUtil;
@@ -143,7 +141,7 @@ import org.slf4j.LoggerFactory;
 
 /** Defines the relationship between PolarisEntities and Iceberg's business 
logic. */
 public class IcebergCatalog extends BaseMetastoreViewCatalog
-    implements SupportsNamespaces, SupportsNotifications, Closeable, 
SupportsCredentialDelegation {
+    implements SupportsNamespaces, SupportsNotifications, Closeable {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(IcebergCatalog.class);
 
   private static final Joiner SLASH = Joiner.on("/");
@@ -163,7 +161,6 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
       };
 
   private final PolarisDiagnostics diagnostics;
-  private final StorageCredentialCache storageCredentialCache;
   private final ResolverFactory resolverFactory;
   private final CallContext callContext;
   private final RealmConfig realmConfig;
@@ -194,7 +191,6 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
    */
   public IcebergCatalog(
       PolarisDiagnostics diagnostics,
-      StorageCredentialCache storageCredentialCache,
       ResolverFactory resolverFactory,
       PolarisMetaStoreManager metaStoreManager,
       CallContext callContext,
@@ -204,7 +200,6 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
       FileIOFactory fileIOFactory,
       PolarisEventListener polarisEventListener) {
     this.diagnostics = diagnostics;
-    this.storageCredentialCache = storageCredentialCache;
     this.resolverFactory = resolverFactory;
     this.callContext = callContext;
     this.realmConfig = callContext.getRealmConfig();
@@ -385,7 +380,9 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
       lastMetadata = null;
     }
 
-    Optional<PolarisEntity> storageInfoEntity = 
findStorageInfo(tableIdentifier);
+    Optional<PolarisEntity> storageInfoEntity =
+        FileIOUtil.findStorageInfoFromHierarchy(
+            CatalogUtils.findResolvedStorageEntity(resolvedEntityView, 
tableIdentifier));
 
     // The storageProperties we stash away in the Task should be the superset 
of the
     // internalProperties of the StorageInfoEntity to be able to use its 
StorageIntegration
@@ -831,31 +828,6 @@ public class IcebergCatalog extends 
BaseMetastoreViewCatalog
         PolarisEntitySubType.ICEBERG_TABLE, identifier, notificationRequest);
   }
 
-  @Override
-  public AccessConfig getAccessConfig(
-      TableIdentifier tableIdentifier,
-      TableMetadata tableMetadata,
-      Set<PolarisStorageActions> storageActions,
-      Optional<String> refreshCredentialsEndpoint) {
-    Optional<PolarisEntity> storageInfo = findStorageInfo(tableIdentifier);
-    if (storageInfo.isEmpty()) {
-      LOGGER
-          .atWarn()
-          .addKeyValue("tableIdentifier", tableIdentifier)
-          .log("Table entity has no storage configuration in its hierarchy");
-      return AccessConfig.builder().supportsCredentialVending(false).build();
-    }
-    return FileIOUtil.refreshAccessConfig(
-        callContext,
-        storageCredentialCache,
-        getCredentialVendor(),
-        tableIdentifier,
-        StorageUtil.getLocationsUsedByTable(tableMetadata),
-        storageActions,
-        storageInfo.get(),
-        refreshCredentialsEndpoint);
-  }
-
   private String buildPrefixedLocation(TableIdentifier tableIdentifier) {
     StringBuilder locationBuilder = new StringBuilder();
     locationBuilder.append(defaultBaseLocation);
@@ -961,19 +933,6 @@ public class IcebergCatalog extends 
BaseMetastoreViewCatalog
         tableIdentifier, applyReplaceNewLocationWithCatalogDefault(location));
   }
 
-  private @Nonnull Optional<PolarisEntity> findStorageInfo(TableIdentifier 
tableIdentifier) {
-    PolarisResolvedPathWrapper resolvedTableEntities =
-        resolvedEntityView.getResolvedPath(
-            tableIdentifier, PolarisEntityType.TABLE_LIKE, 
PolarisEntitySubType.ICEBERG_TABLE);
-
-    PolarisResolvedPathWrapper resolvedStorageEntity =
-        resolvedTableEntities == null
-            ? resolvedEntityView.getResolvedPath(tableIdentifier.namespace())
-            : resolvedTableEntities;
-
-    return FileIOUtil.findStorageInfoFromHierarchy(resolvedStorageEntity);
-  }
-
   /**
    * Validates that the specified {@code location} is valid for whatever 
storage config is found for
    * this TableLike's parent hierarchy.
@@ -2130,10 +2089,6 @@ public class IcebergCatalog extends 
BaseMetastoreViewCatalog
     return metaStoreManager;
   }
 
-  private PolarisCredentialVendor getCredentialVendor() {
-    return metaStoreManager;
-  }
-
   @VisibleForTesting
   public void setFileIOFactory(FileIOFactory newFactory) {
     this.fileIOFactory = newFactory;
diff --git 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
index a21d2883e..0f622cb0b 100644
--- 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
+++ 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
@@ -83,6 +83,7 @@ import org.apache.polaris.service.catalog.CatalogPrefixParser;
 import org.apache.polaris.service.catalog.api.IcebergRestCatalogApiService;
 import 
org.apache.polaris.service.catalog.api.IcebergRestConfigurationApiService;
 import org.apache.polaris.service.catalog.common.CatalogAdapter;
+import org.apache.polaris.service.catalog.io.AccessConfigProvider;
 import org.apache.polaris.service.config.ReservedProperties;
 import org.apache.polaris.service.context.catalog.CallContextCatalogFactory;
 import org.apache.polaris.service.events.listeners.PolarisEventListener;
@@ -156,6 +157,7 @@ public class IcebergCatalogAdapter
   private final CatalogHandlerUtils catalogHandlerUtils;
   private final Instance<ExternalCatalogFactory> externalCatalogFactories;
   private final PolarisEventListener polarisEventListener;
+  private final AccessConfigProvider accessConfigProvider;
 
   @Inject
   public IcebergCatalogAdapter(
@@ -173,7 +175,8 @@ public class IcebergCatalogAdapter
       ReservedProperties reservedProperties,
       CatalogHandlerUtils catalogHandlerUtils,
       @Any Instance<ExternalCatalogFactory> externalCatalogFactories,
-      PolarisEventListener polarisEventListener) {
+      PolarisEventListener polarisEventListener,
+      AccessConfigProvider accessConfigProvider) {
     this.diagnostics = diagnostics;
     this.realmContext = realmContext;
     this.callContext = callContext;
@@ -190,6 +193,7 @@ public class IcebergCatalogAdapter
     this.catalogHandlerUtils = catalogHandlerUtils;
     this.externalCatalogFactories = externalCatalogFactories;
     this.polarisEventListener = polarisEventListener;
+    this.accessConfigProvider = accessConfigProvider;
   }
 
   /**
@@ -230,7 +234,8 @@ public class IcebergCatalogAdapter
         reservedProperties,
         catalogHandlerUtils,
         externalCatalogFactories,
-        polarisEventListener);
+        polarisEventListener,
+        accessConfigProvider);
   }
 
   @Override
diff --git 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
index 07e265c01..280c98d46 100644
--- 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
+++ 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
@@ -101,9 +101,12 @@ import 
org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
 import org.apache.polaris.core.secrets.UserSecretsManager;
 import org.apache.polaris.core.storage.AccessConfig;
 import org.apache.polaris.core.storage.PolarisStorageActions;
+import org.apache.polaris.core.storage.StorageUtil;
 import org.apache.polaris.service.catalog.AccessDelegationMode;
 import org.apache.polaris.service.catalog.SupportsNotifications;
 import org.apache.polaris.service.catalog.common.CatalogHandler;
+import org.apache.polaris.service.catalog.common.CatalogUtils;
+import org.apache.polaris.service.catalog.io.AccessConfigProvider;
 import org.apache.polaris.service.config.ReservedProperties;
 import org.apache.polaris.service.context.catalog.CallContextCatalogFactory;
 import org.apache.polaris.service.events.listeners.PolarisEventListener;
@@ -136,6 +139,7 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
   private final ReservedProperties reservedProperties;
   private final CatalogHandlerUtils catalogHandlerUtils;
   private final PolarisEventListener polarisEventListener;
+  private final AccessConfigProvider accessConfigProvider;
 
   // Catalog instance will be initialized after authorizing resolver 
successfully resolves
   // the catalog entity.
@@ -160,7 +164,8 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
       ReservedProperties reservedProperties,
       CatalogHandlerUtils catalogHandlerUtils,
       Instance<ExternalCatalogFactory> externalCatalogFactories,
-      PolarisEventListener polarisEventListener) {
+      PolarisEventListener polarisEventListener,
+      AccessConfigProvider accessConfigProvider) {
     super(
         diagnostics,
         callContext,
@@ -176,6 +181,7 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
     this.reservedProperties = reservedProperties;
     this.catalogHandlerUtils = catalogHandlerUtils;
     this.polarisEventListener = polarisEventListener;
+    this.accessConfigProvider = accessConfigProvider;
   }
 
   private CatalogEntity getResolvedCatalogEntity() {
@@ -799,16 +805,19 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
       Optional<String> refreshCredentialsEndpoint) {
     LoadTableResponse.Builder responseBuilder =
         LoadTableResponse.builder().withTableMetadata(tableMetadata);
+    PolarisResolvedPathWrapper resolvedStoragePath =
+        CatalogUtils.findResolvedStorageEntity(resolutionManifest, 
tableIdentifier);
+
+    if (baseCatalog instanceof IcebergCatalog && resolvedStoragePath != null) {
 
-    if (baseCatalog instanceof SupportsCredentialDelegation 
credentialDelegation) {
-      LOGGER
-          .atDebug()
-          .addKeyValue("tableIdentifier", tableIdentifier)
-          .addKeyValue("tableLocation", tableMetadata.location())
-          .log("Fetching client credentials for table");
       AccessConfig accessConfig =
-          credentialDelegation.getAccessConfig(
-              tableIdentifier, tableMetadata, actions, 
refreshCredentialsEndpoint);
+          accessConfigProvider.getAccessConfig(
+              callContext,
+              tableIdentifier,
+              StorageUtil.getLocationsUsedByTable(tableMetadata),
+              actions,
+              refreshCredentialsEndpoint,
+              resolvedStoragePath);
       Map<String, String> credentialConfig = accessConfig.credentials();
       if (delegationModes.contains(VENDED_CREDENTIALS)) {
         if (!credentialConfig.isEmpty()) {
diff --git 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/SupportsCredentialDelegation.java
 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/SupportsCredentialDelegation.java
deleted file mode 100644
index b85973ed8..000000000
--- 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/SupportsCredentialDelegation.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.polaris.service.catalog.iceberg;
-
-import java.util.Optional;
-import java.util.Set;
-import org.apache.iceberg.TableMetadata;
-import org.apache.iceberg.catalog.TableIdentifier;
-import org.apache.polaris.core.storage.AccessConfig;
-import org.apache.polaris.core.storage.PolarisStorageActions;
-
-/**
- * Adds support for credential vending for (typically) {@link 
org.apache.iceberg.TableOperations} to
- * fetch access credentials that are inserted into the {@link
- * org.apache.iceberg.rest.responses.LoadTableResponse#config()} property. See 
the
- * rest-catalog-open-api.yaml spec for details on the expected format of 
vended credential
- * configuration.
- */
-public interface SupportsCredentialDelegation {
-  AccessConfig getAccessConfig(
-      TableIdentifier tableIdentifier,
-      TableMetadata tableMetadata,
-      Set<PolarisStorageActions> storageActions,
-      Optional<String> refreshCredentialsEndpoint);
-}
diff --git 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/io/AccessConfigProvider.java
 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/io/AccessConfigProvider.java
new file mode 100644
index 000000000..d33604027
--- /dev/null
+++ 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/io/AccessConfigProvider.java
@@ -0,0 +1,104 @@
+/*
+ * 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.polaris.service.catalog.io;
+
+import jakarta.annotation.Nonnull;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import java.util.Optional;
+import java.util.Set;
+import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.polaris.core.context.CallContext;
+import org.apache.polaris.core.entity.PolarisEntity;
+import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
+import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
+import org.apache.polaris.core.storage.AccessConfig;
+import org.apache.polaris.core.storage.PolarisStorageActions;
+import org.apache.polaris.core.storage.cache.StorageCredentialCache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides temporary, scoped credentials for accessing table data in object 
storage (S3, GCS, Azure
+ * Blob Storage).
+ *
+ * <p>This provider decouples credential vending from catalog implementations, 
and should be the
+ * primary entrypoint to get sub-scoped credentials for accessing table data.
+ */
+@ApplicationScoped
+public class AccessConfigProvider {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(AccessConfigProvider.class);
+
+  private final StorageCredentialCache storageCredentialCache;
+  private final MetaStoreManagerFactory metaStoreManagerFactory;
+
+  @Inject
+  public AccessConfigProvider(
+      StorageCredentialCache storageCredentialCache,
+      MetaStoreManagerFactory metaStoreManagerFactory) {
+    this.storageCredentialCache = storageCredentialCache;
+    this.metaStoreManagerFactory = metaStoreManagerFactory;
+  }
+
+  /**
+   * Vends credentials for accessing table storage at explicit locations.
+   *
+   * @param callContext the call context containing realm, principal, and 
security context
+   * @param tableIdentifier the table identifier, used for logging and refresh 
endpoint construction
+   * @param tableLocations set of storage location URIs to scope credentials to
+   * @param storageActions the storage operations (READ, WRITE, LIST, DELETE) 
to scope credentials
+   *     to
+   * @param refreshCredentialsEndpoint optional endpoint URL for clients to 
refresh credentials
+   * @param resolvedPath the entity hierarchy to search for storage 
configuration
+   * @return {@link AccessConfig} with scoped credentials and metadata; empty 
if no storage config
+   *     found
+   */
+  public AccessConfig getAccessConfig(
+      @Nonnull CallContext callContext,
+      @Nonnull TableIdentifier tableIdentifier,
+      @Nonnull Set<String> tableLocations,
+      @Nonnull Set<PolarisStorageActions> storageActions,
+      @Nonnull Optional<String> refreshCredentialsEndpoint,
+      @Nonnull PolarisResolvedPathWrapper resolvedPath) {
+    LOGGER
+        .atDebug()
+        .addKeyValue("tableIdentifier", tableIdentifier)
+        .addKeyValue("tableLocation", tableLocations)
+        .log("Fetching client credentials for table");
+    Optional<PolarisEntity> storageInfo = 
FileIOUtil.findStorageInfoFromHierarchy(resolvedPath);
+    if (storageInfo.isEmpty()) {
+      LOGGER
+          .atWarn()
+          .addKeyValue("tableIdentifier", tableIdentifier)
+          .log("Table entity has no storage configuration in its hierarchy");
+      return AccessConfig.builder().supportsCredentialVending(false).build();
+    }
+    return FileIOUtil.refreshAccessConfig(
+        callContext,
+        storageCredentialCache,
+        
metaStoreManagerFactory.getOrCreateMetaStoreManager(callContext.getRealmContext()),
+        tableIdentifier,
+        tableLocations,
+        storageActions,
+        storageInfo.get(),
+        refreshCredentialsEndpoint);
+  }
+}
diff --git 
a/runtime/service/src/main/java/org/apache/polaris/service/context/catalog/PolarisCallContextCatalogFactory.java
 
b/runtime/service/src/main/java/org/apache/polaris/service/context/catalog/PolarisCallContextCatalogFactory.java
index 342d7d774..c9dcbefae 100644
--- 
a/runtime/service/src/main/java/org/apache/polaris/service/context/catalog/PolarisCallContextCatalogFactory.java
+++ 
b/runtime/service/src/main/java/org/apache/polaris/service/context/catalog/PolarisCallContextCatalogFactory.java
@@ -32,7 +32,6 @@ import org.apache.polaris.core.entity.CatalogEntity;
 import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
 import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
 import org.apache.polaris.core.persistence.resolver.ResolverFactory;
-import org.apache.polaris.core.storage.cache.StorageCredentialCache;
 import org.apache.polaris.service.catalog.iceberg.IcebergCatalog;
 import org.apache.polaris.service.catalog.io.FileIOFactory;
 import org.apache.polaris.service.events.listeners.PolarisEventListener;
@@ -48,7 +47,6 @@ public class PolarisCallContextCatalogFactory implements 
CallContextCatalogFacto
   private final PolarisDiagnostics diagnostics;
   private final TaskExecutor taskExecutor;
   private final FileIOFactory fileIOFactory;
-  private final StorageCredentialCache storageCredentialCache;
   private final ResolverFactory resolverFactory;
   private final MetaStoreManagerFactory metaStoreManagerFactory;
   private final PolarisEventListener polarisEventListener;
@@ -56,14 +54,12 @@ public class PolarisCallContextCatalogFactory implements 
CallContextCatalogFacto
   @Inject
   public PolarisCallContextCatalogFactory(
       PolarisDiagnostics diagnostics,
-      StorageCredentialCache storageCredentialCache,
       ResolverFactory resolverFactory,
       MetaStoreManagerFactory metaStoreManagerFactory,
       TaskExecutor taskExecutor,
       FileIOFactory fileIOFactory,
       PolarisEventListener polarisEventListener) {
     this.diagnostics = diagnostics;
-    this.storageCredentialCache = storageCredentialCache;
     this.resolverFactory = resolverFactory;
     this.metaStoreManagerFactory = metaStoreManagerFactory;
     this.taskExecutor = taskExecutor;
@@ -87,7 +83,6 @@ public class PolarisCallContextCatalogFactory implements 
CallContextCatalogFacto
     IcebergCatalog catalogInstance =
         new IcebergCatalog(
             diagnostics,
-            storageCredentialCache,
             resolverFactory,
             
metaStoreManagerFactory.getOrCreateMetaStoreManager(context.getRealmContext()),
             context,
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAuthzTestBase.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAuthzTestBase.java
index 875c2262a..6db99fb34 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAuthzTestBase.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAuthzTestBase.java
@@ -91,6 +91,7 @@ import org.apache.polaris.service.catalog.Profiles;
 import org.apache.polaris.service.catalog.generic.PolarisGenericTableCatalog;
 import org.apache.polaris.service.catalog.iceberg.CatalogHandlerUtils;
 import org.apache.polaris.service.catalog.iceberg.IcebergCatalog;
+import org.apache.polaris.service.catalog.io.AccessConfigProvider;
 import org.apache.polaris.service.catalog.io.FileIOFactory;
 import org.apache.polaris.service.catalog.policy.PolicyCatalog;
 import org.apache.polaris.service.config.ReservedProperties;
@@ -206,6 +207,7 @@ public abstract class PolarisAuthzTestBase {
   @Inject protected PolarisConfigurationStore configurationStore;
   @Inject protected StorageCredentialCache storageCredentialCache;
   @Inject protected ResolverFactory resolverFactory;
+  @Inject protected AccessConfigProvider accessConfigProvider;
 
   protected IcebergCatalog baseCatalog;
   protected PolarisGenericTableCatalog genericTableCatalog;
@@ -529,7 +531,6 @@ public abstract class PolarisAuthzTestBase {
     this.baseCatalog =
         new IcebergCatalog(
             diagServices,
-            storageCredentialCache,
             resolverFactory,
             metaStoreManager,
             callContext,
@@ -569,7 +570,6 @@ public abstract class PolarisAuthzTestBase {
         PolarisEventListener polarisEventListener) {
       super(
           diagnostics,
-          storageCredentialCache,
           resolverFactory,
           metaStoreManagerFactory,
           taskExecutor,
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/AbstractPolarisGenericTableCatalogTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/AbstractPolarisGenericTableCatalogTest.java
index 1d1071dfe..af2efded5 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/AbstractPolarisGenericTableCatalogTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/AbstractPolarisGenericTableCatalogTest.java
@@ -239,7 +239,6 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     this.icebergCatalog =
         new IcebergCatalog(
             diagServices,
-            storageCredentialCache,
             resolverFactory,
             metaStoreManager,
             polarisContext,
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogTest.java
index 2418bcfcc..369a67252 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogTest.java
@@ -448,7 +448,6 @@ public abstract class AbstractIcebergCatalogTest extends 
CatalogTests<IcebergCat
     TaskExecutor taskExecutor = Mockito.mock(TaskExecutor.class);
     return new IcebergCatalog(
         diagServices,
-        storageCredentialCache,
         resolverFactory,
         metaStoreManager,
         polarisContext,
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogViewTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogViewTest.java
index c4b68658a..97c31cdb5 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogViewTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogViewTest.java
@@ -215,7 +215,6 @@ public abstract class AbstractIcebergCatalogViewTest 
extends ViewCatalogTests<Ic
     this.catalog =
         new IcebergCatalog(
             diagServices,
-            storageCredentialCache,
             resolverFactory,
             metaStoreManager,
             polarisContext,
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerAuthzTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerAuthzTest.java
index d930bf1ba..5148bf0ef 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerAuthzTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerAuthzTest.java
@@ -135,7 +135,8 @@ public class IcebergCatalogHandlerAuthzTest extends 
PolarisAuthzTestBase {
         reservedProperties,
         catalogHandlerUtils,
         emptyExternalCatalogFactory(),
-        polarisEventListener);
+        polarisEventListener,
+        accessConfigProvider);
   }
 
   protected void doTestInsufficientPrivileges(
@@ -275,7 +276,8 @@ public class IcebergCatalogHandlerAuthzTest extends 
PolarisAuthzTestBase {
             reservedProperties,
             catalogHandlerUtils,
             emptyExternalCatalogFactory(),
-            polarisEventListener);
+            polarisEventListener,
+            accessConfigProvider);
 
     // a variety of actions are all disallowed because the principal's 
credentials must be rotated
     doTestInsufficientPrivileges(
@@ -313,7 +315,8 @@ public class IcebergCatalogHandlerAuthzTest extends 
PolarisAuthzTestBase {
             reservedProperties,
             catalogHandlerUtils,
             emptyExternalCatalogFactory(),
-            polarisEventListener);
+            polarisEventListener,
+            accessConfigProvider);
 
     doTestSufficientPrivilegeSets(
         List.of(Set.of(PolarisPrivilege.NAMESPACE_LIST)),
@@ -1193,7 +1196,8 @@ public class IcebergCatalogHandlerAuthzTest extends 
PolarisAuthzTestBase {
         reservedProperties,
         catalogHandlerUtils,
         emptyExternalCatalogFactory(),
-        polarisEventListener);
+        polarisEventListener,
+        accessConfigProvider);
   }
 
   @Test
@@ -1896,7 +1900,6 @@ public class IcebergCatalogHandlerAuthzTest extends 
PolarisAuthzTestBase {
     PolarisCallContextCatalogFactory factory =
         new PolarisCallContextCatalogFactory(
             diagServices,
-            storageCredentialCache,
             resolverFactory,
             managerFactory,
             Mockito.mock(),
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFineGrainedDisabledTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFineGrainedDisabledTest.java
index 55ab5ad88..367f9e6d7 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFineGrainedDisabledTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFineGrainedDisabledTest.java
@@ -71,7 +71,8 @@ public class IcebergCatalogHandlerFineGrainedDisabledTest 
extends PolarisAuthzTe
         reservedProperties,
         catalogHandlerUtils,
         emptyExternalCatalogFactory(),
-        polarisEventListener);
+        polarisEventListener,
+        accessConfigProvider);
   }
 
   public static class Profile extends PolarisAuthzTestBase.Profile {
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/io/FileIOFactoryTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/io/FileIOFactoryTest.java
index d966aeae6..d36e9a74f 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/io/FileIOFactoryTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/io/FileIOFactoryTest.java
@@ -222,7 +222,6 @@ public class FileIOFactoryTest {
     IcebergCatalog polarisCatalog =
         new IcebergCatalog(
             services.polarisDiagnostics(),
-            services.storageCredentialCache(),
             services.resolverFactory(),
             services.metaStoreManager(),
             callContext,
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/AbstractPolicyCatalogTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/AbstractPolicyCatalogTest.java
index 9da8260eb..f430e2bff 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/AbstractPolicyCatalogTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/AbstractPolicyCatalogTest.java
@@ -256,7 +256,6 @@ public abstract class AbstractPolicyCatalogTest {
     this.icebergCatalog =
         new IcebergCatalog(
             diagServices,
-            storageCredentialCache,
             resolverFactory,
             metaStoreManager,
             polarisContext,
diff --git 
a/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
 
b/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
index ed3c138e0..a77057274 100644
--- 
a/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
+++ 
b/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
@@ -70,6 +70,7 @@ import 
org.apache.polaris.service.catalog.api.IcebergRestCatalogApi;
 import org.apache.polaris.service.catalog.api.IcebergRestConfigurationApi;
 import org.apache.polaris.service.catalog.iceberg.CatalogHandlerUtils;
 import org.apache.polaris.service.catalog.iceberg.IcebergCatalogAdapter;
+import org.apache.polaris.service.catalog.io.AccessConfigProvider;
 import org.apache.polaris.service.catalog.io.FileIOFactory;
 import org.apache.polaris.service.catalog.io.MeasuredFileIOFactory;
 import org.apache.polaris.service.config.ReservedProperties;
@@ -108,7 +109,8 @@ public record TestServices(
     PolarisMetaStoreManager metaStoreManager,
     FileIOFactory fileIOFactory,
     TaskExecutor taskExecutor,
-    PolarisEventListener polarisEventListener) {
+    PolarisEventListener polarisEventListener,
+    AccessConfigProvider accessConfigProvider) {
 
   private static final RealmContext TEST_REALM = () -> "test-realm";
   private static final String GCP_ACCESS_TOKEN = "abc";
@@ -249,13 +251,15 @@ public record TestServices(
       CallContextCatalogFactory callContextFactory =
           new PolarisCallContextCatalogFactory(
               diagnostics,
-              storageCredentialCache,
               resolverFactory,
               metaStoreManagerFactory,
               taskExecutor,
               fileIOFactory,
               polarisEventListener);
 
+      AccessConfigProvider accessConfigProvider =
+          new AccessConfigProvider(storageCredentialCache, 
metaStoreManagerFactory);
+
       ReservedProperties reservedProperties = ReservedProperties.NONE;
 
       CatalogHandlerUtils catalogHandlerUtils = new 
CatalogHandlerUtils(realmConfig);
@@ -281,7 +285,8 @@ public record TestServices(
               reservedProperties,
               catalogHandlerUtils,
               externalCatalogFactory,
-              polarisEventListener);
+              polarisEventListener,
+              accessConfigProvider);
 
       IcebergRestCatalogApi restApi = new 
IcebergRestCatalogApi(catalogService);
       IcebergRestConfigurationApi restConfigurationApi =
@@ -354,7 +359,8 @@ public record TestServices(
           metaStoreManager,
           fileIOFactory,
           taskExecutor,
-          polarisEventListener);
+          polarisEventListener,
+          accessConfigProvider);
     }
   }
 


Reply via email to