LDAP Filter Syntax

Question:

I am using python library ldap3 to send requests to the servers to query user objects that are not disabled and have a display name or email that contains the user input:

query = "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(|(displayName={0}*)(mail={0}*))".format(value)

I followed what I think the documentation says about forming LDAP filters, but I am getting an incorrect LDAP filter error message:

LDAPInvalidFilterError: malformed filter

I played around with it and this works:

query = "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(displayName={0}*))".format(value) 

I haven’t been able to construct a filter using | yet. How should the query be constructed?

Asked By: Josh Sharkey

||

Answers:

You cannot simply .format() any value into a filter.

You need to escape certain characters before you interpolate them into the string.

*     -> 2a
(     -> 28
)     -> 29
     -> 5c
NUL   -> 0
/     -> 2f

Just like with URLs, you’re free to escape any character you like using the above scheme, but the ones above are the minimum.

I haven’t been able to construct a filter using | yet. How should the query be constructed?

That being said, you had a nesting error. You’ll see it when you format your query:

(&
  (objectClass=user)
  (!(userAccountControl:1.2.840.113556.1.4.803:=2))
  (|
    (displayName={0}*)
    (mail={0}*)
  )

You still need to escape the value, but since the LDAP server does not care, keep the query formatting:

value = ldap3.utils.conv.escape_filter_chars(user_input)
query = f"""
(&
  (objectClass=user)
  (!(userAccountControl:1.2.840.113556.1.4.803:=2))
  (|
    (displayName={value}*)
    (mail={value}*)
  )
)
"""
Answered By: Tomalak

not sure if this is a bug in ldap3 or if the strict adherence to RFC 4515, but I had this same issue and managed to resolve it partly due to this post, so hopefully this helps someone else.

https://ldap3.readthedocs.io/en/latest/searches.html
https://www.rfc-editor.org/rfc/rfc4515

I was testing the following query which worked perfectly fine using ldp.exe:

(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(|(userprincipalname={0})(samaccountname={0})(distinguishedname={0})))

I tried a couple of different variations and like yourself, just changing the OR (pipe) to AND (ampersand) allowed the query to run without error.

In the end, I resolved it by adding brackets to my NOT assertion, based on an example in the ldap3 documentation link above.

This query works for me without the "malformed filter" error:

(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(|(userprincipalname={0})(samaccountname={0})(distinguishedname={0})))

Answered By: Lindon Morris