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

diqiu50 pushed a commit to branch trino-irc-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git

commit d6212754f06d3dbd22d77beb2a44d501c5178b86
Author: yuhui <[email protected]>
AuthorDate: Thu Aug 27 09:22:55 2026 +0000

    fix(trino): reuse OAuth config for Iceberg REST
---
 .../gravitino/trino/connector/GravitinoConfig.java | 39 +++++++++++++++---
 .../trino/connector/GravitinoConnectorFactory.java |  8 +++-
 .../trino/connector/TestGravitinoConfig.java       | 48 ++++++++++++++++++++++
 .../TestGravitinoConnectorFactoryStart.java        | 16 ++++++++
 4 files changed, 104 insertions(+), 7 deletions(-)

diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConfig.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConfig.java
index 6f3f213418..553e091e4d 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConfig.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConfig.java
@@ -825,13 +825,42 @@ public class GravitinoConfig {
    */
   public Map<String, String> getIcebergRestCatalogConfig() {
     String prefix = GRAVITINO_ICEBERG_REST_CATALOG_CONFIG_PREFIX.key;
-    return config.entrySet().stream()
+    Map<String, String> restCatalogConfig = new HashMap<>();
+
+    if 
("oauth2".equalsIgnoreCase(config.get(GravitinoAuthProvider.AUTH_TYPE_KEY))) {
+      restCatalogConfig.put(TRINO_ICEBERG_REST_CATALOG_PREFIX + "security", 
"OAUTH2");
+      putIfNotBlank(
+          restCatalogConfig,
+          TRINO_ICEBERG_REST_CATALOG_PREFIX + "oauth2.credential",
+          config.get(GravitinoAuthProvider.OAUTH_CREDENTIAL_KEY));
+      putIfNotBlank(
+          restCatalogConfig,
+          TRINO_ICEBERG_REST_CATALOG_PREFIX + "oauth2.scope",
+          config.get(GravitinoAuthProvider.OAUTH_SCOPE_KEY));
+
+      String serverUri = 
config.get(GravitinoAuthProvider.OAUTH_SERVER_URI_KEY);
+      String path = config.get(GravitinoAuthProvider.OAUTH_PATH_KEY);
+      if (StringUtils.isNotBlank(serverUri) && StringUtils.isNotBlank(path)) {
+        restCatalogConfig.put(
+            TRINO_ICEBERG_REST_CATALOG_PREFIX + "oauth2.server-uri",
+            StringUtils.removeEnd(serverUri, "/") + "/" + 
StringUtils.removeStart(path, "/"));
+      }
+    }
+
+    config.entrySet().stream()
         .filter(entry -> entry.getKey().startsWith(prefix))
-        .collect(
-            Collectors.toMap(
-                entry ->
+        .forEach(
+            entry ->
+                restCatalogConfig.put(
                     TRINO_ICEBERG_REST_CATALOG_PREFIX + 
entry.getKey().substring(prefix.length()),
-                Map.Entry::getValue));
+                    entry.getValue()));
+    return restCatalogConfig;
+  }
+
+  private static void putIfNotBlank(Map<String, String> target, String key, 
String value) {
+    if (StringUtils.isNotBlank(value)) {
+      target.put(key, value);
+    }
   }
 
   private long parseLongConfigEntry(ConfigEntry entry) {
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConnectorFactory.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConnectorFactory.java
index a748c0ab58..3c9e804286 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConnectorFactory.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConnectorFactory.java
@@ -126,11 +126,15 @@ public class GravitinoConnectorFactory implements 
ConnectorFactory {
           CatalogRegister catalogRegister = new CatalogRegister();
 
           CatalogConnectorFactory catalogConnectorFactory = 
createCatalogConnectorFactory(config);
-          catalogConnectorManager =
+          CatalogConnectorManager newCatalogConnectorManager =
               new CatalogConnectorManager(
                   catalogRegister, catalogConnectorFactory, 
this::getTrinoCatalogName);
-          catalogConnectorManager.config(config, client);
+          newCatalogConnectorManager.config(config, client);
 
+          // Publish the manager only after it has been configured 
successfully. Otherwise a
+          // failed client initialization leaves a shared manager with a null 
Gravitino client,
+          // causing later connector creation attempts to fail with a 
misleading NPE.
+          catalogConnectorManager = newCatalogConnectorManager;
           gravitinoSystemTableFactory = new 
GravitinoSystemTableFactory(catalogConnectorManager);
         }
 
diff --git 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoConfig.java
 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoConfig.java
index b7ec6b8ff9..601af08ab3 100644
--- 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoConfig.java
+++ 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoConfig.java
@@ -359,6 +359,54 @@ public class TestGravitinoConfig {
         "client_id:client_secret", 
restCatalogConfig.get("iceberg.rest-catalog.oauth2.credential"));
   }
 
+  @Test
+  public void testIcebergRestOAuthDefaultsToGravitinoClientOAuth() {
+    GravitinoConfig config =
+        new GravitinoConfig(
+            ImmutableMap.<String, String>builder()
+                .put("gravitino.metalake", "user_001")
+                .put("gravitino.client.authType", "oauth2")
+                .put("gravitino.client.oauth2.serverUri", 
"https://oauth.example.com/";)
+                .put("gravitino.client.oauth2.path", "/realms/gravitino/token")
+                .put("gravitino.client.oauth2.credential", 
"shared-client:shared-secret")
+                .put("gravitino.client.oauth2.scope", "openid")
+                .build());
+
+    Map<String, String> restCatalogConfig = 
config.getIcebergRestCatalogConfig();
+    assertEquals("OAUTH2", 
restCatalogConfig.get("iceberg.rest-catalog.security"));
+    assertEquals(
+        "shared-client:shared-secret",
+        restCatalogConfig.get("iceberg.rest-catalog.oauth2.credential"));
+    assertEquals("openid", 
restCatalogConfig.get("iceberg.rest-catalog.oauth2.scope"));
+    assertEquals(
+        "https://oauth.example.com/realms/gravitino/token";,
+        restCatalogConfig.get("iceberg.rest-catalog.oauth2.server-uri"));
+  }
+
+  @Test
+  public void testIcebergRestOAuthOverridesGravitinoClientOAuthByField() {
+    GravitinoConfig config =
+        new GravitinoConfig(
+            ImmutableMap.<String, String>builder()
+                .put("gravitino.metalake", "user_001")
+                .put("gravitino.client.authType", "oauth2")
+                .put("gravitino.client.oauth2.serverUri", 
"https://oauth.example.com";)
+                .put("gravitino.client.oauth2.path", "realms/gravitino/token")
+                .put("gravitino.client.oauth2.credential", 
"shared-client:shared-secret")
+                .put("gravitino.client.oauth2.scope", "openid")
+                .put("gravitino.iceberg.rest-catalog.oauth2.credential", 
"irc-client:irc-secret")
+                .put("gravitino.iceberg.rest-catalog.oauth2.scope", 
"irc-scope")
+                .build());
+
+    Map<String, String> restCatalogConfig = 
config.getIcebergRestCatalogConfig();
+    assertEquals(
+        "irc-client:irc-secret", 
restCatalogConfig.get("iceberg.rest-catalog.oauth2.credential"));
+    assertEquals("irc-scope", 
restCatalogConfig.get("iceberg.rest-catalog.oauth2.scope"));
+    assertEquals(
+        "https://oauth.example.com/realms/gravitino/token";,
+        restCatalogConfig.get("iceberg.rest-catalog.oauth2.server-uri"));
+  }
+
   @Test
   public void testIcebergRestConfigScopedToMetalakeInMultiMetalakeMode() {
     ImmutableMap<String, String> configMap =
diff --git 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoConnectorFactoryStart.java
 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoConnectorFactoryStart.java
index b104b4d509..cc189815df 100644
--- 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoConnectorFactoryStart.java
+++ 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoConnectorFactoryStart.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.trino.connector;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -127,6 +128,21 @@ public class TestGravitinoConnectorFactoryStart {
     assertTrue(factory.isCatalogConnectorManagerStartTriggered());
   }
 
+  @Test
+  public void testFailedClientInitializationDoesNotPublishManager() {
+    CoordinatorFactory factory = new CoordinatorFactory(null);
+    Map<String, String> brokenDynamicConfig = dynamicConfig();
+    brokenDynamicConfig.put("gravitino.client.authType", "oauth2");
+
+    assertThrows(
+        Exception.class,
+        () -> factory.create("broken_catalog", brokenDynamicConfig, 
mockContext()));
+
+    assertNull(factory.getCatalogConnectorManager());
+    assertNotNull(factory.create("gravitino", staticConfig(), mockContext()));
+    assertTrue(factory.isCatalogConnectorManagerStartTriggered());
+  }
+
   @Test
   public void testStartIsAttemptedOnlyOnce() {
     CoordinatorFactory factory = newFactory();

Reply via email to