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

emaynard 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 daf4476fe Support IMPLICIT authentication type for federated catalogs 
(#1925)
daf4476fe is described below

commit daf4476fedfd79ff8e858ec1664b550fa31583de
Author: Pooja Nilangekar <[email protected]>
AuthorDate: Mon Jul 7 20:53:10 2025 -0400

    Support IMPLICIT authentication type for federated catalogs (#1925)
    
    Previously, the ConnectionConfigInfo required explicit 
AuthenticationParameters for every federated catalog. However, certain catalogs 
types that Polaris federates to (either now or in the future) allow `IMPLICIT` 
authentication, wherein the authentication parameters are picked from the 
environment or configuration files. This change enables federating to such 
catalogs without passing dummy secrets.
    
    The `IMPLICIT` option is guarded by the 
`SUPPORTED_EXTERNAL_CATALOG_AUTHENTICATION_TYPES`. Hence users may create 
federated catalogs with `IMPLICIT` authentication only when the administrator 
explicitly enables this feature.
---
 CHANGELOG.md                                       |  4 ++
 .../connection/AuthenticationParametersDpo.java    |  4 ++
 .../core/connection/AuthenticationType.java        |  1 +
 .../ImplicitAuthenticationParametersDpo.java       | 55 +++++++++++++++
 .../connection/ConnectionConfigInfoDpoTest.java    | 38 ++++++++++
 .../polaris/service/admin/PolarisAdminService.java | 82 ++++++++++++++--------
 spec/polaris-management-service.yml                |  9 +++
 7 files changed, 165 insertions(+), 28 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9593d75e2..cbbe3ac44 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,10 @@ request adding CHANGELOG notes for breaking (!) changes and 
possibly other secti
 
 - Added Catalog configuration for S3 and STS endpoints. This also allows using 
non-AWS S3 implementations.
 
+- The `IMPLICIT` authentication type enables users to create federated 
catalogs without explicitly
+providing authentication parameters to Polaris. When the authentication type 
is set to `IMPLICIT`, 
+the authentication parameters are picked from the environment or configuration 
files. 
+
 ### Changes
 
 ### Deprecations
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationParametersDpo.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationParametersDpo.java
index f2267b12a..73523cadd 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationParametersDpo.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationParametersDpo.java
@@ -39,6 +39,7 @@ import org.apache.polaris.core.secrets.UserSecretReference;
 @JsonSubTypes({
   @JsonSubTypes.Type(value = OAuthClientCredentialsParametersDpo.class, name = 
"1"),
   @JsonSubTypes.Type(value = BearerAuthenticationParametersDpo.class, name = 
"2"),
+  @JsonSubTypes.Type(value = ImplicitAuthenticationParametersDpo.class, name = 
"3"),
 })
 public abstract class AuthenticationParametersDpo implements 
IcebergCatalogPropertiesProvider {
 
@@ -81,6 +82,9 @@ public abstract class AuthenticationParametersDpo implements 
IcebergCatalogPrope
             new BearerAuthenticationParametersDpo(
                 secretReferences.get(INLINE_BEARER_TOKEN_REFERENCE_KEY));
         break;
+      case IMPLICIT:
+        config = new ImplicitAuthenticationParametersDpo();
+        break;
       default:
         throw new IllegalStateException(
             "Unsupported authentication type: " + 
authenticationParameters.getAuthenticationType());
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationType.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationType.java
index 71ad0b72d..02e89c059 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationType.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationType.java
@@ -33,6 +33,7 @@ public enum AuthenticationType {
   NULL_TYPE(0),
   OAUTH(1),
   BEARER(2),
+  IMPLICIT(3),
   ;
 
   private static final AuthenticationType[] REVERSE_MAPPING_ARRAY;
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/connection/ImplicitAuthenticationParametersDpo.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/connection/ImplicitAuthenticationParametersDpo.java
new file mode 100644
index 000000000..dc19a789a
--- /dev/null
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/connection/ImplicitAuthenticationParametersDpo.java
@@ -0,0 +1,55 @@
+/*
+ * 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.core.connection;
+
+import com.google.common.base.MoreObjects;
+import java.util.Map;
+import org.apache.polaris.core.admin.model.AuthenticationParameters;
+import org.apache.polaris.core.admin.model.ImplicitAuthenticationParameters;
+import org.apache.polaris.core.secrets.UserSecretsManager;
+
+/**
+ * The internal persistence-object counterpart to 
ImplicitAuthenticationParameters defined in the
+ * API model.
+ */
+public class ImplicitAuthenticationParametersDpo extends 
AuthenticationParametersDpo {
+
+  public ImplicitAuthenticationParametersDpo() {
+    super(AuthenticationType.IMPLICIT.getCode());
+  }
+
+  @Override
+  public Map<String, String> asIcebergCatalogProperties(UserSecretsManager 
secretsManager) {
+    return Map.of();
+  }
+
+  @Override
+  public AuthenticationParameters asAuthenticationParametersModel() {
+    return ImplicitAuthenticationParameters.builder()
+        
.setAuthenticationType(AuthenticationParameters.AuthenticationTypeEnum.IMPLICIT)
+        .build();
+  }
+
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(this)
+        .add("authenticationTypeCode", getAuthenticationTypeCode())
+        .toString();
+  }
+}
diff --git 
a/polaris-core/src/test/java/org/apache/polaris/core/connection/ConnectionConfigInfoDpoTest.java
 
b/polaris-core/src/test/java/org/apache/polaris/core/connection/ConnectionConfigInfoDpoTest.java
index 3aeed0b05..f2b461358 100644
--- 
a/polaris-core/src/test/java/org/apache/polaris/core/connection/ConnectionConfigInfoDpoTest.java
+++ 
b/polaris-core/src/test/java/org/apache/polaris/core/connection/ConnectionConfigInfoDpoTest.java
@@ -131,4 +131,42 @@ public class ConnectionConfigInfoDpoTest {
         objectMapper.readValue(expectedApiModelJson, 
ConnectionConfigInfo.class),
         connectionConfigInfoApiModel);
   }
+
+  @Test
+  void testImplicitAuthenticationParameters() throws JsonProcessingException {
+    // Test deserialization and reserialization of the persistence JSON.
+    String json =
+        ""
+            + "{"
+            + "  \"connectionTypeCode\": 2,"
+            + "  \"uri\": \"file:///hadoop-catalog/warehouse\","
+            + "  \"warehouse\": \"hadoop-catalog\","
+            + "  \"authenticationParameters\": {"
+            + "    \"authenticationTypeCode\": 3"
+            + "  }"
+            + "}";
+    ConnectionConfigInfoDpo connectionConfigInfoDpo =
+        ConnectionConfigInfoDpo.deserialize(polarisDiagnostics, json);
+    Assertions.assertNotNull(connectionConfigInfoDpo);
+    JsonNode tree1 = objectMapper.readTree(json);
+    JsonNode tree2 = 
objectMapper.readTree(connectionConfigInfoDpo.serialize());
+    Assertions.assertEquals(tree1, tree2);
+
+    // Test conversion into API model JSON.
+    ConnectionConfigInfo connectionConfigInfoApiModel =
+        connectionConfigInfoDpo.asConnectionConfigInfoModel();
+    String expectedApiModelJson =
+        ""
+            + "{"
+            + "  \"connectionType\": \"HADOOP\","
+            + "  \"uri\": \"file:///hadoop-catalog/warehouse\","
+            + "  \"warehouse\": \"hadoop-catalog\","
+            + "  \"authenticationParameters\": {"
+            + "    \"authenticationType\": \"IMPLICIT\""
+            + "  }"
+            + "}";
+    Assertions.assertEquals(
+        objectMapper.readValue(expectedApiModelJson, 
ConnectionConfigInfo.class),
+        connectionConfigInfoApiModel);
+  }
 }
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
 
b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
index a023025cc..df046f6c4 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
@@ -19,6 +19,7 @@
 package org.apache.polaris.service.admin;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
 
 import jakarta.annotation.Nonnull;
 import jakarta.annotation.Nullable;
@@ -29,6 +30,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -699,16 +701,10 @@ public class PolarisAdminService {
   /**
    * @see #extractSecretReferences
    */
-  private boolean requiresSecretReferenceExtraction(CreateCatalogRequest 
catalogRequest) {
-    Catalog catalog = catalogRequest.getCatalog();
-    if (catalog instanceof ExternalCatalog externalCatalog) {
-      if (externalCatalog.getConnectionConfigInfo() != null) {
-        // TODO: Make this more targeted once we have connection configs that 
don't involve
-        // processing of inline secrets.
-        return true;
-      }
-    }
-    return false;
+  private boolean requiresSecretReferenceExtraction(
+      @NotNull ConnectionConfigInfo connectionConfigInfo) {
+    return 
connectionConfigInfo.getAuthenticationParameters().getAuthenticationType()
+        != AuthenticationParameters.AuthenticationTypeEnum.IMPLICIT;
   }
 
   public PolarisEntity createCatalog(CreateCatalogRequest catalogRequest) {
@@ -733,24 +729,54 @@ public class PolarisAdminService {
             
.setProperties(reservedProperties.removeReservedProperties(entity.getPropertiesAsMap()))
             .build();
 
-    if (requiresSecretReferenceExtraction(catalogRequest)) {
-      LOGGER
-          .atDebug()
-          .addKeyValue("catalogName", entity.getName())
-          .log("Extracting secret references to create federated catalog");
-      FeatureConfiguration.enforceFeatureEnabledOrThrow(
-          callContext, FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
-      // For fields that contain references to secrets, we'll separately 
process the secrets from
-      // the original request first, and then populate those fields with the 
extracted secret
-      // references as part of the construction of the internal persistence 
entity.
-      Map<String, UserSecretReference> processedSecretReferences =
-          extractSecretReferences(catalogRequest, entity);
-      entity =
-          new CatalogEntity.Builder(entity)
-              .setConnectionConfigInfoDpoWithSecrets(
-                  ((ExternalCatalog) 
catalogRequest.getCatalog()).getConnectionConfigInfo(),
-                  processedSecretReferences)
-              .build();
+    Catalog catalog = catalogRequest.getCatalog();
+    if (catalog instanceof ExternalCatalog externalCatalog) {
+      ConnectionConfigInfo connectionConfigInfo = 
externalCatalog.getConnectionConfigInfo();
+
+      if (connectionConfigInfo != null) {
+        LOGGER
+            .atDebug()
+            .addKeyValue("catalogName", entity.getName())
+            .log("Creating a federated catalog");
+        FeatureConfiguration.enforceFeatureEnabledOrThrow(
+            callContext, FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
+        Map<String, UserSecretReference> processedSecretReferences = Map.of();
+        List<String> supportedAuthenticationTypes =
+            callContext
+                .getPolarisCallContext()
+                .getConfigurationStore()
+                .getConfiguration(
+                    callContext.getRealmContext(),
+                    
FeatureConfiguration.SUPPORTED_EXTERNAL_CATALOG_AUTHENTICATION_TYPES)
+                .stream()
+                .map(s -> s.toUpperCase(Locale.ROOT))
+                .toList();
+        if (requiresSecretReferenceExtraction(connectionConfigInfo)) {
+          // For fields that contain references to secrets, we'll separately 
process the secrets
+          // from the original request first, and then populate those fields 
with the extracted
+          // secret references as part of the construction of the internal 
persistence entity.
+          checkState(
+              supportedAuthenticationTypes.contains(
+                  connectionConfigInfo
+                      .getAuthenticationParameters()
+                      .getAuthenticationType()
+                      .name()),
+              "Authentication type %s is not supported.",
+              
connectionConfigInfo.getAuthenticationParameters().getAuthenticationType());
+          processedSecretReferences = extractSecretReferences(catalogRequest, 
entity);
+        } else {
+          // Support no-auth catalog federation only when the feature is 
enabled.
+          checkState(
+              supportedAuthenticationTypes.contains(
+                  
AuthenticationParameters.AuthenticationTypeEnum.IMPLICIT.name()),
+              "Implicit authentication based catalog federation is not 
supported.");
+        }
+        entity =
+            new CatalogEntity.Builder(entity)
+                .setConnectionConfigInfoDpoWithSecrets(
+                    connectionConfigInfo, processedSecretReferences)
+                .build();
+      }
     }
 
     CreateCatalogResult catalogResult =
diff --git a/spec/polaris-management-service.yml 
b/spec/polaris-management-service.yml
index 39c767e66..acf87f8dc 100644
--- a/spec/polaris-management-service.yml
+++ b/spec/polaris-management-service.yml
@@ -917,6 +917,7 @@ components:
             - OAUTH
             - BEARER
             - SIGV4
+            - IMPLICIT
           description: The type of authentication to use when connecting to 
the remote rest service
       required:
         - authenticationType
@@ -926,6 +927,7 @@ components:
           OAUTH: "#/components/schemas/OAuthClientCredentialsParameters"
           BEARER: "#/components/schemas/BearerAuthenticationParameters"
           SIGV4: "#/components/schemas/SigV4AuthenticationParameters"
+          IMPLICIT: "#/components/schemas/ImplicitAuthenticationParameters"
 
     OAuthClientCredentialsParameters:
       type: object
@@ -990,6 +992,13 @@ components:
         - roleArn
         - signingRegion
 
+    ImplicitAuthenticationParameters:
+      type: object
+      description: Polaris does not explicity accept any authentication 
parameters for the connection. Authentication 
+        parameters found in the environment and/or configuration files will be 
used for this connection.
+      allOf:
+        - $ref: '#/components/schemas/AuthenticationParameters'
+
     StorageConfigInfo:
       type: object
       description: A storage configuration used by catalogs

Reply via email to