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");