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

diqiu50 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 5b3b27f02c [#10003] feat (trino-connector): Gravitino Trino connector 
supports authentication for the Gravitino server (#10052)
5b3b27f02c is described below

commit 5b3b27f02c52067ea5f65fbc3bdc20ac671eb163
Author: Yuhui <[email protected]>
AuthorDate: Wed Apr 1 15:06:52 2026 +0800

    [#10003] feat (trino-connector): Gravitino Trino connector supports 
authentication for the Gravitino server (#10052)
    
    ### What changes were proposed in this pull request?
    
    Gravitino Trino connector supports authentication for the Gravitino
    server
    
    ### Why are the changes needed?
    
    Fix: #10003
    
    ### Does this PR introduce _any_ user-facing change?
    
    Update docs
    
    ### How was this patch tested?
    
    Manually test
    
    ---------
    
    Co-authored-by: Claude Sonnet 4.5 <[email protected]>
---
 .../client/GravitinoClientConfiguration.java       |  31 +--
 .../gravitino/client/KerberosTokenProvider.java    |  51 ++++-
 docs/trino-connector/authentication.md             | 136 +++++++++++++
 docs/trino-connector/configuration.md              |   4 +
 .../gravitino/trino/connector/GravitinoConfig.java |  22 ++
 .../connector/catalog/CatalogConnectorManager.java |  25 ++-
 .../connector/catalog/GravitinoAuthProvider.java   | 226 +++++++++++++++++++++
 .../trino/connector/TestGravitinoConfig.java       |  21 ++
 .../catalog/TestGravitinoAuthProvider.java         | 150 ++++++++++++++
 9 files changed, 645 insertions(+), 21 deletions(-)

diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClientConfiguration.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClientConfiguration.java
index eb61f734c5..03326ed912 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClientConfiguration.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClientConfiguration.java
@@ -32,18 +32,6 @@ public class GravitinoClientConfiguration {
   /** The configuration key prefix for the Gravitino client config. */
   public static final String GRAVITINO_CLIENT_CONFIG_PREFIX = 
"gravitino.client.";
 
-  /** A default value for http connection timeout in milliseconds. */
-  public static final long CLIENT_CONNECTION_TIMEOUT_MS_DEFAULT = 180_000L;
-
-  /** A default value for http socket timeout in milliseconds. */
-  public static final int CLIENT_SOCKET_TIMEOUT_MS_DEFAULT = 180_000;
-
-  /** An optional http connection timeout in milliseconds. */
-  public static final String CLIENT_CONNECTION_TIMEOUT_MS = 
"gravitino.client.connectionTimeoutMs";
-
-  /** An optional http socket timeout in milliseconds. */
-  public static final String CLIENT_SOCKET_TIMEOUT_MS = 
"gravitino.client.socketTimeoutMs";
-
   /**
    * A default value for max total HTTP connections in the connection pool. 
This is the same as the
    * default value of Apache HttpClient 5.x
@@ -51,7 +39,8 @@ public class GravitinoClientConfiguration {
   public static final int CLIENT_MAX_CONNECTIONS_DEFAULT = 25;
 
   /** An optional max total HTTP connections. */
-  public static final String CLIENT_MAX_CONNECTIONS = 
"gravitino.client.maxConnections";
+  public static final String CLIENT_MAX_CONNECTIONS =
+      GRAVITINO_CLIENT_CONFIG_PREFIX + "maxConnections";
 
   /**
    * A default value for max HTTP connections per route. This is the same as 
the default value of
@@ -61,7 +50,21 @@ public class GravitinoClientConfiguration {
 
   /** An optional max HTTP connections per route. */
   public static final String CLIENT_MAX_CONNECTIONS_PER_ROUTE =
-      "gravitino.client.maxConnectionsPerRoute";
+      GRAVITINO_CLIENT_CONFIG_PREFIX + "maxConnectionsPerRoute";
+
+  /** A default value for http connection timeout in milliseconds. */
+  public static final long CLIENT_CONNECTION_TIMEOUT_MS_DEFAULT = 180_000L;
+
+  /** A default value for http socket timeout in milliseconds. */
+  public static final int CLIENT_SOCKET_TIMEOUT_MS_DEFAULT = 180_000;
+
+  /** An optional http connection timeout in milliseconds. */
+  public static final String CLIENT_CONNECTION_TIMEOUT_MS =
+      GRAVITINO_CLIENT_CONFIG_PREFIX + "connectionTimeoutMs";
+
+  /** An optional http socket timeout in milliseconds. */
+  public static final String CLIENT_SOCKET_TIMEOUT_MS =
+      GRAVITINO_CLIENT_CONFIG_PREFIX + "socketTimeoutMs";
 
   private static final Set<String> SUPPORT_CLIENT_CONFIG_KEYS =
       ImmutableSet.of(
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/KerberosTokenProvider.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/KerberosTokenProvider.java
index f3688700fa..21ef259342 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/KerberosTokenProvider.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/KerberosTokenProvider.java
@@ -23,7 +23,10 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Method;
 import java.nio.charset.StandardCharsets;
+import java.security.AccessControlContext;
+import java.security.AccessController;
 import java.time.Instant;
 import java.util.Base64;
 import java.util.List;
@@ -296,9 +299,18 @@ public final class KerberosTokenProvider implements 
AuthDataProvider {
     public KerberosTokenProvider build() {
       KerberosTokenProvider provider = new KerberosTokenProvider();
 
-      // Check if the framework (e.g., Flink) has already established Kerberos 
credentials
-      java.security.AccessControlContext context = 
java.security.AccessController.getContext();
-      Subject subject = Subject.getSubject(context);
+      // Check if the framework (e.g., Flink) has already established Kerberos 
credentials.
+      // Use Subject.current() on JDK 18+ (where 
Subject.getSubject(AccessControlContext)
+      // was removed), and fall back to the deprecated API on JDK 17 and below.
+      Subject subject;
+      try {
+        subject = getCurrentSubject();
+      } catch (UnsupportedOperationException e) {
+        throw new IllegalArgumentException(
+            "Cannot detect current Kerberos subject on JDK 17 with Security 
Manager disabled. "
+                + "Please configure keyTabFile and clientPrincipal 
explicitly.",
+            e);
+      }
 
       // If credentials exist (KerberosKey or KerberosTicket), reuse them
       // This avoids redundant logins when Flink has already authenticated 
with Kerberos
@@ -349,5 +361,38 @@ public final class KerberosTokenProvider implements 
AuthDataProvider {
               .map(Object::toString)
               .orElse(null);
     }
+
+    /**
+     * Returns the current {@link Subject} in a JDK-version-neutral way.
+     *
+     * <ul>
+     *   <li>JDK 18+: uses {@code Subject.current()} via reflection, which is 
the designated
+     *       replacement for the removed {@code 
Subject.getSubject(AccessControlContext)}
+     *   <li>JDK 17 and below: uses the deprecated {@code 
Subject.getSubject(AccessControlContext)}
+     * </ul>
+     *
+     * @return the current Subject, or {@code null} if none is established
+     * @throws UnsupportedOperationException if the Security Manager is 
explicitly disabled on JDK
+     *     17
+     * @throws RuntimeException if reflection fails unexpectedly
+     */
+    @SuppressWarnings("removal")
+    private static Subject getCurrentSubject() {
+      // Use reflection to call Subject.current() (JDK 18+) because this 
project compiles on
+      // JDK 17, where Subject.current() does not exist as a compile-time API.
+      // Fall back to the deprecated Subject.getSubject(AccessControlContext) 
on JDK 17 and below.
+      try {
+        Method currentMethod = Subject.class.getMethod("current");
+        return (Subject) currentMethod.invoke(null);
+      } catch (NoSuchMethodException e) {
+        // JDK 17 and below: Subject.current() does not exist, use the legacy 
API.
+        // AccessController.getContext() may throw 
UnsupportedOperationException when the
+        // Security Manager is explicitly disabled — propagate so the caller 
can decide.
+        AccessControlContext context = AccessController.getContext();
+        return Subject.getSubject(context);
+      } catch (ReflectiveOperationException e) {
+        throw new RuntimeException("Failed to invoke Subject.current() via 
reflection", e);
+      }
+    }
   }
 }
diff --git a/docs/trino-connector/authentication.md 
b/docs/trino-connector/authentication.md
new file mode 100644
index 0000000000..262cc2455c
--- /dev/null
+++ b/docs/trino-connector/authentication.md
@@ -0,0 +1,136 @@
+---
+title: "Apache Gravitino Trino connector Authentication"
+slug: /trino-connector/authentication
+keyword: gravitino connector trino authentication
+license: "This software is licensed under the Apache License version 2."
+---
+
+## Authentication
+
+The Gravitino Trino connector supports authenticating to the Gravitino server 
using the same authentication mechanisms as the Gravitino Java client: Simple, 
OAuth2, and Kerberos. Authentication is configured through the Trino connector 
properties file using the `gravitino.client.*` prefix.
+
+If `gravitino.client.authType` is not set, the connector operates in 
no-authentication mode and connects to the Gravitino server without any 
credentials.
+
+### Simple Authentication
+
+Simple authentication uses a username to authenticate with the Gravitino 
server.
+
+**Configuration in `etc/catalog/gravitino.properties`:**
+
+```properties
+connector.name=gravitino
+gravitino.metalake=metalake
+gravitino.uri=http://localhost:8090
+
+# Simple authentication with username
+gravitino.client.authType=simple
+gravitino.user=admin
+```
+
+**Configuration properties:**
+
+| Property                          | Description                              
                            | Default value    | Required                       
        | Since version |
+|-----------------------------------|----------------------------------------------------------------------|------------------|----------------------------------------|---------------|
+| `gravitino.client.authType`       | Authentication type: `simple`, `oauth2`, 
or `kerberos`              | (none)           | No                              
       | 1.3.0         |
+| `gravitino.user`                  | Username for simple authentication       
                            | (none)           | No (uses system user if not 
specified) | 1.3.0         |
+
+### OAuth2 Authentication
+
+OAuth2 authentication uses OAuth 2.0 tokens to authenticate with the Gravitino 
server.
+
+**Configuration in `etc/catalog/gravitino.properties`:**
+
+```properties
+connector.name=gravitino
+gravitino.metalake=metalake
+gravitino.uri=http://localhost:8090
+
+# OAuth2 authentication
+gravitino.client.authType=oauth2
+gravitino.client.oauth2.serverUri=http://oauth-server:8080
+gravitino.client.oauth2.credential=client_id:client_secret
+gravitino.client.oauth2.path=oauth2/token
+gravitino.client.oauth2.scope=gravitino
+```
+
+**Configuration properties:**
+
+| Property                             | Description                           
                 | Default value | Required                    | Since version |
+|--------------------------------------|--------------------------------------------------------|---------------|-----------------------------|---------------|
+| `gravitino.client.authType`          | Authentication type: `simple`, 
`oauth2`, or `kerberos` | (none)        | Yes (to enable OAuth2)      | 1.3.0   
      |
+| `gravitino.client.oauth2.serverUri`  | OAuth2 server URI                     
                 | (none)        | Yes if authType is `oauth2` | 1.3.0         |
+| `gravitino.client.oauth2.credential` | OAuth2 credentials in format 
`client_id:client_secret` | (none)        | Yes if authType is `oauth2` | 1.3.0 
        |
+| `gravitino.client.oauth2.path`       | OAuth2 token endpoint path            
                 | (none)        | Yes if authType is `oauth2` | 1.3.0         |
+| `gravitino.client.oauth2.scope`      | OAuth2 scope                          
                 | (none)        | Yes if authType is `oauth2` | 1.3.0         |
+
+### Kerberos Authentication
+
+Kerberos authentication uses Kerberos tickets to authenticate with the 
Gravitino server.
+
+**Configuration in `etc/catalog/gravitino.properties`:**
+
+```properties
+connector.name=gravitino
+gravitino.metalake=metalake
+gravitino.uri=http://localhost:8090
+
+# Kerberos authentication with keytab
+gravitino.client.authType=kerberos
+gravitino.client.kerberos.principal=user@REALM
+gravitino.client.kerberos.keytabFilePath=/path/to/user.keytab
+```
+
+**Configuration properties:**
+
+| Property                                   | Description         | Default 
value | Required                                                   | Since 
version |
+|--------------------------------------------|---------------------|---------------|------------------------------------------------------------|---------------|
+| `gravitino.client.authType`                | Authentication type: `simple`, 
`oauth2`, or `kerberos` | (none)        | Yes (to enable Kerberos)              
                     | 1.3.0         |
+| `gravitino.client.kerberos.principal`      | Kerberos principal  | (none)    
    | Yes if authType is `kerberos`           | 1.3.0         |
+| `gravitino.client.kerberos.keytabFilePath` | Path to keytab file | (none)    
    | No (uses ticket cache if not specified) | 1.3.0         |
+
+### Example: Connecting to OAuth-protected Gravitino Server
+
+This example shows how to configure the Trino connector to connect to a 
Gravitino server protected by OAuth authentication.
+
+**1. Configure Gravitino server with OAuth** (in `conf/gravitino.conf`):
+
+```properties
+gravitino.authenticators=oauth
+gravitino.authenticator.oauth.serviceAudience=gravitino
+gravitino.authenticator.oauth.defaultSignKey=<your-signing-key>
+gravitino.authenticator.oauth.tokenPath=/oauth2/token
+gravitino.authenticator.oauth.serverUri=http://localhost:8177
+```
+
+**2. Configure Trino connector** (in `etc/catalog/gravitino.properties`):
+
+```properties
+connector.name=gravitino
+gravitino.metalake=my_metalake
+gravitino.uri=http://localhost:8090
+
+# OAuth2 authentication
+gravitino.client.authType=oauth2
+gravitino.client.oauth2.serverUri=http://localhost:8177
+gravitino.client.oauth2.credential=test:test
+gravitino.client.oauth2.path=oauth2/token
+gravitino.client.oauth2.scope=test
+```
+
+**3. Verify the connection:**
+
+```sql
+SHOW CATALOGS;
+```
+
+### Notes
+
+- The Gravitino server must be configured with the corresponding 
authentication mechanism enabled.
+- For OAuth2 authentication, ensure the OAuth2 server is accessible from the 
Trino coordinator and workers.
+- For Kerberos authentication, ensure the Kerberos configuration is properly 
set up on all Trino nodes.
+- Authentication configuration is passed through the `gravitino.client.*` 
prefix to the underlying Gravitino Java client.
+
+### See Also
+
+- [Gravitino Server Authentication 
Configuration](../security/how-to-authenticate.md)
+- [Trino Connector Configuration](./configuration.md)
diff --git a/docs/trino-connector/configuration.md 
b/docs/trino-connector/configuration.md
index 4adeb28360..7380684a90 100644
--- a/docs/trino-connector/configuration.md
+++ b/docs/trino-connector/configuration.md
@@ -20,3 +20,7 @@ license: "This software is licensed under the Apache License 
version 2."
 To configure the Gravitino client, use properties prefixed with 
`gravitino.client.`. These properties will directly passed to the Gravitino 
client.
 
 **Note:** Invalid configuration properties will result in exceptions. Please 
see [Gravitino Java client 
configurations](../how-to-use-gravitino-client.md#gravitino-java-client-configuration)
 for more support client configuration.
+
+## Authentication
+
+The Gravitino Trino connector supports authenticating to the Gravitino server 
using Simple, OAuth, and Kerberos authentication. For detailed authentication 
configuration, please refer to [Trino Connector 
Authentication](./authentication.md).
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 70d69ead10..f32d5dc98d 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
@@ -80,6 +80,13 @@ public class GravitinoConfig {
   private static final ConfigEntry GRAVITINO_METALAKE =
       new ConfigEntry("gravitino.metalake", "The metalake name for used", "", 
true);
 
+  private static final ConfigEntry GRAVITINO_USER =
+      new ConfigEntry(
+          "gravitino.user",
+          "The username for simple authentication with the Gravitino server",
+          "",
+          false);
+
   /**
    * @deprecated Please use {@code gravitino.use-single-metalake} instead.
    */
@@ -193,6 +200,15 @@ public class GravitinoConfig {
     return config.getOrDefault(GRAVITINO_METALAKE.key, 
GRAVITINO_METALAKE.defaultValue);
   }
 
+  /**
+   * Retrieves the username for simple authentication.
+   *
+   * @return the username, or empty string if not configured
+   */
+  public String getUser() {
+    return config.getOrDefault(GRAVITINO_USER.key, 
GRAVITINO_USER.defaultValue);
+  }
+
   /**
    * Retrieves the config for Grivitino client.
    *
@@ -323,6 +339,12 @@ public class GravitinoConfig {
         stringList.add(String.format("\"%s\"='%s'", entry.getKey(), value));
       }
     }
+    // copy the configuration by the prefix of GRAVITINO_CLIENT_CONFIG_PREFIX
+    config.entrySet().stream()
+        .filter(entry -> 
entry.getKey().startsWith(GRAVITINO_CLIENT_CONFIG_PREFIX.key))
+        .forEach(
+            entry ->
+                stringList.add(String.format("\"%s\"='%s'", entry.getKey(), 
entry.getValue())));
     return StringUtils.join(stringList, ',');
   }
 
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java
index 38f5290464..7357531830 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java
@@ -116,10 +116,27 @@ public class CatalogConnectorManager {
     Preconditions.checkArgument(config != null, "config is not null");
     this.config = config;
     if (client == null) {
-      this.gravitinoClient =
-          GravitinoAdminClient.builder(config.getURI())
-              .withClientConfig(config.getClientConfig())
-              .build();
+      String authType = 
config.getClientConfig().getOrDefault("gravitino.client.authType", "none");
+      LOG.info("Building Gravitino client with authType: {}", authType);
+      try {
+        this.gravitinoClient = GravitinoAuthProvider.buildClient(config);
+      } catch (IllegalArgumentException e) {
+        throw new TrinoException(
+            GravitinoErrorCode.GRAVITINO_ILLEGAL_ARGUMENT,
+            "Invalid Gravitino client configuration for authType '"
+                + authType
+                + "': "
+                + e.getMessage(),
+            e);
+      } catch (RuntimeException e) {
+        throw new TrinoException(
+            GravitinoErrorCode.GRAVITINO_RUNTIME_ERROR,
+            "Runtime failure while building Gravitino client with authType '"
+                + authType
+                + "': "
+                + e.getMessage(),
+            e);
+      }
     } else {
       this.gravitinoClient = client;
     }
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/GravitinoAuthProvider.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/GravitinoAuthProvider.java
new file mode 100644
index 0000000000..da12c32547
--- /dev/null
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/GravitinoAuthProvider.java
@@ -0,0 +1,226 @@
+/*
+ * 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.gravitino.trino.connector.catalog;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.gravitino.client.DefaultOAuth2TokenProvider;
+import org.apache.gravitino.client.GravitinoAdminClient;
+import org.apache.gravitino.client.GravitinoClientConfiguration;
+import org.apache.gravitino.client.KerberosTokenProvider;
+import org.apache.gravitino.trino.connector.GravitinoConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Builds a {@link GravitinoAdminClient} with the appropriate authentication 
provider based on the
+ * Gravitino config.
+ */
+class GravitinoAuthProvider {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(GravitinoAuthProvider.class);
+
+  /** Authentication type configuration key. */
+  static final String AUTH_TYPE_KEY =
+      GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX + "authType";
+
+  /** Simple authentication user configuration key. */
+  static final String SIMPLE_AUTH_USER_KEY = "gravitino.user";
+
+  /** OAuth2 server URI configuration key. */
+  static final String OAUTH_SERVER_URI_KEY =
+      GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX + 
"oauth2.serverUri";
+
+  /** OAuth2 credential configuration key. */
+  static final String OAUTH_CREDENTIAL_KEY =
+      GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX + 
"oauth2.credential";
+
+  /** OAuth2 path configuration key. */
+  static final String OAUTH_PATH_KEY =
+      GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX + 
"oauth2.path";
+
+  /** OAuth2 scope configuration key. */
+  static final String OAUTH_SCOPE_KEY =
+      GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX + 
"oauth2.scope";
+
+  /** Kerberos principal configuration key. */
+  static final String KERBEROS_PRINCIPAL_KEY =
+      GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX + 
"kerberos.principal";
+
+  /** Kerberos keytab file path configuration key. */
+  static final String KERBEROS_KEYTAB_FILE_PATH_KEY =
+      GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX + 
"kerberos.keytabFilePath";
+
+  /** Authentication types supported by the Trino connector. */
+  enum AuthType {
+    SIMPLE,
+    OAUTH2,
+    KERBEROS,
+    NONE
+  }
+
+  private GravitinoAuthProvider() {}
+
+  /**
+   * Builds a GravitinoAdminClient from the given config, applying 
authentication settings found in
+   * the client config.
+   *
+   * @param config the Gravitino configuration containing server URI and 
client properties
+   * @return a configured GravitinoAdminClient
+   */
+  public static GravitinoAdminClient buildClient(GravitinoConfig config) {
+    Map<String, String> clientConfig = new HashMap<>(config.getClientConfig());
+    String uri = config.getURI();
+    String authTypeStr = clientConfig.get(AUTH_TYPE_KEY);
+
+    GravitinoAdminClient.AdminClientBuilder builder = 
GravitinoAdminClient.builder(uri);
+
+    if (StringUtils.isNotBlank(authTypeStr)) {
+      AuthType authType;
+      try {
+        authType = AuthType.valueOf(authTypeStr.toUpperCase(Locale.ROOT));
+      } catch (IllegalArgumentException e) {
+        throw new IllegalArgumentException(
+            String.format(
+                "Invalid authentication type: %s. Valid values are: simple, 
oauth2, kerberos, none",
+                authTypeStr),
+            e);
+      }
+
+      switch (authType) {
+        case SIMPLE:
+          buildSimpleAuth(builder, config.getUser());
+          break;
+        case OAUTH2:
+          builder.withOAuth(buildOAuthProvider(clientConfig));
+          break;
+        case KERBEROS:
+          builder.withKerberosAuth(buildKerberosProvider(clientConfig));
+          break;
+        case NONE:
+        default:
+          break;
+      }
+    }
+
+    // Remove auth-specific keys before passing to withClientConfig
+    clientConfig.remove(AUTH_TYPE_KEY);
+    clientConfig.remove(OAUTH_SERVER_URI_KEY);
+    clientConfig.remove(OAUTH_CREDENTIAL_KEY);
+    clientConfig.remove(OAUTH_PATH_KEY);
+    clientConfig.remove(OAUTH_SCOPE_KEY);
+    clientConfig.remove(KERBEROS_PRINCIPAL_KEY);
+    clientConfig.remove(KERBEROS_KEYTAB_FILE_PATH_KEY);
+
+    builder.withClientConfig(clientConfig);
+    return builder.build();
+  }
+
+  private static void buildSimpleAuth(
+      GravitinoAdminClient.AdminClientBuilder builder, String simpleUser) {
+    if (StringUtils.isNotBlank(simpleUser)) {
+      builder.withSimpleAuth(simpleUser);
+    } else {
+      builder.withSimpleAuth();
+    }
+  }
+
+  private static DefaultOAuth2TokenProvider buildOAuthProvider(Map<String, 
String> config) {
+    String serverUri = config.get(OAUTH_SERVER_URI_KEY);
+    String credential = config.get(OAUTH_CREDENTIAL_KEY);
+    String path = config.get(OAUTH_PATH_KEY);
+    String scope = config.get(OAUTH_SCOPE_KEY);
+
+    if (StringUtils.isBlank(serverUri)) {
+      throw new IllegalArgumentException(
+          String.format("OAuth server URI is required. Please set %s", 
OAUTH_SERVER_URI_KEY));
+    }
+    if (StringUtils.isBlank(credential)) {
+      throw new IllegalArgumentException(
+          String.format("OAuth credential is required. Please set %s", 
OAUTH_CREDENTIAL_KEY));
+    }
+    if (StringUtils.isBlank(path)) {
+      throw new IllegalArgumentException(
+          String.format("OAuth path is required. Please set %s", 
OAUTH_PATH_KEY));
+    }
+    if (StringUtils.isBlank(scope)) {
+      throw new IllegalArgumentException(
+          String.format("OAuth scope is required. Please set %s", 
OAUTH_SCOPE_KEY));
+    }
+
+    // Remove leading slash from path if present
+    String normalizedPath = path.startsWith("/") ? path.substring(1) : path;
+
+    LOG.info("Initializing OAuth2 token provider with server URI: {}", 
serverUri);
+    return DefaultOAuth2TokenProvider.builder()
+        .withUri(serverUri)
+        .withCredential(credential)
+        .withPath(normalizedPath)
+        .withScope(scope)
+        .build();
+  }
+
+  private static KerberosTokenProvider buildKerberosProvider(Map<String, 
String> config) {
+    String principal = config.get(KERBEROS_PRINCIPAL_KEY);
+    String keytabFilePath = config.get(KERBEROS_KEYTAB_FILE_PATH_KEY);
+
+    if (StringUtils.isBlank(principal)) {
+      throw new IllegalArgumentException(
+          String.format("Kerberos principal is required. Please set %s", 
KERBEROS_PRINCIPAL_KEY));
+    }
+
+    KerberosTokenProvider.Builder kerberosBuilder =
+        KerberosTokenProvider.builder().withClientPrincipal(principal);
+
+    if (StringUtils.isNotBlank(keytabFilePath)) {
+      File keytabFile = new File(keytabFilePath);
+      if (!keytabFile.exists()) {
+        throw new IllegalArgumentException(
+            String.format(
+                "Keytab file configured via %s does not exist: %s",
+                KERBEROS_KEYTAB_FILE_PATH_KEY, keytabFilePath));
+      }
+      if (!keytabFile.isFile()) {
+        throw new IllegalArgumentException(
+            String.format(
+                "Keytab path configured via %s is not a file: %s",
+                KERBEROS_KEYTAB_FILE_PATH_KEY, keytabFilePath));
+      }
+      if (!keytabFile.canRead()) {
+        throw new IllegalArgumentException(
+            String.format(
+                "Keytab file configured via %s is not readable: %s",
+                KERBEROS_KEYTAB_FILE_PATH_KEY, keytabFilePath));
+      }
+      kerberosBuilder.withKeyTabFile(keytabFile);
+    } else {
+      LOG.warn(
+          "No keytab file configured for Kerberos authentication ({}). "
+              + "Authentication will fail at runtime unless Kerberos 
credentials are already "
+              + "present in the current security context.",
+          KERBEROS_KEYTAB_FILE_PATH_KEY);
+    }
+
+    // host is set by GravitinoAdminClient.Builder.withKerberosAuth() from the 
server URI
+    return kerberosBuilder.build();
+  }
+}
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 f79fa1bfe2..8aa65b4b69 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
@@ -147,6 +147,27 @@ public class TestGravitinoConfig {
         "Config `gravitino.trino.skip-catalog-patterns` is invalid because it 
contains an illegal regular expression");
   }
 
+  @Test
+  public void testToCatalogConfigWithAuthProperties() {
+    String gravitinoUrl = "http://127.0.0.1:8000";;
+    String metalake = "user_001";
+    ImmutableMap<String, String> configMap =
+        ImmutableMap.of(
+            "gravitino.uri",
+            gravitinoUrl,
+            "gravitino.metalake",
+            metalake,
+            "gravitino.client.authType",
+            "simple",
+            "gravitino.user",
+            "admin");
+    GravitinoConfig config = new GravitinoConfig(configMap);
+
+    String catalogConfig = config.toCatalogConfig();
+    
assertTrue(catalogConfig.contains("\"gravitino.client.authType\"='simple'"));
+    assertTrue(catalogConfig.contains("\"gravitino.user\"='admin'"));
+  }
+
   private static boolean skipCatalog(String catalogName, GravitinoConfig 
config) {
     for (Pattern pattern : config.getSkipCatalogPatterns()) {
       if (pattern.matcher(catalogName).matches()) {
diff --git 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/TestGravitinoAuthProvider.java
 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/TestGravitinoAuthProvider.java
new file mode 100644
index 0000000000..5a341614b7
--- /dev/null
+++ 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/TestGravitinoAuthProvider.java
@@ -0,0 +1,150 @@
+/*
+ * 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.gravitino.trino.connector.catalog;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import org.apache.gravitino.trino.connector.GravitinoConfig;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class TestGravitinoAuthProvider {
+
+  @Test
+  public void testBuildClientNoAuth() {
+    assertDoesNotThrow(() -> 
GravitinoAuthProvider.buildClient(buildConfig(ImmutableMap.of())));
+  }
+
+  @Test
+  public void testBuildClientNoneAuth() {
+    assertDoesNotThrow(
+        () ->
+            GravitinoAuthProvider.buildClient(
+                
buildConfig(ImmutableMap.of(GravitinoAuthProvider.AUTH_TYPE_KEY, "none"))));
+  }
+
+  @Test
+  public void testBuildClientSimpleAuthWithUser() {
+    assertDoesNotThrow(
+        () ->
+            GravitinoAuthProvider.buildClient(
+                buildConfig(
+                    ImmutableMap.of(
+                        GravitinoAuthProvider.AUTH_TYPE_KEY, "simple",
+                        GravitinoAuthProvider.SIMPLE_AUTH_USER_KEY, 
"alice"))));
+  }
+
+  @Test
+  public void testBuildClientSimpleAuthNoUser() {
+    assertDoesNotThrow(
+        () ->
+            GravitinoAuthProvider.buildClient(
+                
buildConfig(ImmutableMap.of(GravitinoAuthProvider.AUTH_TYPE_KEY, "simple"))));
+  }
+
+  @Test
+  public void testBuildClientInvalidAuthType() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () ->
+            GravitinoAuthProvider.buildClient(
+                
buildConfig(ImmutableMap.of(GravitinoAuthProvider.AUTH_TYPE_KEY, 
"invalid_type"))));
+  }
+
+  @Test
+  public void testBuildClientOAuthMissingServerUri() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () ->
+            GravitinoAuthProvider.buildClient(
+                buildConfig(
+                    ImmutableMap.of(
+                        GravitinoAuthProvider.AUTH_TYPE_KEY, "oauth2",
+                        GravitinoAuthProvider.OAUTH_CREDENTIAL_KEY, "cred",
+                        GravitinoAuthProvider.OAUTH_PATH_KEY, "oauth2/token",
+                        GravitinoAuthProvider.OAUTH_SCOPE_KEY, "scope"))));
+  }
+
+  @Test
+  public void testBuildClientOAuthMissingCredential() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () ->
+            GravitinoAuthProvider.buildClient(
+                buildConfig(
+                    ImmutableMap.of(
+                        GravitinoAuthProvider.AUTH_TYPE_KEY, "oauth2",
+                        GravitinoAuthProvider.OAUTH_SERVER_URI_KEY, 
"http://auth.example.com";,
+                        GravitinoAuthProvider.OAUTH_PATH_KEY, "oauth2/token",
+                        GravitinoAuthProvider.OAUTH_SCOPE_KEY, "scope"))));
+  }
+
+  @Test
+  public void testBuildClientKerberosMissingPrincipal() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () ->
+            GravitinoAuthProvider.buildClient(
+                
buildConfig(ImmutableMap.of(GravitinoAuthProvider.AUTH_TYPE_KEY, "kerberos"))));
+  }
+
+  @Test
+  public void testBuildClientKerberosKeytabNotFound(@TempDir 
java.nio.file.Path tempDir) {
+    assertThrows(
+        IllegalArgumentException.class,
+        () ->
+            GravitinoAuthProvider.buildClient(
+                buildConfig(
+                    ImmutableMap.of(
+                        GravitinoAuthProvider.AUTH_TYPE_KEY, "kerberos",
+                        GravitinoAuthProvider.KERBEROS_PRINCIPAL_KEY, 
"[email protected]",
+                        GravitinoAuthProvider.KERBEROS_KEYTAB_FILE_PATH_KEY,
+                            tempDir.resolve("missing.keytab").toString()))));
+  }
+
+  @Test
+  public void testBuildClientKerberosWithKeytab(@TempDir java.nio.file.Path 
tempDir)
+      throws IOException {
+    File keytabFile = tempDir.resolve("user.keytab").toFile();
+    Files.write(keytabFile.toPath(), new byte[0]);
+    assertDoesNotThrow(
+        () ->
+            GravitinoAuthProvider.buildClient(
+                buildConfig(
+                    ImmutableMap.of(
+                        GravitinoAuthProvider.AUTH_TYPE_KEY, "kerberos",
+                        GravitinoAuthProvider.KERBEROS_PRINCIPAL_KEY, 
"[email protected]",
+                        GravitinoAuthProvider.KERBEROS_KEYTAB_FILE_PATH_KEY,
+                            keytabFile.getAbsolutePath()))));
+  }
+
+  private GravitinoConfig buildConfig(ImmutableMap<String, String> authConfig) 
{
+    ImmutableMap.Builder<String, String> builder =
+        ImmutableMap.<String, String>builder()
+            .put("gravitino.uri", "http://127.0.0.1:8090";)
+            .put("gravitino.metalake", "test");
+    builder.putAll(authConfig);
+    return new GravitinoConfig(builder.build());
+  }
+}


Reply via email to