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

jerryshao 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 ad104ca711 [Cherry-pick to branch-1.3] [#13967] fix(spark-connector): 
Reject Kerberos for routed Iceberg REST catalogs (#13968) (#14034)
ad104ca711 is described below

commit ad104ca7114d9d683c503bc8cc91ded2b0dff57c
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Oct 22 10:06:47 2026 +0800

    [Cherry-pick to branch-1.3] [#13967] fix(spark-connector): Reject Kerberos 
for routed Iceberg REST catalogs (#13968) (#14034)
    
    **Cherry-pick Information:**
    - Original commit: 5a45beb1c743fe9b34be7a8d0d5a3596e7ec84af
    - Target branch: `branch-1.3`
    - Status: ⚠️ Adapted cherry-pick: dropped the bearer-token reuse, since
    the `token` auth type (#12570) is not in branch-1.3. Only the Kerberos
    fail-fast is backported.
    
    ---------
    
    Co-authored-by: Yuhui <[email protected]>
    Co-authored-by: diqiu50 <[email protected]>
---
 docs/spark-connector/spark-catalog-iceberg.md      |  2 ++
 .../connector/iceberg/IcebergRestOAuthConfig.java  | 15 ++++++--
 .../iceberg/TestIcebergRestOAuthConfig.java        | 40 ++++++++++++++++++++++
 3 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/docs/spark-connector/spark-catalog-iceberg.md 
b/docs/spark-connector/spark-catalog-iceberg.md
index a50a21f5b6..b2e9deccc6 100644
--- a/docs/spark-connector/spark-catalog-iceberg.md
+++ b/docs/spark-connector/spark-catalog-iceberg.md
@@ -200,6 +200,8 @@ See [Connect Spark to Iceberg 
REST](../iceberg-rest-engine/spark.md) for the ful
 
 When the Gravitino client uses Basic authentication 
(`spark.sql.gravitino.authType=basic`), the connector reuses its user name and 
password for IRC. Any `rest.auth.*` or `token` property set through 
`spark.sql.gravitino.iceberg.rest.*` disables the reuse.
 
+Kerberos can't be carried to IRC because the Iceberg REST client doesn't 
support SPNEGO. With `spark.sql.gravitino.authType=kerberos`, a routed Iceberg 
catalog fails at initialization unless its authentication is configured through 
`spark.sql.gravitino.iceberg.rest.*`.
+
 When the Gravitino client uses OAuth2, the connector reuses its OAuth2 client 
configuration for IRC by
 default. This avoids duplicating configuration when both endpoints accept the 
same client identity. The
 equivalent explicit setting is:
diff --git 
a/spark-connector/spark-common/src/main/java/org/apache/gravitino/spark/connector/iceberg/IcebergRestOAuthConfig.java
 
b/spark-connector/spark-common/src/main/java/org/apache/gravitino/spark/connector/iceberg/IcebergRestOAuthConfig.java
index 1a65415aef..12f866f83f 100644
--- 
a/spark-connector/spark-common/src/main/java/org/apache/gravitino/spark/connector/iceberg/IcebergRestOAuthConfig.java
+++ 
b/spark-connector/spark-common/src/main/java/org/apache/gravitino/spark/connector/iceberg/IcebergRestOAuthConfig.java
@@ -83,13 +83,22 @@ class IcebergRestOAuthConfig {
     if (AuthProperties.isBasic(authType)) {
       return applyBasicCredentials(sparkConf, result);
     }
+    boolean hasExplicitLegacyOAuth2 =
+        StringUtils.equalsIgnoreCase(explicitAuthType, AUTH_TYPE_OAUTH2)
+            || 
result.keySet().stream().anyMatch(OAUTH2_TRIGGER_PROPERTIES::contains);
+    // An explicit legacy OAuth2 configuration already decides how IRC is 
authenticated.
+    if (!hasExplicitLegacyOAuth2) {
+      // The Iceberg REST client has no SPNEGO support, so Kerberos can't be 
carried over.
+      Preconditions.checkArgument(
+          !AuthProperties.isKerberos(authType),
+          "Iceberg REST service can't be accessed with %s=kerberos; set"
+              + " spark.sql.gravitino.iceberg.rest.* to configure its 
authentication explicitly",
+          GravitinoSparkConfig.GRAVITINO_AUTH_TYPE);
+    }
 
     boolean reuseOAuth2 =
         
sparkConf.getBoolean(GravitinoSparkConfig.GRAVITINO_ICEBERG_REUSE_OAUTH2, true)
             && AuthProperties.isOAuth2(authType);
-    boolean hasExplicitLegacyOAuth2 =
-        StringUtils.equalsIgnoreCase(explicitAuthType, AUTH_TYPE_OAUTH2)
-            || 
result.keySet().stream().anyMatch(OAUTH2_TRIGGER_PROPERTIES::contains);
     if (!reuseOAuth2 && !hasExplicitLegacyOAuth2) {
       return result;
     }
diff --git 
a/spark-connector/spark-common/src/test/java/org/apache/gravitino/spark/connector/iceberg/TestIcebergRestOAuthConfig.java
 
b/spark-connector/spark-common/src/test/java/org/apache/gravitino/spark/connector/iceberg/TestIcebergRestOAuthConfig.java
index 4abcd2fed7..d5c97d93f5 100644
--- 
a/spark-connector/spark-common/src/test/java/org/apache/gravitino/spark/connector/iceberg/TestIcebergRestOAuthConfig.java
+++ 
b/spark-connector/spark-common/src/test/java/org/apache/gravitino/spark/connector/iceberg/TestIcebergRestOAuthConfig.java
@@ -239,6 +239,46 @@ public class TestIcebergRestOAuthConfig {
     Assertions.assertTrue(exception.getMessage().contains("basic.password"));
   }
 
+  @Test
+  void testKerberosFailsFast() {
+    SparkConf sparkConf = new SparkConf(false);
+    sparkConf.set(GravitinoSparkConfig.GRAVITINO_AUTH_TYPE, "kerberos");
+
+    IllegalArgumentException exception =
+        Assertions.assertThrows(
+            IllegalArgumentException.class,
+            () -> IcebergRestOAuthConfig.resolve(sparkConf, 
Collections.emptyMap()));
+
+    Assertions.assertTrue(exception.getMessage().contains("kerberos"));
+  }
+
+  @Test
+  void testExplicitConfigSkipsKerberosFailure() {
+    SparkConf sparkConf = new SparkConf(false);
+    sparkConf.set(GravitinoSparkConfig.GRAVITINO_AUTH_TYPE, "kerberos");
+    Map<String, String> explicit = ImmutableMap.of("token", "irc-token");
+
+    Map<String, String> result = IcebergRestOAuthConfig.resolve(sparkConf, 
explicit);
+
+    Assertions.assertEquals(explicit, result);
+  }
+
+  @Test
+  void testExplicitLegacyOAuth2SkipsKerberosFailure() {
+    Map<String, String> explicit =
+        ImmutableMap.of(
+            "credential",
+            "irc:secret",
+            "oauth2-server-uri",
+            "https://identity.example.com/oauth/token";);
+    SparkConf sparkConf = new SparkConf(false);
+    sparkConf.set(GravitinoSparkConfig.GRAVITINO_AUTH_TYPE, "kerberos");
+
+    Map<String, String> result = IcebergRestOAuthConfig.resolve(sparkConf, 
explicit);
+
+    Assertions.assertEquals("irc:secret", 
result.get(IcebergRestOAuthConfig.CREDENTIAL));
+  }
+
   private SparkConf basicSparkConf(String username, String password) {
     SparkConf sparkConf = new SparkConf(false);
     sparkConf.set(GravitinoSparkConfig.GRAVITINO_AUTH_TYPE, "basic");

Reply via email to