How should I escape ldap special characters?
Question:
I’m using python-ldap to query Active Directory
I have this DN
CN=Whalen, Sean,OU=Users,OU=Users and Groups,DC=example,DC=net
That works fine as a base in a query, but if I try to use it in a search filter like this
(&(objectClass=group)(memberof:1.2.840.113556.1.4.1941:=CN=Whalen, Sean,OU=Users,OU=Users and Groups,DC=example,DC=net))
I get a Bad search filter
error. From my testing, the comma in the CN seems to be the culprit, even though I escaped it with a backslash (
). But, comma isn’t listed in the Microsoft documentation as a character that needs escaped in filters.
What am I missing?
Answers:
The LDAP filter specification assigns special meaning to the following characters * ( ) NUL
that should be escaped with a backslash followed by the two character ASCII hexadecimal representation of the character when used in a search filter (rfc2254) :
* 2A
( 28
) 29
5C
Nul 0
That means any backslash used for escaping a Distinguished Name’ special character (including commas) must be represented by 5c
in a search filter :
(&(objectClass=group)(memberof:1.2.840.113556.1.4.1941:=CN=Whalen5c, Sean,OU=Users,OU=Users and Groups,DC=example,DC=net))
Here is the list of dn special characters that must be escaped with
, or whith 5C
when used in a search filter :
+-------------------------------+---+
| comma | , |
+-------------------------------+---+
| Backslash character | |
+-------------------------------+---+
| Pound sign (hash sign) | # |
+-------------------------------+---+
| Plus sign | + |
+-------------------------------+---+
| Less than symbol | < |
+-------------------------------+---+
| Greater than symbol | > |
+-------------------------------+---+
| Semicolon | ; |
+-------------------------------+---+
| Double quote (quotation mark) | " |
+-------------------------------+---+
| Equal sign | = |
+-------------------------------+---+
| Leading or trailing spaces | |
+-------------------------------+---+
I have experienced very odd behaviour when searching with member:1.2.840.113556.1.4.1941
with escaped characters.
It seems that the search fails when the search term is escaped ‘properly’, but succeeds when the search term is not escaped!
In contrast, a plain search using member
works whether the search term is escaped or not.
Here’s a PowerShell example.
function Find-AdObjects([string]$Filter) {
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$DirectorySearcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry
$DirectorySearcher.SearchScope = [System.DirectoryServices.SearchScope]::Subtree
$DirectorySearcher.PropertiesToLoad.Add('distinguishedname') > $null
$DirectorySearcher.PageSize = 100
$DirectorySearcher.Filter = $Filter
$SearchResultCollection = $DirectorySearcher.FindAll()
foreach ($r in $SearchResultCollection) {
$r.Properties['distinguishedname']
}
$SearchResultCollection.Dispose()
$DirectorySearcher.Dispose()
}
$UserDn = 'CN=Rees, John,OU=Tier3,DC=big,DC=com'
$EscapedUserDn = 'CN=Rees5C, John,OU=Tier3,DC=big,DC=com'
# Returns expected results with escaped search term
Find-AdObjects "(&(member=$EscapedUserDn))"
# Returns same results even though search term is NOT escaped correctly
Find-AdObjects "(&(member=$UserDn))"
# Returns NO results even though search term is escaped correctly
Find-AdObjects "(&(member:1.2.840.113556.1.4.1941:=$EscapedUserDn))"
# Returns recursive results even though search term is NOT escaped correctly
Find-AdObjects "(&(member:1.2.840.113556.1.4.1941:=$UserDn))"
So I do not see an acceptable workaround, since there does not seem to be a reliable way to escape a DN that could contain a variety of special characters: *()
I’m using python-ldap to query Active Directory
I have this DN
CN=Whalen, Sean,OU=Users,OU=Users and Groups,DC=example,DC=net
That works fine as a base in a query, but if I try to use it in a search filter like this
(&(objectClass=group)(memberof:1.2.840.113556.1.4.1941:=CN=Whalen, Sean,OU=Users,OU=Users and Groups,DC=example,DC=net))
I get a Bad search filter
error. From my testing, the comma in the CN seems to be the culprit, even though I escaped it with a backslash (). But, comma isn’t listed in the Microsoft documentation as a character that needs escaped in filters.
What am I missing?
The LDAP filter specification assigns special meaning to the following characters * ( ) NUL
that should be escaped with a backslash followed by the two character ASCII hexadecimal representation of the character when used in a search filter (rfc2254) :
* 2A
( 28
) 29
5C
Nul 0
That means any backslash used for escaping a Distinguished Name’ special character (including commas) must be represented by 5c
in a search filter :
(&(objectClass=group)(memberof:1.2.840.113556.1.4.1941:=CN=Whalen5c, Sean,OU=Users,OU=Users and Groups,DC=example,DC=net))
Here is the list of dn special characters that must be escaped with , or whith
5C
when used in a search filter :
+-------------------------------+---+
| comma | , |
+-------------------------------+---+
| Backslash character | |
+-------------------------------+---+
| Pound sign (hash sign) | # |
+-------------------------------+---+
| Plus sign | + |
+-------------------------------+---+
| Less than symbol | < |
+-------------------------------+---+
| Greater than symbol | > |
+-------------------------------+---+
| Semicolon | ; |
+-------------------------------+---+
| Double quote (quotation mark) | " |
+-------------------------------+---+
| Equal sign | = |
+-------------------------------+---+
| Leading or trailing spaces | |
+-------------------------------+---+
I have experienced very odd behaviour when searching with member:1.2.840.113556.1.4.1941
with escaped characters.
It seems that the search fails when the search term is escaped ‘properly’, but succeeds when the search term is not escaped!
In contrast, a plain search using member
works whether the search term is escaped or not.
Here’s a PowerShell example.
function Find-AdObjects([string]$Filter) {
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$DirectorySearcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry
$DirectorySearcher.SearchScope = [System.DirectoryServices.SearchScope]::Subtree
$DirectorySearcher.PropertiesToLoad.Add('distinguishedname') > $null
$DirectorySearcher.PageSize = 100
$DirectorySearcher.Filter = $Filter
$SearchResultCollection = $DirectorySearcher.FindAll()
foreach ($r in $SearchResultCollection) {
$r.Properties['distinguishedname']
}
$SearchResultCollection.Dispose()
$DirectorySearcher.Dispose()
}
$UserDn = 'CN=Rees, John,OU=Tier3,DC=big,DC=com'
$EscapedUserDn = 'CN=Rees5C, John,OU=Tier3,DC=big,DC=com'
# Returns expected results with escaped search term
Find-AdObjects "(&(member=$EscapedUserDn))"
# Returns same results even though search term is NOT escaped correctly
Find-AdObjects "(&(member=$UserDn))"
# Returns NO results even though search term is escaped correctly
Find-AdObjects "(&(member:1.2.840.113556.1.4.1941:=$EscapedUserDn))"
# Returns recursive results even though search term is NOT escaped correctly
Find-AdObjects "(&(member:1.2.840.113556.1.4.1941:=$UserDn))"
So I do not see an acceptable workaround, since there does not seem to be a reliable way to escape a DN that could contain a variety of special characters: *()