This is an automated email from the ASF dual-hosted git repository.
jongyoul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/master by this push:
new 65d0bcc1ee [HOTFIX] Escape Ldap search filters (#4714)
65d0bcc1ee is described below
commit 65d0bcc1ee8ec3ec372d0a71ab513cd20e6522a0
Author: Jongyoul Lee <[email protected]>
AuthorDate: Wed Feb 28 00:16:13 2024 +0900
[HOTFIX] Escape Ldap search filters (#4714)
---
.../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>() {