Copilot commented on code in PR #10730:
URL: https://github.com/apache/gravitino/pull/10730#discussion_r3083643922


##########
trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConnector.java:
##########
@@ -64,6 +83,39 @@ public GravitinoConnector(CatalogConnectorContext 
catalogConnectorContext) {
     this.catalogConnectorContext = catalogConnectorContext;
     this.connectorMetadata =
         new CatalogConnectorMetadata(catalogConnectorContext.getMetalake(), 
this.catalogIdentifier);
+
+    GravitinoConfig config = catalogConnectorContext.getConfig();
+    Map<String, String> clientConfig = config.getClientConfig();
+    this.forwardUser =
+        Boolean.parseBoolean(
+            
clientConfig.getOrDefault(GravitinoAuthProvider.FORWARD_SESSION_USER_KEY, 
"false"));
+    String authTypeStr = 
clientConfig.getOrDefault(GravitinoAuthProvider.AUTH_TYPE_KEY, "none");
+    this.authType = GravitinoAuthProvider.parseAuthType(authTypeStr);
+    this.oauth2CredentialKey = 
clientConfig.get(GravitinoAuthProvider.OAUTH2_TOKEN_CREDENTIAL_KEY);
+
+    if (forwardUser && authType == GravitinoAuthProvider.AuthType.OAUTH2) {
+      Preconditions.checkArgument(
+          StringUtils.isNotBlank(oauth2CredentialKey),
+          "oauth2 with forwardUser=true requires '%s' to be set",
+          GravitinoAuthProvider.OAUTH2_TOKEN_CREDENTIAL_KEY);
+    }
+
+    if (forwardUser) {
+      this.perUserSessionCache =
+          CacheBuilder.newBuilder()
+              .maximumSize(500)
+              .expireAfterAccess(1, TimeUnit.HOURS)
+              .removalListener(
+                  (RemovalNotification<String, UserSession> notification) -> {
+                    UserSession session = notification.getValue();
+                    if (session != null) {
+                      session.close();
+                    }
+                  })
+              .build();

Review Comment:
   Evicting/expiring entries from `perUserSessionCache` closes the associated 
`GravitinoAdminClient`. Trino can hold on to a `ConnectorMetadata` instance for 
the lifetime of a query; if the underlying cached session is evicted while a 
query is still using its metadata, this could close the HTTP client mid-query 
and cause intermittent failures. Consider either (a) not closing sessions on 
cache eviction (only on connector shutdown), or (b) making the per-query 
metadata/client lifecycle explicit (e.g., tying it to transaction/query scope) 
so clients are only closed when no longer in use.



##########
trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConnector.java:
##########
@@ -64,6 +83,39 @@ public GravitinoConnector(CatalogConnectorContext 
catalogConnectorContext) {
     this.catalogConnectorContext = catalogConnectorContext;
     this.connectorMetadata =
         new CatalogConnectorMetadata(catalogConnectorContext.getMetalake(), 
this.catalogIdentifier);
+
+    GravitinoConfig config = catalogConnectorContext.getConfig();
+    Map<String, String> clientConfig = config.getClientConfig();
+    this.forwardUser =
+        Boolean.parseBoolean(
+            
clientConfig.getOrDefault(GravitinoAuthProvider.FORWARD_SESSION_USER_KEY, 
"false"));
+    String authTypeStr = 
clientConfig.getOrDefault(GravitinoAuthProvider.AUTH_TYPE_KEY, "none");
+    this.authType = GravitinoAuthProvider.parseAuthType(authTypeStr);
+    this.oauth2CredentialKey = 
clientConfig.get(GravitinoAuthProvider.OAUTH2_TOKEN_CREDENTIAL_KEY);
+
+    if (forwardUser && authType == GravitinoAuthProvider.AuthType.OAUTH2) {
+      Preconditions.checkArgument(
+          StringUtils.isNotBlank(oauth2CredentialKey),
+          "oauth2 with forwardUser=true requires '%s' to be set",
+          GravitinoAuthProvider.OAUTH2_TOKEN_CREDENTIAL_KEY);

Review Comment:
   When `forwardUser` is enabled, the connector currently only validates the 
OAuth2 credential-key case. If `authType` is `none` or `kerberos`, the 
connector will initialize successfully but later fail at query time when 
`buildForSession` is invoked. Consider validating at construction time that 
`forwardUser=true` is only allowed with `authType=simple` or `authType=oauth2` 
(and keep the existing OAuth2 credential-key validation), so misconfiguration 
fails fast with a clear error.
   ```suggestion
       if (forwardUser) {
         Preconditions.checkArgument(
             authType == GravitinoAuthProvider.AuthType.SIMPLE
                 || authType == GravitinoAuthProvider.AuthType.OAUTH2,
             "forwardUser=true requires authType to be 'simple' or 'oauth2', 
but found '%s'",
             authTypeStr);
         if (authType == GravitinoAuthProvider.AuthType.OAUTH2) {
           Preconditions.checkArgument(
               StringUtils.isNotBlank(oauth2CredentialKey),
               "oauth2 with forwardUser=true requires '%s' to be set",
               GravitinoAuthProvider.OAUTH2_TOKEN_CREDENTIAL_KEY);
         }
   ```



##########
trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConnector.java:
##########
@@ -90,6 +142,45 @@ public ConnectorMetadata getMetadata(
     ConnectorMetadata internalMetadata =
         internalConnector.getMetadata(session, 
gravitinoTransactionHandle.getInternalHandle());
     Preconditions.checkArgument(internalMetadata != null, "Internal metadata 
must not be null");
+
+    if (forwardUser) {
+      String credKey =
+          authType == GravitinoAuthProvider.AuthType.OAUTH2
+              ? "oauth2:" + 
session.getIdentity().getExtraCredentials().get(oauth2CredentialKey)
+              : "simple:" + session.getUser();
+      UserSession userSession;
+      try {
+        userSession =
+            perUserSessionCache.get(
+                credKey,
+                () -> {
+                  GravitinoAdminClient userClient =
+                      GravitinoAuthProvider.buildForSession(
+                          catalogConnectorContext.getConfig(), session);
+                  GravitinoMetalake userMetalake =
+                      
userClient.loadMetalake(catalogConnectorContext.getMetalake().name());
+                  CatalogConnectorMetadata userMetadata =
+                      new CatalogConnectorMetadata(userMetalake, 
catalogIdentifier);
+                  return new UserSession(userClient, userMetadata);
+                });
+      } catch (ExecutionException e) {
+        Throwable cause = e.getCause();
+        LOG.warn(
+            "Failed to create per-user Gravitino client for user '{}': {}",
+            session.getUser(),
+            cause.getMessage());
+        throw new TrinoException(
+            PERMISSION_DENIED,
+            "Failed to authenticate user '"
+                + session.getUser()
+                + "' with Gravitino: "
+                + cause.getMessage(),
+            cause);
+      }
+      return createGravitinoMetadata(
+          userSession.metadata, catalogConnectorContext.getMetadataAdapter(), 
internalMetadata);
+    }

Review Comment:
   The new per-user session forwarding path in `getMetadata()` (per-user cache 
keying + building per-session `GravitinoAdminClient` and `GravitinoMetalake`) 
is a significant behavioral change but isn’t covered by unit tests in the 
connector module. Adding tests that exercise `forwardUser=true` (simple and 
oauth2), cache reuse, and failure cases (e.g., missing token / unsupported 
authType) would help prevent regressions.



##########
trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java:
##########
@@ -414,7 +416,8 @@ public CatalogConnectorContext 
createCatalogConnectorContext(
           
catalogConnectorFactory.createCatalogConnectorContextBuilder(catalog);
       builder
           .withMetalake(metalakes.computeIfAbsent(catalog.getMetalake(), 
this::retrieveMetalake))
-          .withContext(context);
+          .withContext(context)
+          .withConfig(this.config);

Review Comment:
   `createCatalogConnectorContext(...)` receives a per-catalog `config` 
parameter, but the builder is currently populated with 
`withConfig(this.config)` (the manager’s global config captured from the first 
initialization). This means per-catalog settings (including 
`gravitino.client.*` auth/session forwarding options) may be ignored for 
dynamically loaded catalogs, and multiple catalogs with different connector 
properties would behave incorrectly. Consider passing the method parameter 
`config` into the context instead (or rename/remove the parameter if 
per-catalog config is intentionally unsupported).
   ```suggestion
             .withConfig(config);
   ```



##########
trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoConnector.java:
##########
@@ -90,6 +142,45 @@ public ConnectorMetadata getMetadata(
     ConnectorMetadata internalMetadata =
         internalConnector.getMetadata(session, 
gravitinoTransactionHandle.getInternalHandle());
     Preconditions.checkArgument(internalMetadata != null, "Internal metadata 
must not be null");
+
+    if (forwardUser) {
+      String credKey =
+          authType == GravitinoAuthProvider.AuthType.OAUTH2
+              ? "oauth2:" + 
session.getIdentity().getExtraCredentials().get(oauth2CredentialKey)
+              : "simple:" + session.getUser();

Review Comment:
   The cache key for OAuth2 session forwarding is built from the raw Bearer 
token value. This keeps access tokens in cleartext in heap keys (and 
potentially in diagnostics like heap dumps) and can also amplify memory usage 
for long tokens. Consider using a stable, non-sensitive key (e.g., a hash of 
the token, or a token ID if available) and avoid retaining the raw token beyond 
what’s needed to build the per-user client.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to