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

jongyoul pushed a commit to branch branch-0.11
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 75ccdc73ff44c7e6f97d19ab13375313f078f567
Author: Jongyoul Lee <jongy...@gmail.com>
AuthorDate: Wed Feb 28 00:16:13 2024 +0900

    [HOTFIX] Escape Ldap search filters (#4714)
    
    (cherry picked from commit 65d0bcc1ee8ec3ec372d0a71ab513cd20e6522a0)
---
 .../java/org/apache/zeppelin/realm/LdapRealm.java  | 73 +++++++++++++++++++++-
 .../org/apache/zeppelin/realm/LdapRealmTest.java   | 13 ++++
 2 files changed, 84 insertions(+), 2 deletions(-)

diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java
index 51c92c805a..e1d6d694c7 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java
@@ -773,7 +773,7 @@ public class LdapRealm extends DefaultLdapRealm {
   }
 
   public void setUserSearchFilter(final String filter) {
-    this.userSearchFilter = (filter == null ? null : filter.trim());
+    this.userSearchFilter = (filter == null ? null : 
escapeAttributeValue(filter.trim()));
   }
 
   public String getGroupSearchFilter() {
@@ -781,7 +781,7 @@ public class LdapRealm extends DefaultLdapRealm {
   }
 
   public void setGroupSearchFilter(final String filter) {
-    this.groupSearchFilter = (filter == null ? null : filter.trim());
+    this.groupSearchFilter = (filter == null ? null : 
escapeAttributeValue(filter.trim()));
   }
 
   public boolean getUserLowerCase() {
@@ -941,6 +941,75 @@ public class LdapRealm extends DefaultLdapRealm {
     }
   }
 
+  // Implements the necessary escaping to represent an attribute value as a 
String as per RFC 4514.
+  // 
https://github.com/apache/tomcat/blob/main/java/org/apache/catalina/realm/JNDIRealm.java#L2921
+  protected String escapeAttributeValue(String input) {
+    if (input == null) {
+      return null;
+    }
+    int len = input.length();
+    StringBuilder result = new StringBuilder();
+
+    for (int i = 0; i < len; i++) {
+      char c = input.charAt(i);
+      switch (c) {
+        case ' ': {
+          if (i == 0 || i == (len - 1)) {
+            result.append("\\20");
+          } else {
+            result.append(c);
+          }
+          break;
+        }
+        case '#': {
+          if (i == 0) {
+            result.append("\\23");
+          } else {
+            result.append(c);
+          }
+          break;
+        }
+        case '\"': {
+          result.append("\\22");
+          break;
+        }
+        case '+': {
+          result.append("\\2B");
+          break;
+        }
+        case ',': {
+          result.append("\\2C");
+          break;
+        }
+        case ';': {
+          result.append("\\3B");
+          break;
+        }
+        case '<': {
+          result.append("\\3C");
+          break;
+        }
+        case '>': {
+          result.append("\\3E");
+          break;
+        }
+        case '\\': {
+          result.append("\\5C");
+          break;
+        }
+        case '\u0000': {
+          result.append("\\00");
+          break;
+        }
+        default:
+          result.append(c);
+      }
+    }
+
+    return result.toString();
+  }
+
+
   @Override
   protected AuthenticationInfo createAuthenticationInfo(AuthenticationToken 
token,
       Object ldapPrincipal, Object ldapCredentials, LdapContext ldapContext)
diff --git 
a/zeppelin-server/src/test/java/org/apache/zeppelin/realm/LdapRealmTest.java 
b/zeppelin-server/src/test/java/org/apache/zeppelin/realm/LdapRealmTest.java
index d5e3c6d84f..9abce28d4b 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/realm/LdapRealmTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/realm/LdapRealmTest.java
@@ -119,6 +119,19 @@ class LdapRealmTest {
     assertEquals(new HashSet<>(Arrays.asList("group-one", "zeppelin-role")), 
roles);
   }
 
+  @Test
+  void testFilterEscaping() {
+    LdapRealm realm = new LdapRealm();
+    assertEquals("foo", realm.escapeAttributeValue("foo"));
+    assertEquals("foo\\2B", realm.escapeAttributeValue("foo+"));
+    assertEquals("foo\\5C", realm.escapeAttributeValue("foo\\"));
+    assertEquals("foo\\00", realm.escapeAttributeValue("foo\u0000"));
+    realm.setUserSearchFilter("uid=<{0}>");
+    assertEquals("uid=\\3C{0}\\3E", realm.getUserSearchFilter());
+    realm.setUserSearchFilter("gid=\\{0}\\");
+    assertEquals("gid=\\5C{0}\\5C", realm.getUserSearchFilter());
+  }
+
   private NamingEnumeration<SearchResult> enumerationOf(BasicAttributes... 
attrs) {
     final Iterator<BasicAttributes> iterator = Arrays.asList(attrs).iterator();
     return new NamingEnumeration<SearchResult>() {

Reply via email to