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

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new 5e6a7724abc [fix](ldap) Replace custom LDAP filter escaping with 
`LdapEncoder.filterEncode` to prevent injection vulnerabilities and add related 
documentation. (#61662) (#61777)
5e6a7724abc is described below

commit 5e6a7724abc326633035a7d6bfe2cee4bc2aa2a0
Author: seawinde <[email protected]>
AuthorDate: Fri Mar 27 09:42:41 2026 +0800

    [fix](ldap) Replace custom LDAP filter escaping with 
`LdapEncoder.filterEncode` to prevent injection vulnerabilities and add related 
documentation. (#61662) (#61777)
    
    pick from #61662
---
 .../doris/mysql/authenticate/ldap/LdapClient.java  | 18 +++++++------
 .../mysql/authenticate/ldap/LdapClientTest.java    | 30 ++++++++++++++++++++++
 2 files changed, 40 insertions(+), 8 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/ldap/LdapClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/ldap/LdapClient.java
index 79248ab0212..5d03917f0d3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/ldap/LdapClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/authenticate/ldap/LdapClient.java
@@ -25,7 +25,6 @@ import org.apache.doris.common.util.NetUtils;
 import org.apache.doris.common.util.SymmetricEncryption;
 import org.apache.doris.persist.LdapInfo;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.Lists;
 import lombok.Data;
 import org.apache.logging.log4j.LogManager;
@@ -37,6 +36,7 @@ import 
org.springframework.ldap.core.support.LdapContextSource;
 import org.springframework.ldap.pool.factory.PoolingContextSource;
 import org.springframework.ldap.pool.validation.DefaultDirContextValidator;
 import org.springframework.ldap.query.LdapQuery;
+import org.springframework.ldap.support.LdapEncoder;
 import 
org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy;
 
 import java.util.List;
@@ -146,7 +146,7 @@ public class LdapClient {
         try {
             
clientInfo.getLdapTemplateNoPool().authenticate(org.springframework.ldap.query.LdapQueryBuilder.query()
                     .base(LdapConfig.ldap_user_basedn)
-                    .filter(getUserFilter(LdapConfig.ldap_user_filter, 
userName)), password);
+                    .filter(applyLoginFilter(LdapConfig.ldap_user_filter, 
userName)), password);
             return true;
         } catch (Exception e) {
             LOG.info("ldap client checkPassword failed, userName: {}", 
userName, e);
@@ -167,7 +167,7 @@ public class LdapClient {
         List<String> groupDns;
         if (!LdapConfig.ldap_group_filter.isEmpty()) {
             // Support Open Directory implementations
-            String filter = LdapConfig.ldap_group_filter.replace("{login}", 
userName);
+            String filter = applyLoginFilter(LdapConfig.ldap_group_filter, 
userName);
             groupDns = 
getDn(org.springframework.ldap.query.LdapQueryBuilder.query()
                     .attributes("dn")
                     .base(LdapConfig.ldap_group_basedn)
@@ -195,13 +195,13 @@ public class LdapClient {
 
     private String getUserDn(String userName) {
         List<String> userDns = 
getDn(org.springframework.ldap.query.LdapQueryBuilder.query()
-                
.base(LdapConfig.ldap_user_basedn).filter(getUserFilter(LdapConfig.ldap_user_filter,
 userName)));
+                
.base(LdapConfig.ldap_user_basedn).filter(applyLoginFilter(LdapConfig.ldap_user_filter,
 userName)));
         if (userDns == null || userDns.isEmpty()) {
             return null;
         }
         if (userDns.size() > 1) {
             String msg = String.format("[%s] not unique in LDAP server: [%s]",
-                    getUserFilter(LdapConfig.ldap_user_filter, userName), 
userDns);
+                    applyLoginFilter(LdapConfig.ldap_user_filter, userName), 
userDns);
             LOG.error(msg);
             ErrorReport.report(ErrorCode.ERROR_LDAP_USER_NOT_UNIQUE_ERR, 
userName);
             throw new RuntimeException(msg);
@@ -209,7 +209,6 @@ public class LdapClient {
         return userDns.get(0);
     }
 
-    @VisibleForTesting
     public List<String> getDn(LdapQuery query) {
         init();
         try {
@@ -229,7 +228,10 @@ public class LdapClient {
         }
     }
 
-    private String getUserFilter(String userFilter, String userName) {
-        return userFilter.replaceAll("\\{login}", userName);
+    private String applyLoginFilter(String filter, String userName) {
+        if (filter == null) {
+            return null;
+        }
+        return filter.replace("{login}", LdapEncoder.filterEncode(userName));
     }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/ldap/LdapClientTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/ldap/LdapClientTest.java
index c0d6c36f83b..7790816856f 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/ldap/LdapClientTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/ldap/LdapClientTest.java
@@ -28,6 +28,7 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.springframework.ldap.query.LdapQuery;
+import org.springframework.ldap.support.LdapEncoder;
 
 import java.util.Arrays;
 import java.util.List;
@@ -118,6 +119,35 @@ public class LdapClientTest {
                           secureUrl.startsWith("ldaps://"));
     }
 
+    @Test
+    public void testLdapFilterEncoding() {
+        // Combined special characters
+        String input = "test*()\\\u0000";
+        String expected = "test\\2a\\28\\29\\5c\\00";
+        Assert.assertEquals(expected, LdapEncoder.filterEncode(input));
+
+        // Null input
+        Assert.assertNull(LdapEncoder.filterEncode(null));
+
+        // Normal username should not be altered
+        Assert.assertEquals("zhangsan", LdapEncoder.filterEncode("zhangsan"));
+        Assert.assertEquals("[email protected]", 
LdapEncoder.filterEncode("[email protected]"));
+
+        // Empty string
+        Assert.assertEquals("", LdapEncoder.filterEncode(""));
+
+        // Each special character individually
+        Assert.assertEquals("\\2a", LdapEncoder.filterEncode("*"));
+        Assert.assertEquals("\\28", LdapEncoder.filterEncode("("));
+        Assert.assertEquals("\\29", LdapEncoder.filterEncode(")"));
+        Assert.assertEquals("\\5c", LdapEncoder.filterEncode("\\"));
+        Assert.assertEquals("\\00", LdapEncoder.filterEncode("\u0000"));
+
+        // Injection payload: dorisuser6)(mail=testp*
+        Assert.assertEquals("dorisuser6\\29\\28mail=testp\\2a",
+                LdapEncoder.filterEncode("dorisuser6)(mail=testp*"));
+    }
+
     @After
     public void tearDown() {
         LdapConfig.ldap_use_ssl = false; // restoring default value for other 
tests


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

Reply via email to