You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by ki...@apache.org on 2026/04/13 08:57:58 UTC
(doris) branch master updated: [feat](plugin) Support multi-root auth plugin loading and normalize OIDC access token auth (#62159)
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 3de6d44e433 [feat](plugin) Support multi-root auth plugin loading and normalize OIDC access token auth (#62159)
3de6d44e433 is described below
commit 3de6d44e43305e559f2e0f38ec377a210cf6fb2c
Author: Calvin Kirs <gu...@selectdb.com>
AuthorDate: Mon Apr 13 16:57:49 2026 +0800
[feat](plugin) Support multi-root auth plugin loading and normalize OIDC access token auth (#62159)
https://github.com/apache/doris/issues/60361
Problem Summary:
FE authentication plugin loading currently assumes a single plugin root
in several runtime paths, which makes
external plugin deployment less flexible and inconsistent across
callers.
In addition, OIDC token-based authentication uses inconsistent
credential typing across MySQL authentication and
authentication_chain fallback flows, and the client-visible error
message handling is not aligned with access-token-
specific failures.
This change makes plugin root parsing reusable across FE runtime paths,
allows configuring multiple authentication
or authorization plugin roots with a comma-separated list, normalizes
OIDC access token requests to use
`OAUTH_TOKEN`, broadens OIDC request detection in fallback
authentication flow, and aligns access-token-related
failure messages. It also marks `authentication_chain` as mutable so the
fallback chain can be adjusted dynamically.
---
.../main/java/org/apache/doris/common/Config.java | 8 ++-
.../AuthenticationIntegrationRuntime.java | 9 ++-
.../apache/doris/common/util/ClassLoaderUtils.java | 80 ++++++++++++++--------
.../mysql/authenticate/AuthenticatorManager.java | 6 +-
.../MysqlAuthPacketCredentialExtractor.java | 2 +-
.../AuthenticationIntegrationAuthenticator.java | 8 ++-
.../plugin/AuthenticationPluginAuthenticator.java | 16 +++--
.../AuthenticationIntegrationRuntimeTest.java | 25 +++++++
.../authenticate/AuthenticatorManagerTest.java | 8 +--
.../MysqlAuthPacketCredentialExtractorTest.java | 4 +-
.../AuthenticationPluginAuthenticatorTest.java | 26 ++++++-
11 files changed, 136 insertions(+), 56 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 f503b2a05fa..724d1eb044d 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
@@ -2797,7 +2797,7 @@ public class Config extends ConfigBase {
options = {"default", "password", "ldap", "<plugin_name>"})
public static String authentication_type = "default";
- @ConfField(description = {
+ @ConfField(mutable = true, description = {
"Specifies the authentication chain used after primary authentication failure, "
+ "multiple integration names are comma-separated"})
public static String authentication_chain = "";
@@ -3463,10 +3463,12 @@ public class Config extends ConfigBase {
+ "detailed information of all replicas of the tablet will be printed."})
public static boolean sql_block_rule_ignore_admin = false;
- @ConfField(description = {"Authentication plugin directory."})
+ @ConfField(description = {"Authentication plugin root directories. Use a comma-separated list to configure "
+ + "multiple roots."})
public static String authentication_plugins_dir = EnvUtils.getDorisHome() + "/plugins/authentication";
- @ConfField(description = {"Authorization plugin directory."})
+ @ConfField(description = {"Authorization plugin root directories. Use a comma-separated list to configure "
+ + "multiple roots."})
public static String authorization_plugins_dir = EnvUtils.getDorisHome() + "/plugins/authorization";
@ConfField(description = {"Security plugin directory."})
diff --git a/fe/fe-core/src/main/java/org/apache/doris/authentication/AuthenticationIntegrationRuntime.java b/fe/fe-core/src/main/java/org/apache/doris/authentication/AuthenticationIntegrationRuntime.java
index 9d9a63fb695..d3eb2a1747a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/authentication/AuthenticationIntegrationRuntime.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/authentication/AuthenticationIntegrationRuntime.java
@@ -25,6 +25,7 @@ import org.apache.doris.authentication.rolemapping.RoleMappingEvaluator;
import org.apache.doris.authentication.spi.AuthenticationPlugin;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.Config;
+import org.apache.doris.common.util.ClassLoaderUtils;
import com.google.common.base.Strings;
import org.apache.logging.log4j.LogManager;
@@ -32,9 +33,6 @@ import org.apache.logging.log4j.Logger;
import java.io.Closeable;
import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -293,8 +291,9 @@ public class AuthenticationIntegrationRuntime {
}
try {
- Path pluginRoot = Paths.get(Config.authentication_plugins_dir);
- pluginManager.loadAll(Collections.singletonList(pluginRoot), getClass().getClassLoader());
+ pluginManager.loadAll(
+ ClassLoaderUtils.parsePluginRootDirectories(Config.authentication_plugins_dir),
+ getClass().getClassLoader());
} catch (AuthenticationException e) {
throw new AuthenticationException(
"Failed to load authentication plugins for type '" + pluginType + "': " + e.getMessage(),
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
index 97be2a5ad9e..91d5762c7fd 100644
--- 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
@@ -21,6 +21,7 @@ import org.apache.doris.common.Config;
import org.apache.doris.mysql.authenticate.AuthenticatorFactory;
import org.apache.doris.mysql.privilege.AccessControllerFactory;
+import com.google.common.base.Splitter;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -29,10 +30,15 @@ import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
/**
* Utility class for loading service implementations from external JAR files in specific plugin directories.
@@ -61,11 +67,24 @@ import java.util.ServiceLoader;
public class ClassLoaderUtils {
private static final Logger LOG = LogManager.getLogger(ClassLoaderUtils.class);
// A mapping of service class simple names to their respective plugin directories.
- private static final Map<String, String> pluginDirMapping = new HashedMap();
+ private static final Map<String, Supplier<String>> pluginDirMapping = new HashedMap<>();
static {
- pluginDirMapping.put(AuthenticatorFactory.class.getSimpleName(), Config.authentication_plugins_dir);
- pluginDirMapping.put(AccessControllerFactory.class.getSimpleName(), Config.authorization_plugins_dir);
+ pluginDirMapping.put(AuthenticatorFactory.class.getSimpleName(), () -> Config.authentication_plugins_dir);
+ pluginDirMapping.put(AccessControllerFactory.class.getSimpleName(), () -> Config.authorization_plugins_dir);
+ }
+
+ public static List<Path> parsePluginRootDirectories(String pluginRootsConfig) {
+ if (pluginRootsConfig == null) {
+ return Collections.emptyList();
+ }
+ return Splitter.on(',')
+ .trimResults()
+ .omitEmptyStrings()
+ .splitToList(pluginRootsConfig)
+ .stream()
+ .map(Paths::get)
+ .collect(Collectors.toList());
}
/**
@@ -87,38 +106,45 @@ public class ClassLoaderUtils {
*/
public static <T> List<T> loadServicesFromDirectory(Class<T> serviceClass) throws IOException {
String pluginDirKey = serviceClass.getSimpleName();
- String pluginDir = pluginDirMapping.get(pluginDirKey);
- if (pluginDir == null) {
+ Supplier<String> pluginDirSupplier = pluginDirMapping.get(pluginDirKey);
+ if (pluginDirSupplier == 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) {
- LOG.info("No JAR files found in the plugin directory: {}", pluginDir);
+ List<Path> pluginRoots = parsePluginRootDirectories(pluginDirSupplier.get());
+ if (pluginRoots.isEmpty()) {
return new ArrayList<>();
}
List<T> services = new ArrayList<>();
- for (File jarFile : jarFiles) {
- URL[] jarURLs;
- jarURLs = new URL[]{jarFile.toURI().toURL()};
+ for (Path pluginRoot : pluginRoots) {
+ File jarDir = pluginRoot.toFile();
+ // If the directory does not exist, skip it.
+ if (!jarDir.exists()) {
+ continue;
+ }
+ if (!jarDir.isDirectory()) {
+ throw new IOException("The specified path is not a directory: " + pluginRoot);
+ }
+
+ File[] jarFiles = jarDir.listFiles((dir, name) -> name.endsWith(".jar"));
+ if (jarFiles == null || jarFiles.length == 0) {
+ LOG.info("No JAR files found in the plugin directory: {}", pluginRoot);
+ continue;
+ }
+
+ 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);
+ 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);
}
- } 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 ea6173ec527..cb5a63dc43e 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
@@ -305,7 +305,9 @@ public class AuthenticatorManager {
}
private boolean isOidcAuthenticateRequest(AuthenticateRequest request) {
- if (CredentialType.OIDC_ID_TOKEN.equals(request.getCredentialType())) {
+ if (CredentialType.OIDC_ID_TOKEN.equals(request.getCredentialType())
+ || CredentialType.OAUTH_TOKEN.equals(request.getCredentialType())
+ || CredentialType.JWT_TOKEN.equals(request.getCredentialType())) {
return true;
}
if (!(request.getPassword() instanceof ClearPassword)) {
@@ -355,7 +357,7 @@ public class AuthenticatorManager {
.remoteHost(primaryRequest.getRemoteHost())
.remotePort(primaryRequest.getRemotePort())
.clientType(primaryRequest.getClientType())
- .credentialType(CredentialType.OIDC_ID_TOKEN)
+ .credentialType(CredentialType.OAUTH_TOKEN)
.credential(clearPassword.getPassword().getBytes(StandardCharsets.UTF_8))
.properties(primaryRequest.getProperties())
.build();
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/MysqlAuthPacketCredentialExtractor.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/MysqlAuthPacketCredentialExtractor.java
index c9f94024aa7..443515702ed 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/MysqlAuthPacketCredentialExtractor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/MysqlAuthPacketCredentialExtractor.java
@@ -54,7 +54,7 @@ public class MysqlAuthPacketCredentialExtractor {
.password(new ClearPassword(token))
.remoteHost(channel.getRemoteIp())
.clientType("mysql")
- .credentialType(CredentialType.OIDC_ID_TOKEN)
+ .credentialType(CredentialType.OAUTH_TOKEN)
.credential(oidcToken)
.build());
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/integration/AuthenticationIntegrationAuthenticator.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/integration/AuthenticationIntegrationAuthenticator.java
index b53103eb240..4d3104f75a1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/integration/AuthenticationIntegrationAuthenticator.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/integration/AuthenticationIntegrationAuthenticator.java
@@ -225,10 +225,12 @@ public class AuthenticationIntegrationAuthenticator implements Authenticator {
return "";
}
String detailMessage = Strings.nullToEmpty(exception.getMessage());
- if (detailMessage.startsWith("OIDC token signature validation failed")) {
- return "OIDC token signature validation failed";
+ if (detailMessage.startsWith("OIDC access token signature validation failed")) {
+ return "OIDC access token signature validation failed";
}
- if (detailMessage.startsWith("OIDC token ")
+ if (detailMessage.startsWith("OIDC access token ")
+ || detailMessage.startsWith("OIDC token ")
+ || "Authentication request username does not match OIDC access token username".equals(detailMessage)
|| "Authentication request username does not match OIDC token username".equals(detailMessage)) {
return detailMessage;
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/plugin/AuthenticationPluginAuthenticator.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/plugin/AuthenticationPluginAuthenticator.java
index f05f4dbbce7..ff61bde349c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/plugin/AuthenticationPluginAuthenticator.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/plugin/AuthenticationPluginAuthenticator.java
@@ -29,6 +29,7 @@ import org.apache.doris.authentication.handler.AuthenticationPluginManager;
import org.apache.doris.authentication.spi.AuthenticationPlugin;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.Config;
+import org.apache.doris.common.util.ClassLoaderUtils;
import org.apache.doris.mysql.authenticate.AuthenticateRequest;
import org.apache.doris.mysql.authenticate.AuthenticateResponse;
import org.apache.doris.mysql.authenticate.AuthenticationFailureSummary;
@@ -49,8 +50,6 @@ import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -202,8 +201,9 @@ public class AuthenticationPluginAuthenticator implements Authenticator {
return;
}
try {
- Path pluginRoot = Paths.get(Config.authentication_plugins_dir);
- pluginManager.loadAll(Collections.singletonList(pluginRoot), getClass().getClassLoader());
+ pluginManager.loadAll(
+ ClassLoaderUtils.parsePluginRootDirectories(Config.authentication_plugins_dir),
+ getClass().getClassLoader());
} catch (AuthenticationException e) {
throw new AuthenticationException(
"Failed to load authentication plugin for type '" + pluginType + "': " + e.getMessage(),
@@ -228,10 +228,12 @@ public class AuthenticationPluginAuthenticator implements Authenticator {
return "";
}
String detailMessage = Strings.nullToEmpty(exception.getMessage());
- if (detailMessage.startsWith("OIDC token signature validation failed")) {
- return "OIDC token signature validation failed";
+ if (detailMessage.startsWith("OIDC access token signature validation failed")) {
+ return "OIDC access token signature validation failed";
}
- if (detailMessage.startsWith("OIDC token ")
+ if (detailMessage.startsWith("OIDC access token ")
+ || detailMessage.startsWith("OIDC token ")
+ || "Authentication request username does not match OIDC access token username".equals(detailMessage)
|| "Authentication request username does not match OIDC token username".equals(detailMessage)) {
return detailMessage;
}
diff --git a/fe/fe-core/src/test/java/org/apache/doris/authentication/AuthenticationIntegrationRuntimeTest.java b/fe/fe-core/src/test/java/org/apache/doris/authentication/AuthenticationIntegrationRuntimeTest.java
index 1edeeb46958..72ba74428a0 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/authentication/AuthenticationIntegrationRuntimeTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/authentication/AuthenticationIntegrationRuntimeTest.java
@@ -27,10 +27,13 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -43,15 +46,18 @@ import java.util.Set;
class AuthenticationIntegrationRuntimeTest {
private static final String CREATE_USER = "creator";
private MockedStatic<Env> envMockedStatic;
+ private String originalAuthenticationPluginsDir;
@BeforeEach
void setUp() {
envMockedStatic = Mockito.mockStatic(Env.class);
envMockedStatic.when(Env::getCurrentEnv).thenReturn(null);
+ originalAuthenticationPluginsDir = org.apache.doris.common.Config.authentication_plugins_dir;
}
@AfterEach
void tearDown() {
+ org.apache.doris.common.Config.authentication_plugins_dir = originalAuthenticationPluginsDir;
if (envMockedStatic != null) {
envMockedStatic.close();
}
@@ -272,6 +278,25 @@ class AuthenticationIntegrationRuntimeTest {
runtime.getRuntimeState("corp"));
}
+ @Test
+ void testPrepareAuthenticationIntegrationLoadsPluginFactoriesFromMultipleRoots() throws Exception {
+ org.apache.doris.common.Config.authentication_plugins_dir = "/tmp/auth-root-a, /tmp/auth-root-b";
+ AuthenticationPluginManager pluginManager = Mockito.mock(AuthenticationPluginManager.class);
+ AuthenticationPlugin plugin = Mockito.mock(AuthenticationPlugin.class);
+ Mockito.when(pluginManager.hasFactory("multi-root")).thenReturn(false, true);
+ Mockito.when(pluginManager.createPlugin(Mockito.any())).thenReturn(plugin);
+
+ AuthenticationIntegrationRuntime runtime = new AuthenticationIntegrationRuntime(pluginManager);
+ runtime.prepareAuthenticationIntegration(meta("corp", "multi-root", Collections.emptyMap()));
+
+ @SuppressWarnings("unchecked")
+ ArgumentCaptor<List<Path>> pluginRootsCaptor = ArgumentCaptor.forClass((Class) List.class);
+ Mockito.verify(pluginManager).loadAll(pluginRootsCaptor.capture(), Mockito.any());
+ Assertions.assertEquals(
+ Arrays.asList(Paths.get("/tmp/auth-root-a"), Paths.get("/tmp/auth-root-b")),
+ pluginRootsCaptor.getValue());
+ }
+
private static AuthenticationIntegrationMeta meta(String name, String type, Map<String, String> properties)
throws Exception {
Map<String, String> createProperties = new LinkedHashMap<>();
diff --git a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/AuthenticatorManagerTest.java b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/AuthenticatorManagerTest.java
index a989de3e8ab..a12923d14f1 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/AuthenticatorManagerTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/AuthenticatorManagerTest.java
@@ -536,7 +536,7 @@ class AuthenticatorManagerTest {
Assertions.assertTrue(result);
ArgumentCaptor<AuthenticateRequest> requestCaptor = ArgumentCaptor.forClass(AuthenticateRequest.class);
Mockito.verify(chainAuthenticator).authenticate(requestCaptor.capture());
- Assertions.assertEquals(CredentialType.OIDC_ID_TOKEN, requestCaptor.getValue().getCredentialType());
+ Assertions.assertEquals(CredentialType.OAUTH_TOKEN, requestCaptor.getValue().getCredentialType());
Assertions.assertArrayEquals("oidc-token".getBytes(StandardCharsets.UTF_8),
requestCaptor.getValue().getCredential());
}
@@ -554,7 +554,7 @@ class AuthenticatorManagerTest {
.password(new ClearPassword(OIDC_ID_TOKEN))
.remoteHost(REMOTE_IP)
.clientType("mysql")
- .credentialType(CredentialType.OIDC_ID_TOKEN)
+ .credentialType(CredentialType.OAUTH_TOKEN)
.credential(OIDC_ID_TOKEN.getBytes(StandardCharsets.UTF_8))
.build()));
@@ -605,7 +605,7 @@ class AuthenticatorManagerTest {
.password(new ClearPassword(OIDC_ID_TOKEN))
.remoteHost(REMOTE_IP)
.clientType("mysql")
- .credentialType(CredentialType.OIDC_ID_TOKEN)
+ .credentialType(CredentialType.OAUTH_TOKEN)
.credential(OIDC_ID_TOKEN.getBytes(StandardCharsets.UTF_8))
.build()));
@@ -731,7 +731,7 @@ class AuthenticatorManagerTest {
ArgumentCaptor<AuthenticateRequest> requestCaptor = ArgumentCaptor.forClass(AuthenticateRequest.class);
Mockito.verify(chainAuthenticator).authenticate(requestCaptor.capture());
AuthenticateRequest chainRequest = requestCaptor.getValue();
- Assertions.assertEquals(CredentialType.OIDC_ID_TOKEN, chainRequest.getCredentialType());
+ Assertions.assertEquals(CredentialType.OAUTH_TOKEN, chainRequest.getCredentialType());
Assertions.assertArrayEquals(originalOidcToken, chainRequest.getCredential());
Assertions.assertInstanceOf(ClearPassword.class, chainRequest.getPassword());
Assertions.assertEquals("oidc-token", ((ClearPassword) chainRequest.getPassword()).getPassword());
diff --git a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/MysqlAuthPacketCredentialExtractorTest.java b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/MysqlAuthPacketCredentialExtractorTest.java
index fc4bffe56e4..acb6c7790a1 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/MysqlAuthPacketCredentialExtractorTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/MysqlAuthPacketCredentialExtractorTest.java
@@ -56,7 +56,7 @@ class MysqlAuthPacketCredentialExtractorTest {
AuthenticateRequest request = extractor.extractAuthenticateRequest(USER_NAME, channel, authPacket)
.orElseThrow(() -> new AssertionError("request is required"));
- Assertions.assertEquals(CredentialType.OIDC_ID_TOKEN, request.getCredentialType());
+ Assertions.assertEquals(CredentialType.OAUTH_TOKEN, request.getCredentialType());
Assertions.assertArrayEquals("token-from-client".getBytes(StandardCharsets.UTF_8), request.getCredential());
Assertions.assertInstanceOf(ClearPassword.class, request.getPassword());
Assertions.assertEquals("token-from-client", ((ClearPassword) request.getPassword()).getPassword());
@@ -75,7 +75,7 @@ class MysqlAuthPacketCredentialExtractorTest {
AuthenticateRequest request = extractor.extractAuthenticateRequest(USER_NAME, channel, authPacket)
.orElseThrow(() -> new AssertionError("request is required"));
- Assertions.assertEquals(CredentialType.OIDC_ID_TOKEN, request.getCredentialType());
+ Assertions.assertEquals(CredentialType.OAUTH_TOKEN, request.getCredentialType());
Assertions.assertArrayEquals(token.getBytes(StandardCharsets.UTF_8), request.getCredential());
Assertions.assertInstanceOf(ClearPassword.class, request.getPassword());
Assertions.assertEquals(token, ((ClearPassword) request.getPassword()).getPassword());
diff --git a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/plugin/AuthenticationPluginAuthenticatorTest.java b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/plugin/AuthenticationPluginAuthenticatorTest.java
index 86dc1642d3a..af012aeb2ac 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/plugin/AuthenticationPluginAuthenticatorTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/plugin/AuthenticationPluginAuthenticatorTest.java
@@ -41,8 +41,12 @@ import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
class AuthenticationPluginAuthenticatorTest {
@@ -51,6 +55,7 @@ class AuthenticationPluginAuthenticatorTest {
private AuthenticationPluginManager pluginManager;
private AuthenticationPlugin plugin;
private MockedStatic<Env> envMockedStatic;
+ private String originalAuthenticationPluginsDir;
private static final String USER_NAME = "alice";
private static final String REMOTE_IP = "127.0.0.1";
@@ -62,6 +67,7 @@ class AuthenticationPluginAuthenticatorTest {
auth = Mockito.mock(Auth.class);
pluginManager = Mockito.mock(AuthenticationPluginManager.class);
plugin = Mockito.mock(AuthenticationPlugin.class);
+ originalAuthenticationPluginsDir = org.apache.doris.common.Config.authentication_plugins_dir;
envMockedStatic = Mockito.mockStatic(Env.class);
envMockedStatic.when(Env::getCurrentEnv).thenReturn(env);
@@ -134,7 +140,7 @@ class AuthenticationPluginAuthenticatorTest {
authPacket,
handshakePacket).orElseThrow(() -> new AssertionError("request is required"));
- Assertions.assertEquals(CredentialType.OIDC_ID_TOKEN, request.getCredentialType());
+ Assertions.assertEquals(CredentialType.OAUTH_TOKEN, request.getCredentialType());
Assertions.assertArrayEquals("token-from-client".getBytes(StandardCharsets.UTF_8), request.getCredential());
AuthenticateResponse response = authenticator.authenticate(request);
@@ -142,13 +148,29 @@ class AuthenticationPluginAuthenticatorTest {
ArgumentCaptor<AuthenticationRequest> requestCaptor = ArgumentCaptor.forClass(AuthenticationRequest.class);
Mockito.verify(plugin).authenticate(requestCaptor.capture(), Mockito.any());
- Assertions.assertEquals(CredentialType.OIDC_ID_TOKEN, requestCaptor.getValue().getCredentialType());
+ Assertions.assertEquals(CredentialType.OAUTH_TOKEN, requestCaptor.getValue().getCredentialType());
Assertions.assertArrayEquals("token-from-client".getBytes(StandardCharsets.UTF_8),
requestCaptor.getValue().getCredential());
}
+ @Test
+ void testEnsurePluginFactoryLoadedSupportsMultiplePluginRoots() throws Exception {
+ org.apache.doris.common.Config.authentication_plugins_dir = "/tmp/auth-root-a, /tmp/auth-root-b";
+ Mockito.when(pluginManager.hasFactory("oidc")).thenReturn(false, true);
+
+ new AuthenticationPluginAuthenticator("oidc", new HashMap<>(), pluginManager);
+
+ @SuppressWarnings("unchecked")
+ ArgumentCaptor<List<Path>> pluginRootsCaptor = ArgumentCaptor.forClass((Class) List.class);
+ Mockito.verify(pluginManager).loadAll(pluginRootsCaptor.capture(), Mockito.any());
+ Assertions.assertEquals(
+ Arrays.asList(Paths.get("/tmp/auth-root-a"), Paths.get("/tmp/auth-root-b")),
+ pluginRootsCaptor.getValue());
+ }
+
@AfterEach
void tearDown() {
+ org.apache.doris.common.Config.authentication_plugins_dir = originalAuthenticationPluginsDir;
if (envMockedStatic != null) {
envMockedStatic.close();
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org