github-actions[bot] commented on code in PR #66890:
URL: https://github.com/apache/doris/pull/66890#discussion_r3803809679


##########
fe/fe-connector/fe-connector-hms/src/main/java/org/apache/doris/connector/hms/HmsConfHelper.java:
##########
@@ -58,21 +69,92 @@ public static HiveConf createHiveConf(Map<String, String> 
properties) {
         // (fixes SecurityUtil.<clinit>) but cannot fix this conf-cached CL. 
Pinning here keeps the whole
         // hive-metastore class graph in one loader.
         hiveConf.setClassLoader(HmsConfHelper.class.getClassLoader());
+        addConfResources(hiveConf, confResources);
         for (Map.Entry<String, String> entry : properties.entrySet()) {
+            // A blank username was ignored by the legacy copy-if-present 
path; preserving a resource value (or
+            // the "hadoop" default) avoids createRemoteUser("") failing 
before the first HMS RPC.
+            if ("hadoop.username".equals(entry.getKey()) && 
isBlank(entry.getValue())) {
+                continue;
+            }
             hiveConf.set(entry.getKey(), entry.getValue());
         }
         // A kerberized HMS requires SASL transport on the metastore Thrift 
connection. The legacy fe-core
         // HMSBaseProperties.initHadoopAuthenticator auto-enabled 
hive.metastore.sasl.enabled whenever the
         // metastore/hadoop auth was kerberos; preserve that here so a catalog 
that only declares kerberos auth
         // (without an explicit hive.metastore.sasl.enabled) still negotiates 
SASL, instead of opening a plain
         // TSocket that a kerberized metastore drops with TTransportException.
-        if 
("kerberos".equalsIgnoreCase(properties.get("hadoop.security.authentication"))
-                || 
"kerberos".equalsIgnoreCase(properties.get("hive.metastore.authentication.type")))
 {
+        String hmsAuthType = 
properties.get("hive.metastore.authentication.type");
+        boolean explicitSimple = "simple".equalsIgnoreCase(hmsAuthType);

Review Comment:
   **[P1] Make explicit SIMPLE override resource-provided SASL**
   
   The resource base is loaded before this block, but `explicitSimple` only 
prevents us from setting SASL to true; it never clears an inherited 
`hive.metastore.sasl.enabled=true`. A catalog that points at a simple HMS while 
reusing a cluster hive-site.xml can therefore still enter HiveMetaStoreClient's 
Kerberos/SASL transport instead of the configured SIMPLE `set_ugi` path. The 
Iceberg/Paimon assembler has the same gap because `toHiveConfOverrides` emits 
`true` for Kerberos but no `false` for explicit SIMPLE. This is distinct from 
the earlier storage-Kerberos issue: the stale value now comes from the 
lower-precedence resource. Please emit an explicit false override after 
resource layering (for both builders) and cover a resource-backed 
SASL-true/SIMPLE catalog.



##########
fe/fe-connector/fe-connector-paimon/src/main/java/org/apache/doris/connector/paimon/PaimonConnector.java:
##########
@@ -489,14 +502,40 @@ private Catalog createCatalogFromContext(CatalogContext 
catalogContext, String f
         ClassLoader previous = Thread.currentThread().getContextClassLoader();
         try {
             
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
-            return context.executeAuthenticated(() -> 
CatalogFactory.createCatalog(catalogContext));
+            return context.executeAuthenticated(() -> {
+                // Paimon's CachedClientPool eagerly opens a SIMPLE client in 
the HiveCatalog constructor, so
+                // construction must cross the HMS boundary too. FileIO only 
stores its configuration here and
+                // still creates filesystems lazily under the connector's 
separate storage authenticator.
+                Catalog catalog = hmsAuth == null
+                        ? CatalogFactory.createCatalog(catalogContext)
+                        : hmsAuth.doAs(() -> 
CatalogFactory.createCatalog(catalogContext));

Review Comment:
   **[P1] Keep Paimon's eager FileIO work under the storage identity**
   
   This inner `doAs` wraps the whole SDK factory, not just eager HMS client 
creation. In Paimon 1.3.1, `HiveCatalog.createHiveCatalog` calls 
`FileIO.get(...)` and `fileIO.checkOrMkdirs(warehouse)` before it constructs 
the catalog/client pool, so a SIMPLE HMS user nested inside a Kerberos storage 
`doAs` performs that warehouse access as the HMS user. Mixed-identity catalogs 
can fail construction or create/access the warehouse under the wrong owner. 
Please keep factory FileIO work under the storage boundary and scope HMS 
authentication to client-pool creation/RPCs; the regression should construct a 
real mixed-identity catalog and observe the UGI used by the warehouse check.



##########
fe/fe-connector/fe-connector-hive/src/main/java/org/apache/doris/connector/hive/HiveConnector.java:
##########
@@ -591,14 +592,19 @@ private HmsClient createClient() {
 
         // getHmsClientProperties(), not the raw map: the metastore URI must 
reach HiveConf under its canonical
         // key even when the catalog spells it with the "uri" short form.
-        HmsClientConfig config = new 
HmsClientConfig(props.getHmsClientProperties(), poolSize);
+        AbstractHmsMetaStoreProperties hms = (AbstractHmsMetaStoreProperties) 
MetaStoreProviders.bindForType(
+                HmsClientConfig.METASTORE_TYPE_HMS, 
props.getHmsClientProperties(), Collections.emptyMap());
+        HmsClientConfig config = new HmsClientConfig(hms.getConfResources(),
+                HmsConfHelper.mergeCatalogProperties(
+                        props.getHmsClientProperties(), 
hms.toHiveConfOverrides("")),

Review Comment:
   **[P1] Preserve the FE-configured HMS socket timeout**
   
   This new client assembly passes a blank default to `toHiveConfOverrides`, 
which makes the shared parser write an explicit 10-second 
`hive.metastore.client.socket.timeout`. `DefaultConnectorContext` already 
forwards the deployment's `hive_metastore_client_timeout_second` specifically 
for this SPI call, and Iceberg/Paimon consume it; Hive and the parallel Hudi 
call instead ignore (for example) an operator's 60-second setting and time out 
longer HMS operations at 10 seconds. Please resolve the connector/environment 
value here and in Hudi before building the actual client config, and cover a 
non-default environment value with no per-catalog timeout.



##########
fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergConnector.java:
##########
@@ -1248,45 +1277,42 @@ private HadoopAuthenticator pluginAuthenticator() {
     }
 
     /**
-     * Resolves the plugin-side Kerberos authenticator for the catalog, or 
{@code null} for a non-Kerberos
-     * catalog. Two Kerberos sources are covered, in precedence order:
-     * <ol>
-     *   <li><b>Storage</b> Kerberos — the raw {@code 
hadoop.security.authentication=kerberos} passthrough
-     *       (HDFS / data-lake login), built from the storage Hadoop 
configuration. Unchanged prior behavior;
-     *       when storage is Kerberos this single login also carries the HMS 
metastore RPC (same UGI).</li>
-     *   <li><b>HMS-metastore</b> Kerberos with non-Kerberos storage — a 
secured Hive Metastore whose data
-     *       storage is simple (e.g. a Kerberized HMS over S3). Legacy fe-core 
served this from the fe-core
-     *       {@code IcebergHMSMetaStoreProperties} HMS authenticator 
(delivered via {@code DefaultConnectorContext});
-     *       once the fe-core iceberg property cluster is deleted the 
connector must own it. This mirrors
-     *       {@code HMSBaseProperties.initHadoopAuthenticator}: the HMS client 
principal/keytab facts
-     *       ({@link HmsMetaStoreProperties#kerberos()}) feed a {@link 
KerberosAuthenticationConfig}, so the
-     *       {@code doAs} logs in the same client identity fe-core used. The 
HMS <em>service</em> principal /
-     *       SASL settings ride the catalog's own HiveConf ({@code 
hms.toHiveConfOverrides}), not the login.</li>
-     * </ol>
-     * Package-visible + static for direct unit testing (mirrors the {@code 
metaFailureMessage} helpers).
+     * Resolves only the storage-side Kerberos authenticator used by FileIO. 
HMS authentication is intentionally
+     * resolved separately by {@link #buildHmsAuthenticator} and applied at 
the client-pool boundary.
      */
     static HadoopAuthenticator buildPluginAuthenticator(Map<String, String> 
properties,
             Map<String, String> storageHadoopConfig) {
         if 
("kerberos".equalsIgnoreCase(properties.get(HADOOP_SECURITY_AUTHENTICATION))) {
             return HadoopAuthenticator.getHadoopAuthenticator(
                     IcebergCatalogFactory.buildHadoopConfiguration(properties, 
storageHadoopConfig));
         }
-        if 
(IcebergCatalogProperties.TYPE_HMS.equals(IcebergCatalogProperties.of(properties).getFlavor()))
 {
-            HmsMetaStoreProperties hms = (HmsMetaStoreProperties) 
MetaStoreProviders.bindForType(
-                    IcebergCatalogProperties.TYPE_HMS, properties, 
storageHadoopConfig);
-            Optional<KerberosAuthSpec> spec = hms.kerberos();
-            if (spec.isPresent() && spec.get().hasCredentials()) {
-                Configuration conf =
-                        
IcebergCatalogFactory.buildHadoopConfiguration(properties, storageHadoopConfig);
-                conf.set("hadoop.security.authentication", "kerberos");
-                conf.set("hive.metastore.sasl.enabled", "true");
-                return HadoopAuthenticator.getHadoopAuthenticator(
-                        new 
KerberosAuthenticationConfig(spec.get().getPrincipal(), spec.get().getKeytab(), 
conf));
-            }
-        }
         return null;

Review Comment:
   **[P1] Compute Iceberg's default HMS owner under the HMS identity**
   
   This now returns null for an HMS-Kerberos/simple-storage catalog, so the 
outer plugin context runs the DDL under the FE process identity and only the 
later client-pool callback enters the HMS `doAs`. Iceberg 1.10.1 computes a new 
table's default owner with `HiveHadoopUtil.currentUser()` in 
`HiveTableOperations.doCommit` before `persistTable` calls `metaClients.run`; 
the create RPC is authenticated, but the persisted owner is the FE process user 
rather than the configured HMS principal. Before this change, the HMS fallback 
covered that computation. Please derive/set `HiveCatalog.HMS_TABLE_OWNER` under 
the HMS authenticator without wrapping FileIO, and add a mixed-identity 
create-table test that checks both the persisted owner and storage UGI.



##########
fe/fe-connector/fe-connector-paimon/src/main/java/org/apache/doris/connector/paimon/PaimonHmsClientPool.java:
##########
@@ -0,0 +1,119 @@
+// 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.doris.connector.paimon;
+
+import org.apache.doris.kerberos.HadoopAuthenticator;
+
+import org.apache.hadoop.hive.metastore.IMetaStoreClient;
+import org.apache.paimon.catalog.Catalog;
+import org.apache.paimon.catalog.DelegateCatalog;
+import org.apache.paimon.client.ClientPool;
+import org.apache.paimon.hive.HiveCatalog;
+import org.apache.thrift.TException;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Field;
+import java.security.PrivilegedAction;
+
+/** Applies the HMS identity at Paimon's metastore client acquisition and RPC 
boundary. */
+final class PaimonHmsClientPool implements ClientPool<IMetaStoreClient, 
TException> {
+
+    private final ClientPool<IMetaStoreClient, TException> delegate;
+    private final HadoopAuthenticator authenticator;
+
+    private PaimonHmsClientPool(ClientPool<IMetaStoreClient, TException> 
delegate,
+            HadoopAuthenticator authenticator) {
+        this.delegate = delegate;
+        this.authenticator = authenticator;
+    }
+
+    static ClientPool<IMetaStoreClient, TException> wrap(
+            ClientPool<IMetaStoreClient, TException> delegate, 
HadoopAuthenticator authenticator) {
+        return new PaimonHmsClientPool(delegate, authenticator);
+    }
+
+    static Catalog install(Catalog catalog, HadoopAuthenticator authenticator) 
{
+        if (authenticator == null) {
+            return catalog;
+        }
+        Catalog root = DelegateCatalog.rootCatalog(catalog);
+        if (!(root instanceof HiveCatalog)) {
+            throw new IllegalStateException("Expected a Paimon HiveCatalog for 
HMS authentication");
+        }
+        try {
+            Field clients = HiveCatalog.class.getDeclaredField("clients");
+            clients.setAccessible(true);
+            @SuppressWarnings("unchecked")
+            ClientPool<IMetaStoreClient, TException> delegate =
+                    (ClientPool<IMetaStoreClient, TException>) 
clients.get(root);
+            // Paimon exposes no client-pool injection seam; replacing only 
this field prevents the HMS user
+            // from leaking into FileIO while covering both cached-pool client 
creation and every metastore RPC.
+            clients.set(root, wrap(delegate, authenticator));

Review Comment:
   **[P1] Apply the HMS boundary to loader-created Paimon catalogs too**
   
   Replacing `clients` on this one root object does not cover the 
`HiveCatalogLoader` retained by tables loaded from it. Paimon 1.3.1's loader 
creates a fresh `HiveCatalog` with an unwrapped `CachedClientPool`; ordinary 
Doris `beginQuerySnapshot -> table.latestSnapshot()` can reuse the handle's 
transient table and reach that loader outside the table-resolution auth scope. 
A user-supplied `ugi`/`user_name` pool key makes the split immediate; with the 
canonical config keys, access eviction lets the loader recreate its eager 
SIMPLE client under the caller rather than the HMS UGI. Please make the 
boundary part of every catalog/pool created by the retained loader, and test a 
loaded table across pool recreation rather than only `wrap(delegate).run(...)`.



##########
fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergConnector.java:
##########
@@ -969,8 +974,32 @@ private Catalog createCatalog() {
 
         LOG.info("Creating Iceberg catalog '{}' flavor='{}' impl='{}'",
                 catalogName, flavor, 
catalogOptions.get(CatalogProperties.CATALOG_IMPL));
-        return buildCatalogAuthenticated(flavor,
-                () -> CatalogUtil.buildIcebergCatalog(catalogName, 
catalogOptions, conf));
+        return buildCatalogAuthenticated(flavor, () -> {
+            if (!IcebergCatalogProperties.TYPE_HMS.equals(flavor)) {
+                return CatalogUtil.buildIcebergCatalog(catalogName, 
catalogOptions, conf);
+            }
+            HadoopAuthenticator hmsAuth = buildHmsAuthenticator(properties, 
storageHadoopConfig);
+            Catalog catalog = CatalogUtil.buildIcebergCatalog(catalogName, 
catalogOptions, conf);
+            return IcebergHmsClientPool.install(catalog, hmsAuth);
+        });
+    }
+
+    static String appendHmsCacheKeys(String existing) {
+        String keys = appendCacheKey(existing, "conf:hadoop.username");
+        keys = appendCacheKey(keys, "conf:hive.metastore.client.principal");
+        return appendCacheKey(keys, "conf:hadoop.kerberos.principal");
+    }
+
+    static String appendCacheKey(String existing, String required) {
+        if (StringUtils.isBlank(existing)) {
+            return required;
+        }
+        for (String element : existing.split(",")) {
+            if (required.equalsIgnoreCase(element.trim())) {

Review Comment:
   **[P1] Do not deduplicate case-sensitive conf keys case-insensitively**
   
   The SDKs treat only the `conf:` prefix case-insensitively; they preserve the 
suffix and call Hadoop `Configuration.get` with it. If a user already supplied 
`conf:HADOOP.USERNAME`, this comparison suppresses the required 
`conf:hadoop.username`, but extraction reads the uppercase property as null. 
Same-URI catalogs with different lowercase `hadoop.username` values can then 
derive the same JVM-static pool key and reuse the first catalog's connected 
client. The Paimon copy has the same bug. Please require/replace the exact 
canonical suffix (while handling the prefix as supported) and test a mis-cased 
existing key with two different users.



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to