diff --git a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java index 4e1c339d1fe9..a2fdadb61a7f 100644 --- a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java +++ b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java @@ -447,7 +447,7 @@ public Table loadTable(SessionContext context, TableIdentifier identifier) { tableClient, paths.table(finalIdentifier), Map::of, - tableFileIO(context, tableConf, response.credentials()), + tableFileIO(context, identifier, tableConf, response.credentials()), tableMetadata, endpoints); @@ -992,6 +992,38 @@ private FileIO newFileIO( } } + private FileIO tableFileIO( + SessionContext context, + TableIdentifier identifier, + Map config, + List storageCredentials) { + // Check if either credential refresh is enabled from either client side or server side. + // TODO: convert this to constants. + boolean s3RefreshEnabled = + PropertyUtil.propertyAsBoolean(config, "client.refresh-credentials-enabled", false) + || PropertyUtil.propertyAsBoolean( + properties(), "client.refresh-credentials-enabled", false); + boolean adlsRefreshEnabled = + PropertyUtil.propertyAsBoolean(config, "adls.refresh-credentials-enabled", false) + || PropertyUtil.propertyAsBoolean( + properties(), "adls.refresh-credentials-enabled", false); + + // Inject the credentials refresh endpoint if, refresh is configured. + // This is done because the server would not know the complete URI of the refresh endpoint. + // The IRC relative path for refreshing the credentials for a table is fixed. + if (s3RefreshEnabled && endpoints.contains(Endpoint.V1_TABLE_CREDENTIALS)) { + // respect server-side refresh endpoint configuration. + config.putIfAbsent("client.refresh-credentials-endpoint", paths.tableCredentials(identifier)); + } else if (adlsRefreshEnabled && endpoints.contains(Endpoint.V1_TABLE_CREDENTIALS)) { + // respect server-side refresh endpoint configuration. + config.putIfAbsent("adls.refresh-credentials-endpoint", paths.tableCredentials(identifier)); + } + + // FileIO will use the credential provider which will use the refresh endpoint when + // the vended credentials from load table are close to expiration. + return tableFileIO(context, config, storageCredentials); + } + private FileIO tableFileIO( SessionContext context, Map config, List storageCredentials) { if (config.isEmpty() && ioBuilder == null && storageCredentials.isEmpty()) { diff --git a/core/src/main/java/org/apache/iceberg/rest/ResourcePaths.java b/core/src/main/java/org/apache/iceberg/rest/ResourcePaths.java index d5c11f6052f1..1d57b2cc483f 100644 --- a/core/src/main/java/org/apache/iceberg/rest/ResourcePaths.java +++ b/core/src/main/java/org/apache/iceberg/rest/ResourcePaths.java @@ -90,6 +90,17 @@ public String table(TableIdentifier ident) { RESTUtil.encodeString(ident.name())); } + public String tableCredentials(TableIdentifier ident) { + return SLASH.join( + "v1", + prefix, + "namespaces", + RESTUtil.encodeNamespace(ident.namespace()), + "tables", + RESTUtil.encodeString(ident.name()), + "credentials"); + } + public String register(Namespace ns) { return SLASH.join("v1", prefix, "namespaces", RESTUtil.encodeNamespace(ns), "register"); }