ejb服务将ldap过滤器作为字符串,并从ActiveDirectory返回结果。
问题是,有时属性值包含需要为整个过滤器转义的特殊字符,如下所示:
https://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx
对于此处指定的专有名称属性值:
https://msdn.microsoft.com/en-us/library/aa366101(v=vs.85).aspx
为了实现这一目标,服务必须执行以下操作:
Java native javax.naming.ldap.Rdn
可以转义dn值,但不是幂等的。至于其他任务,到目前为止,我一直无法找到一个允许我完成它们的库。
现在我倾向于认为逃避ldap过滤器的工作应该由服务的用户而不是服务本身完成,因为服务很难告诉逃脱实际价值。此外,在没有经过良好测试的库的情况下解析复杂的字符串(如ldap过滤器)似乎很容易出错。
有关如何解决这个问题的任何想法?这个任务可以自动完成吗?
答案 0 :(得分:4)
对于转义LDAP过滤器,我依靠此页面编写以下代码:http://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx#Special_Characters
String LdapEscape(String ldap)
{
if(ldap == null) return "";
return ldap.replace("\\", "\\5C").replace("*", "\\2A").replace("(", "\\28").replace(")", "\\29").replace("\000", "\\00");
}
这里要记住的最重要的事情是,必须首先用\
替换\5C
,这样才不会双重转义任何字符。否则它非常简单;没有任何特殊的技巧需要注意。
我想指出,这是为了逃避LDAP过滤器中的个别值,而不是整个LDAP过滤器。但是,如果您愿意,可以使用该函数来逃避这样的事情,以便搜索:
LdapEscape("(!(sn=m*))"); // \28!\28sn=m\2A\29
答案 1 :(得分:3)
冥王星的答案非常简洁,但非ASCII UTF-8字符(例如é,á,ö等)也需要特殊处理。这是我详细的解决方案。
/**
* Filter components need to escape special chars.
* Note that each piece of the filter needs to be escaped,
* not the whole filter expression, for example:
*
* "(&(cn="+ esc("Admins") +")(member="+ esc("CN=Doe\\, Jöhn,OU=ImPeople,DC=ds,DC=augur,DC=com") +"))"
*
* @see Oracle Directory Server Enterprise Edition 11g Reference doc
* @see http://docs.oracle.com/cd/E29127_01/doc.111170/e28969/ds-ldif-search-filters.htm#gdxoy
* @param s A String field within the search expression
* @return The escaped string, safe for use in the search expression.
*/
public static String esc(String s)
{
if(s == null) return "";
StringBuilder sb = new StringBuilder(s.length());
for (byte c : s.getBytes(StandardCharsets.UTF_8))
{
if (c=='\\') { sb.append("\\5c"); }
else if (c=='*') { sb.append("\\2a"); }
else if (c=='(') { sb.append("\\28"); }
else if (c==')') { sb.append("\\29"); }
else if (c==0) { sb.append("\\00"); }
else if ((c&0xff)>127) { sb.append("\\").append(to2CharHexString((c&0xff))); } // UTF-8's non-7-bit characters, e.g. é, á, etc...
else { sb.append((char)c); }
}
return sb.toString();
}
/**
* @return The least significant 16 bits as a two-character hex string,
* padded by a leading '0' if necessary.
*/
public static String to2CharHexString(int i)
{
String s = Integer.toHexString(i & 0xff);
if (s.length()==1) return "0"+s;
else return s;
}
答案 2 :(得分:0)
如果调用方提供的LDAP过滤器代表用于查询的最终过滤器,则无法可靠地对其进行转义。考虑以下由调用者组装的过滤器:
String value = "*)(objectClass=*";
String filter = "(|(attr1=constvalue)(attr2=" + value + "))";
search(filter);
由于代码未转义value
,因此结果过滤器匹配所有对象:
(|(attr1=constvalue)(attr2=*)(objectClass=*))
由于无法再标识开始和结束位置,因此无法基于最终过滤器对value
进行转义。
要解决此歧义和过滤器注入问题,必须在构建过滤器时对输入值进行转义,而不是在随后进行。但是,这并不意味着调用方必须直接处理转义的详细信息-容易出错,因此我不建议这样做。
EJB处理转义所需的全部工作是知道所需的过滤器,包括占位符,而不是实际值和值列表。 Java的DirContext
已经提供了一种可以利用的机制。 DirContext.search
具有一个filterExpr
参数,该参数表示可以包含占位符的过滤器模板,一个filterArgs
参数表示一个对应值的列表。
这样,上面的示例将变为:
String value = "*)(objectClass=*";
String filter = "(|(attr1=constvalue)(attr2={0}))";
search(filter, new String[] { value });
search
的实现:
dircontext.search(basedn, filter, valuearray, null);
这是我能想到的最佳折衷方案。它完全解决了LDAP过滤器注入问题,但不需要调用者处理转义,调用者仅需提供过滤器模板和值列表即可。
通常,应优先使用库功能进行转义,而不是使用自定义代码,以确保正确处理所有情况。其他两个答案说明了这一点。
答案 3 :(得分:0)
这是我的:
static public string LDAPEscape(string s)
{
StringBuilder sb = new StringBuilder(s.Length);
int i;
for (i = 0; i < s.Length; i++)
{
char c = s[i];
if ("/*)(\\\0".IndexOf(c) >= 0)
sb.Append('\\').Append(((uint)c).ToString("x2"));
else
sb.Append(c);
}
return sb.ToString();
}
答案 4 :(得分:0)
如果使用 maven 存储库 apache-ldap-api 作为 LDAP 客户端库,我们可以使用 Util 类 FilterEncoder 来处理 LDAP 搜索过滤器值中特殊字符的编码,如下所示
filter = "(attributeKey=" + FilterEncoder.encodeFilterValue(attributeValue) + ")";