From 8a41f8e361784ae31ec7fca6a1dc9ba6b58b10b1 Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Sat, 17 Feb 2024 23:56:04 +0900 Subject: [PATCH 1/2] [HOTFIX] Escape Ldap search filters --- .../org/apache/zeppelin/realm/LdapRealm.java | 72 ++++++++++++++++++- .../apache/zeppelin/realm/LdapRealmTest.java | 13 ++++ 2 files changed, 83 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 51c92c805af..0da5ba55939 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 String getUserSearchFilter() { } 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 String getGroupSearchFilter() { } 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,74 @@ userSearchAttributeName, expandTemplate(getUserSearchAttributeTemplate(), } } + // Implements the necessary escaping to represent an attribute value as a String as per RFC 4514. + 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 d5e3c6d84fd..9abce28d4b4 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 @@ void testRolesFor() throws NamingException { 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 enumerationOf(BasicAttributes... attrs) { final Iterator iterator = Arrays.asList(attrs).iterator(); return new NamingEnumeration() { From 6e2caa37ab5ec171eccdc46e84ae8fc8aae18d10 Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Sat, 17 Feb 2024 23:56:30 +0900 Subject: [PATCH 2/2] [HOTFIX] Escape Ldap search filters --- .../src/main/java/org/apache/zeppelin/realm/LdapRealm.java | 1 + 1 file changed, 1 insertion(+) 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 0da5ba55939..e1d6d694c73 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 @@ -942,6 +942,7 @@ userSearchAttributeName, expandTemplate(getUserSearchAttributeTemplate(), } // 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;