1

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?

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
Josh Sharkey
  • 1,008
  • 9
  • 34

2 Answers2

3

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   -> \00
/     -> \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}*)
  )
)
"""
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • this isn't the query that I am trying to achieve, I am trying to use the string checking multiple fields, meaning the user can type anything and it runs against both the display name and the email. Running this function to escape the characters fails as well: ```query = ldap3.utils.conv.escape_filter_chars("(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(|(displayName={0}*)(mail={0}*)))".format(value))``` – Josh Sharkey Mar 19 '21 at 17:18
  • @JoshSharkey You're not supposed to escape *the whole filter string*. You're supposed to escape the user-supplied bits. And, you can make a filter that runs the user-supplied bits against both display name and email with the info provided in my answer. Sit back, relax, concentrate. – Tomalak Mar 19 '21 at 17:54
  • That's precisely it though- --- using the info provided your answer still doesn't work. I'm not sure if you have the library installed and an LDAP server available but there is something regarding the | operator and varying fields that is not allowing my query to work. It has nothing to do with escaping the value being formatted into the string. – Josh Sharkey Mar 19 '21 at 19:03
  • The query you provided may work, but it's not the query in question. – Josh Sharkey Mar 19 '21 at 19:04
  • @JoshSharkey You're right, you and I manged to overlook the same typo. (So much for "concentrate"...) – Tomalak Mar 20 '21 at 00:09
1

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})))