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

kirs pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new c34e86b1160 [Feat](Authentication)Supporting Authentication Plugins 
and Kernel Isolation (#41100)
c34e86b1160 is described below

commit c34e86b11608da2295ff69c9e8deef58c0897aec
Author: Calvin Kirs <k...@apache.org>
AuthorDate: Wed Sep 25 17:45:30 2024 +0800

    [Feat](Authentication)Supporting Authentication Plugins and Kernel 
Isolation (#41100)
    
    ## Proposed changes
    - Use a Child-First ClassLoader to isolate plugins from the kernel,
    giving priority to plugin classes to prevent conflicts between the
    plugin and kernel classes.
    - Allow users to place plugins in a specified directory, such as
    auth-lib, to avoid classpath conflicts by default.
    - Support developers in debugging plugins by allowing them to bring in
    plugins via Maven, making the debugging process more convenient.
---
 .../main/java/org/apache/doris/common/Config.java  |  27 +++-
 .../doris/common/util/ChildFirstClassLoader.java   | 151 +++++++++++++++++++++
 .../apache/doris/common/util/ClassLoaderUtils.java | 122 +++++++++++++++++
 .../mysql/authenticate/AuthenticatorManager.java   |  39 +++---
 .../mysql/privilege/AccessControllerManager.java   |  18 ++-
 .../doris/mysql/privilege/UserPropertyMgr.java     |  68 ++++++----
 .../org/apache/doris/plugin/PropertiesUtils.java   |  19 ++-
 7 files changed, 391 insertions(+), 53 deletions(-)

diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java 
b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
index 818ab172b93..59522d27a48 100644
--- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
+++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
@@ -2323,12 +2323,6 @@ public class Config extends ConfigBase {
     @ConfField
     public static long ranger_cache_size = 10000;
 
-    @ConfField(description = {
-            "鉴权插件配置文件路径,需在 DORIS_HOME 下,默认为 conf/authorization.conf",
-            "Authorization plugin configuration file path, need to be in 
DORIS_HOME,"
-                    + "default is conf/authorization.conf"})
-    public static String authorization_config_file_path = 
"conf/authorization.conf";
-
     /**
      * This configuration is used to enable the statistics of query 
information, which will record
      * the access status of databases, tables, and columns, and can be used to 
guide the
@@ -3105,4 +3099,25 @@ public class Config extends ConfigBase {
     @ConfField(mutable = true, description = {
             "设置为 true,如果查询无法选择到健康副本时,会打印出该tablet所有副本的详细信息,"})
     public static boolean sql_block_rule_ignore_admin = false;
+
+    @ConfField(description = {"认证插件目录",
+            "Authentication plugin directory"})
+    public static String authentication_plugins_dir = EnvUtils.getDorisHome() 
+ "/plugins/authentication";
+
+    @ConfField(description = {"鉴权插件目录",
+            "Authorization plugin directory"})
+    public static String authorization_plugins_dir = EnvUtils.getDorisHome() + 
"/plugins/authorization";
+
+    @ConfField(description = {
+            "鉴权插件配置文件路径,需在 DORIS_HOME 下,默认为 conf/authorization.conf",
+            "Authorization plugin configuration file path, need to be in 
DORIS_HOME,"
+                    + "default is conf/authorization.conf"})
+    public static String authorization_config_file_path = 
"/conf/authorization.conf";
+
+    @ConfField(description = {
+            "认证插件配置文件路径,需在 DORIS_HOME 下,默认为 conf/authentication.conf",
+            "Authentication plugin configuration file path, need to be in 
DORIS_HOME,"
+                    + "default is conf/authentication.conf"})
+    public static String authentication_config_file_path = 
"/conf/authentication.conf";
+
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/util/ChildFirstClassLoader.java
 
b/fe/fe-core/src/main/java/org/apache/doris/common/util/ChildFirstClassLoader.java
new file mode 100644
index 00000000000..ad3b0dfe77d
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/common/util/ChildFirstClassLoader.java
@@ -0,0 +1,151 @@
+// 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.common.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * ChildFirstClassLoader is a custom class loader designed to load classes from
+ * plugin JAR files. It uses a child-first class loading strategy, where the 
loader
+ * first attempts to load classes from its own URLs (plugin JARs), and if the 
class
+ * is not found, it delegates the loading to its parent class loader.
+ * <p>
+ * This class is intended for plugin-based systems where classes defined in 
plugins
+ * might override or replace standard library classes.
+ * <p>
+ * Key features:
+ * - Child-First loading mechanism.
+ * - Support for loading classes from multiple JAR files.
+ * - Efficient caching of JAR file resources to avoid repeated file access.
+ */
+public class ChildFirstClassLoader extends URLClassLoader {
+
+    // A list of URLs pointing to JAR files
+    private final List<URL> jarURLs;
+
+    /**
+     * Constructs a new ChildFirstClassLoader with the given URLs and parent 
class loader.
+     * This constructor stores the URLs for class loading.
+     *
+     * @param urls   The URLs pointing to the plugin JAR files.
+     * @param parent The parent class loader to use for delegation if class is 
not found.
+     * @throws IOException        If there is an error opening the JAR files.
+     * @throws URISyntaxException If there is an error converting the URL to 
URI.
+     */
+    public ChildFirstClassLoader(URL[] urls, ClassLoader parent) throws 
IOException, URISyntaxException {
+        super(urls, parent);
+        this.jarURLs = new ArrayList<>();
+        for (URL url : urls) {
+            if ("file".equals(url.getProtocol())) {
+                this.jarURLs.add(url);
+            }
+        }
+    }
+
+    /**
+     * Attempts to load the class with the specified name.
+     * This method first tries to find the class using the current class 
loader (child-first strategy),
+     * and if the class is not found, it delegates the loading to the parent 
class loader.
+     *
+     * @param name    The fully qualified name of the class to be loaded.
+     * @param resolve If true, the class will be resolved after being loaded.
+     * @return The resulting Class object.
+     * @throws ClassNotFoundException If the class cannot be found by either 
the child or parent loader.
+     */
+    @Override
+    protected Class<?> loadClass(String name, boolean resolve) throws 
ClassNotFoundException {
+        // Child-First mechanism: try to find the class locally first
+        try {
+            return findClass(name);
+        } catch (ClassNotFoundException e) {
+            // If the class is not found locally, delegate to the parent class 
loader
+            return super.loadClass(name, resolve);
+        }
+    }
+
+    /**
+     * Searches for the class in the loaded plugin JAR files.
+     * If the class is found in one of the JAR files, it will be defined and 
returned.
+     *
+     * @param name The fully qualified name of the class to find.
+     * @return The resulting Class object.
+     * @throws ClassNotFoundException If the class cannot be found in the JAR 
files.
+     */
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        String classFile = name.replace('.', '/') + ".class";  // Convert 
class name to path
+
+        // Iterate over all the JAR URLs to find the class
+        for (URL jarURL : jarURLs) {
+            try (JarFile jarFile = new 
JarFile(Paths.get(jarURL.toURI()).toFile())) {
+                JarEntry entry = jarFile.getJarEntry(classFile);
+                if (entry != null) {
+                    try (InputStream inputStream = 
jarFile.getInputStream(entry)) {
+                        byte[] classData = readAllBytes(inputStream);
+                        // Define the class from the byte array
+                        return defineClass(name, classData, 0, 
classData.length);
+                    }
+                }
+            } catch (IOException | URISyntaxException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        // If the class was not found in any JAR file, throw 
ClassNotFoundException
+        throw new ClassNotFoundException(name);
+    }
+
+    /**
+     * Reads all bytes from the given InputStream.
+     * This method reads the entire content of the InputStream and returns it 
as a byte array.
+     *
+     * @param inputStream The InputStream to read from.
+     * @return A byte array containing the data from the InputStream.
+     * @throws IOException If an I/O error occurs while reading the stream.
+     */
+    private byte[] readAllBytes(InputStream inputStream) throws IOException {
+        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) 
{
+            byte[] buffer = new byte[1024];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            return outputStream.toByteArray();
+        }
+    }
+
+    /**
+     * Closes all open JAR files and releases any resources held by this class 
loader.
+     * This method should be called when the class loader is no longer needed 
to avoid resource leaks.
+     *
+     * @throws IOException If an I/O error occurs while closing the JAR files.
+     */
+    @Override
+    public void close() throws IOException {
+        super.close();  // Call the superclass close method
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/util/ClassLoaderUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/util/ClassLoaderUtils.java
new file mode 100644
index 00000000000..d0ebd265401
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/common/util/ClassLoaderUtils.java
@@ -0,0 +1,122 @@
+// 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.common.util;
+
+import org.apache.doris.common.Config;
+import org.apache.doris.mysql.authenticate.AuthenticatorFactory;
+import org.apache.doris.mysql.privilege.AccessControllerFactory;
+
+import org.apache.commons.collections.map.HashedMap;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+/**
+ * Utility class for loading service implementations from external JAR files 
in specific plugin directories.
+ * <p>
+ * This class provides a mechanism to dynamically load service implementations 
from JAR files located in
+ * plugin directories, which are mapped by the service type's simple name. It 
uses a child-first class loading
+ * strategy to ensure that plugins in the JAR files are prioritized over 
classes loaded by the parent class loader.
+ * <p>
+ * It is particularly useful in scenarios where the system needs to support 
modular or pluggable architectures,
+ * such as dynamically loading authenticators, access controllers, or other 
pluggable services from external
+ * directories without requiring the services to be bundled with the core 
application.
+ * <p>
+ * Plugin directory mappings are maintained in a static map where the key is 
the simple name of the service class,
+ * and the value is the relative path to the directory containing the plugin 
JARs.
+ * <p>
+ * Example usage:
+ * <pre>
+ * {@code
+ * List<AuthenticatorFactory> authenticators = 
ClassLoaderUtils.loadServicesFromDirectory(AuthenticatorFactory.class);
+ * }
+ * </pre>
+ *
+ * @see ServiceLoader
+ * @see ChildFirstClassLoader
+ */
+public class ClassLoaderUtils {
+    // A mapping of service class simple names to their respective plugin 
directories.
+    private static final Map<String, String> pluginDirMapping = new 
HashedMap();
+
+    static {
+        pluginDirMapping.put(AuthenticatorFactory.class.getSimpleName(), 
Config.authentication_plugins_dir);
+        pluginDirMapping.put(AccessControllerFactory.class.getSimpleName(), 
Config.authorization_plugins_dir);
+    }
+
+    /**
+     * Loads service implementations from JAR files in the specified plugin 
directory.
+     * <p>
+     * The method first looks up the directory for the given service class 
type from the {@code pluginDirMapping}.
+     * If a directory exists and contains JAR files, it will load the service 
implementations from those JAR files
+     * using a child-first class loader to prioritize the plugin classes.
+     * <p>
+     * If no directory is found for the service type, or the directory is 
invalid, an exception is thrown. If the
+     * directory does not contain any JAR files, an empty list is returned.
+     *
+     * @param serviceClass The class type of the service to load. This should 
be the interface or
+     *                     base class of the service.
+     * @param <T>          The type of the service.
+     * @return A list of service instances loaded from JAR files. If no 
services are found, an empty list is returned.
+     * @throws IOException      If there is an error reading the JAR files or 
the directory is invalid.
+     * @throws RuntimeException If there is a problem with the directory 
mapping or JAR file URL creation.
+     */
+    public static <T> List<T> loadServicesFromDirectory(Class<T> serviceClass) 
throws IOException {
+        String pluginDirKey = serviceClass.getSimpleName();
+        String pluginDir = pluginDirMapping.get(pluginDirKey);
+        if (pluginDir == null) {
+            throw new RuntimeException("No mapping found for plugin directory 
key: " + pluginDirKey);
+        }
+        File jarDir = new File(pluginDir);
+        // If the directory does not exist, return an empty list.
+        if (!jarDir.exists()) {
+            return new ArrayList<>();
+        }
+        if (!jarDir.isDirectory()) {
+            throw new IOException("The specified path is not a directory: " + 
pluginDir);
+        }
+
+        File[] jarFiles = jarDir.listFiles((dir, name) -> 
name.endsWith(".jar"));
+        if (jarFiles == null || jarFiles.length == 0) {
+            throw new IOException("No JAR files found in the specified 
directory: " + pluginDir);
+        }
+
+        List<T> services = new ArrayList<>();
+        for (File jarFile : jarFiles) {
+            URL[] jarURLs;
+            jarURLs = new URL[]{jarFile.toURI().toURL()};
+
+            try (ChildFirstClassLoader urlClassLoader = new 
ChildFirstClassLoader(jarURLs,
+                    Thread.currentThread().getContextClassLoader())) {
+                ServiceLoader<T> serviceLoader = 
ServiceLoader.load(serviceClass, urlClassLoader);
+                for (T service : serviceLoader) {
+                    services.add(service);
+                }
+            } catch (URISyntaxException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return services;
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/AuthenticatorManager.java
 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/AuthenticatorManager.java
index 68b6724b6d8..de703b306c6 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/AuthenticatorManager.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/AuthenticatorManager.java
@@ -17,22 +17,21 @@
 
 package org.apache.doris.mysql.authenticate;
 
-import org.apache.doris.common.EnvUtils;
+import org.apache.doris.common.util.ClassLoaderUtils;
 import org.apache.doris.mysql.MysqlAuthPacket;
 import org.apache.doris.mysql.MysqlChannel;
 import org.apache.doris.mysql.MysqlHandshakePacket;
 import org.apache.doris.mysql.MysqlProto;
 import org.apache.doris.mysql.MysqlSerializer;
 import org.apache.doris.mysql.authenticate.password.Password;
+import org.apache.doris.plugin.PropertiesUtils;
 import org.apache.doris.qe.ConnectContext;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-import java.io.File;
 import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.util.List;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.ServiceLoader;
@@ -66,9 +65,28 @@ public class AuthenticatorManager {
         for (AuthenticatorFactory factory : loader) {
             LOG.info("Found Authenticator Plugin Factory: {}", 
factory.factoryIdentifier());
             if (factory.factoryIdentifier().equalsIgnoreCase(identifier)) {
-                return factory.create(loadConfigFile());
+                Properties properties = 
PropertiesUtils.loadAuthenticationConfigFile();
+                return factory.create(properties);
             }
         }
+        return loadCustomerFactories(identifier);
+
+    }
+
+    private Authenticator loadCustomerFactories(String identifier) throws 
Exception {
+        List<AuthenticatorFactory> factories = 
ClassLoaderUtils.loadServicesFromDirectory(AuthenticatorFactory.class);
+        if (factories.isEmpty()) {
+            LOG.info("No customer authenticator found, using default 
authenticator");
+            return defaultAuthenticator;
+        }
+        for (AuthenticatorFactory factory : factories) {
+            LOG.info("Found Customer Authenticator Plugin Factory: {}", 
factory.factoryIdentifier());
+            if (factory.factoryIdentifier().equalsIgnoreCase(identifier)) {
+                Properties properties = 
PropertiesUtils.loadAuthenticationConfigFile();
+                return factory.create(properties);
+            }
+        }
+
         throw new RuntimeException("No AuthenticatorFactory found for 
identifier: " + identifier);
     }
 
@@ -100,15 +118,4 @@ public class AuthenticatorManager {
     private Authenticator chooseAuthenticator(String userName) {
         return authTypeAuthenticator.canDeal(userName) ? authTypeAuthenticator 
: defaultAuthenticator;
     }
-
-    private static Properties loadConfigFile() throws Exception {
-        String configFilePath = EnvUtils.getDorisHome() + 
"/conf/authenticate.conf";
-        if (new File(configFilePath).exists()) {
-            LOG.info("Loading authenticate configuration file: {}", 
configFilePath);
-            Properties properties = new Properties();
-            properties.load(Files.newInputStream(Paths.get(configFilePath)));
-            return properties;
-        }
-        return new Properties();
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java
 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java
index bfdf0a7b095..81fae713e44 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java
@@ -24,6 +24,7 @@ import org.apache.doris.catalog.AuthorizationInfo;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.UserException;
+import org.apache.doris.common.util.ClassLoaderUtils;
 import org.apache.doris.datasource.CatalogIf;
 import org.apache.doris.datasource.ExternalCatalog;
 import org.apache.doris.datasource.InternalCatalog;
@@ -92,9 +93,20 @@ public class AccessControllerManager {
     }
 
     private void loadAccessControllerPlugins() {
-        ServiceLoader<AccessControllerFactory> loader = 
ServiceLoader.load(AccessControllerFactory.class);
+        ServiceLoader<AccessControllerFactory> loaderFromClasspath = 
ServiceLoader.load(AccessControllerFactory.class);
+        for (AccessControllerFactory factory : loaderFromClasspath) {
+            LOG.info("Found Authentication Plugin Factories: {} from class 
path.", factory.factoryIdentifier());
+            accessControllerFactoriesCache.put(factory.factoryIdentifier(), 
factory);
+            accessControllerClassNameMapping.put(factory.getClass().getName(), 
factory.factoryIdentifier());
+        }
+        List<AccessControllerFactory> loader = null;
+        try {
+            loader = 
ClassLoaderUtils.loadServicesFromDirectory(AccessControllerFactory.class);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to load Authentication Plugin 
Factories", e);
+        }
         for (AccessControllerFactory factory : loader) {
-            LOG.info("Found Access Controller Plugin Factory: {}", 
factory.factoryIdentifier());
+            LOG.info("Found Access Controller Plugin Factory: {} from 
directory.", factory.factoryIdentifier());
             accessControllerFactoriesCache.put(factory.factoryIdentifier(), 
factory);
             accessControllerClassNameMapping.put(factory.getClass().getName(), 
factory.factoryIdentifier());
         }
@@ -215,7 +227,7 @@ public class AccessControllerManager {
     // ==== Column ====
     // If param has ctx, we can skip auth by isSkipAuth field in ctx
     public void checkColumnsPriv(ConnectContext ctx, String ctl, String 
qualifiedDb, String tbl, Set<String> cols,
-            PrivPredicate wanted) throws UserException {
+                                 PrivPredicate wanted) throws UserException {
         if (ctx.isSkipAuth()) {
             return;
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserPropertyMgr.java
 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserPropertyMgr.java
index 816ce769a31..29ae1f438a1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserPropertyMgr.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserPropertyMgr.java
@@ -29,6 +29,7 @@ import org.apache.doris.common.UserException;
 import org.apache.doris.common.io.Text;
 import org.apache.doris.common.io.Writable;
 import org.apache.doris.load.DppConfig;
+import org.apache.doris.mysql.authenticate.AuthenticateType;
 import org.apache.doris.persist.gson.GsonUtils;
 import org.apache.doris.resource.Tag;
 
@@ -55,9 +56,9 @@ public class UserPropertyMgr implements Writable {
     protected Map<String, UserProperty> propertyMap = Maps.newHashMap();
     public static final String ROOT_USER = "root";
     public static final String SYSTEM_RESOURCE_USER = "system";
-    public static final String LDAP_RESOURCE_USER = "ldap";
-
-    private static final UserProperty LDAP_PROPERTY = new 
UserProperty(LDAP_RESOURCE_USER);
+    public static final String DEFAULT_RESOURCE_USER = 
Config.authentication_type;
+    // When using a non-internal authentication plugin, the user property 
information uses the default configuration.
+    private static final UserProperty DEFAULT_USER_PROPERTY = new 
UserProperty(DEFAULT_RESOURCE_USER);
     @SerializedName(value = "resourceVersion")
     private AtomicLong resourceVersion = new AtomicLong(0);
 
@@ -93,7 +94,7 @@ public class UserPropertyMgr implements Writable {
 
     public int getQueryTimeout(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return 0;
         }
@@ -102,7 +103,7 @@ public class UserPropertyMgr implements Writable {
 
     public int getInsertTimeout(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return 0;
         }
@@ -111,7 +112,7 @@ public class UserPropertyMgr implements Writable {
 
     public long getMaxConn(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return 0;
         }
@@ -120,7 +121,7 @@ public class UserPropertyMgr implements Writable {
 
     public long getMaxQueryInstances(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return Config.default_max_query_instances;
         }
@@ -139,21 +140,21 @@ public class UserPropertyMgr implements Writable {
         List<String> ret = new ArrayList<>();
         users.forEach(
                 u -> {
-                UserProperty userProperty = propertyMap.get(u);
-                if (userProperty == null) {
-                    return;
-                }
-                if (clusterName.equals(userProperty.getDefaultCloudCluster())) 
{
-                    ret.add(ClusterNamespace.getNameFromFullName(u));
+                    UserProperty userProperty = propertyMap.get(u);
+                    if (userProperty == null) {
+                        return;
+                    }
+                    if 
(clusterName.equals(userProperty.getDefaultCloudCluster())) {
+                        ret.add(ClusterNamespace.getNameFromFullName(u));
+                    }
                 }
-            }
         );
         return ret;
     }
 
     public int getParallelFragmentExecInstanceNum(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return -1;
         }
@@ -162,7 +163,7 @@ public class UserPropertyMgr implements Writable {
 
     public Set<Tag> getResourceTags(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return UserProperty.INVALID_RESOURCE_TAGS;
         }
@@ -182,7 +183,7 @@ public class UserPropertyMgr implements Writable {
         Pair<String, DppConfig> loadClusterInfo = null;
 
         UserProperty property = propertyMap.get(qualifiedUser);
-        property = getLdapPropertyIfNull(qualifiedUser, property);
+        property = getPropertyIfNull(qualifiedUser, property);
         if (property == null) {
             throw new DdlException("User " + qualifiedUser + " does not 
exist");
         }
@@ -192,7 +193,7 @@ public class UserPropertyMgr implements Writable {
 
     public List<List<String>> fetchUserProperty(String qualifiedUser) throws 
AnalysisException {
         UserProperty property = propertyMap.get(qualifiedUser);
-        property = getLdapPropertyIfNull(qualifiedUser, property);
+        property = getPropertyIfNull(qualifiedUser, property);
         if (property == null) {
             throw new AnalysisException("User " + qualifiedUser + " does not 
exist");
         }
@@ -201,16 +202,16 @@ public class UserPropertyMgr implements Writable {
 
     public String[] getSqlBlockRules(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
-            return new String[] {};
+            return new String[]{};
         }
         return existProperty.getSqlBlockRules();
     }
 
     public int getCpuResourceLimit(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return -1;
         }
@@ -219,7 +220,7 @@ public class UserPropertyMgr implements Writable {
 
     public long getExecMemLimit(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return -1;
         }
@@ -228,7 +229,7 @@ public class UserPropertyMgr implements Writable {
 
     public String getWorkloadGroup(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
-        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        existProperty = getPropertyIfNull(qualifiedUser, existProperty);
         if (existProperty == null) {
             return null;
         }
@@ -244,9 +245,24 @@ public class UserPropertyMgr implements Writable {
         return Pair.of(false, "");
     }
 
-    private UserProperty getLdapPropertyIfNull(String qualifiedUser, 
UserProperty existProperty) {
-        if (existProperty == null && 
Env.getCurrentEnv().getAuth().getLdapManager().doesUserExist(qualifiedUser)) {
-            return LDAP_PROPERTY;
+    /**
+     * The method determines which user property to return based on the 
existProperty parameter
+     * and system configuration:
+     * If existProperty is not null, return it directly.
+     * If the authentication type is LDAP and the user exists in LDAP, return 
DEFAULT_USER_PROPERTY.
+     * If the authentication type is not the default type, return 
DEFAULT_USER_PROPERTY.
+     * Otherwise, return existProperty.
+     */
+    private UserProperty getPropertyIfNull(String qualifiedUser, UserProperty 
existProperty) {
+        if (null != existProperty) {
+            return existProperty;
+        }
+        if 
(AuthenticateType.LDAP.name().equalsIgnoreCase(Config.authentication_type)
+                && 
Env.getCurrentEnv().getAuth().getLdapManager().doesUserExist(qualifiedUser)) {
+            return DEFAULT_USER_PROPERTY;
+        }
+        if 
(!Config.authentication_type.equalsIgnoreCase(AuthenticateType.DEFAULT.name())) 
{
+            return DEFAULT_USER_PROPERTY;
         }
         return existProperty;
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/plugin/PropertiesUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/plugin/PropertiesUtils.java
index 953a35787b7..7318be7da61 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/plugin/PropertiesUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/plugin/PropertiesUtils.java
@@ -20,6 +20,9 @@ package org.apache.doris.plugin;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.EnvUtils;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
@@ -29,10 +32,11 @@ import java.util.Map;
 import java.util.Properties;
 
 public class PropertiesUtils {
-    public static final String ACCESS_PROPERTIES_FILE_DIR = 
Config.authorization_config_file_path;
+
+    public static final Logger LOG = 
LogManager.getLogger(PropertiesUtils.class);
 
     public static Map<String, String> loadAccessControllerPropertiesOrNull() 
throws IOException {
-        String configFilePath = EnvUtils.getDorisHome() + 
ACCESS_PROPERTIES_FILE_DIR;
+        String configFilePath = EnvUtils.getDorisHome() + 
Config.authorization_config_file_path;
         if (new File(configFilePath).exists()) {
             Properties properties = new Properties();
             properties.load(Files.newInputStream(Paths.get(configFilePath)));
@@ -41,6 +45,17 @@ public class PropertiesUtils {
         return null;
     }
 
+    public static Properties loadAuthenticationConfigFile() throws Exception {
+        String configFilePath = EnvUtils.getDorisHome() + 
Config.authentication_config_file_path;
+        if (new File(configFilePath).exists()) {
+            LOG.info("Loading authenticate configuration file: {}", 
configFilePath);
+            Properties properties = new Properties();
+            properties.load(Files.newInputStream(Paths.get(configFilePath)));
+            return properties;
+        }
+        return new Properties();
+    }
+
     public static Map<String, String> propertiesToMap(Properties properties) {
         Map<String, String> map = new HashMap<>();
         for (Map.Entry<Object, Object> entry : properties.entrySet()) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org


Reply via email to