15 December 2021

Asterisk (*) is wildly used as a wildcard card in regular express (regexp) matching and file name matching. So it is not a suprise at all that many expect it works the same way when put into a LDAP search filter. However, it may give surprising search results at times. More specifically, sometimes the filter does not match any entries while it should. This blog is to help you understand the reason of it and use * in LDAP searches correctly.

Firstly, please note that the filter attribute=* (say member=*) is different from attribute=a_string_contains_*_etc (member=test*, member=*test and member=*test* for example). The former filter means "present", i.e. so long as the attribute exists, corresponding LDAP entry is considered a match. This type of filters does not really incur many confusions. It is the later that sometimes does not work as one may have expected. To be accurate, this filter is not a regexp but a "substring filter". I'll be focusing on substring filters from now on. (Please refer to String Search Filter Definition for more information)

One key point to understand "LDAP search regexp issues" is: attributes can have a different LDAP substring filter matching rules. So, while * in LDAP substring filters normally work the same way as Linux shell file name matching, it is ignored if the targeted attribute does not have substring matching rules. To better understand this, let's have a look at the following test:

  1. Reviewing the schemas of description and member (shown below), we can see that description has a substring matching rule (SUBSTR caseIgnoreSubstringsMatch) but member does not.

    attributetype ( 2.5.4.13 NAME 'description'
          DESC 'RFC2256: descriptive information'
          EQUALITY caseIgnoreMatch
          SUBSTR caseIgnoreSubstringsMatch
          SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
    
    olcAttributeTypes: {27}( 2.5.4.31 NAME 'member' DESC 'RFC2256: member of a g
     roup' SUP distinguishedName )
    
  2. Add an LDAP entry which has both attributes set to the same value:

    dn: cn=guests,ou=OmRoles,dc=mongo,dc=com
    objectClass: groupOfNames
    cn: guests
    member: uid=guest@mongodb.com,ou=OmUsers,dc=mongo,dc=com
    description: uid=guest@mongodb.com,ou=OmUsers,dc=mongo,dc=com
    
  3. Apply the same substring filter to member and description respectively.
    • The search based on description returns the LDAP entry as expected.

      $ ldapsearch -LLL -H ldap://localhost:389 -D cn=Manager,dc=mongo,dc=com -w password -b ou=OmRoles,dc=mongo,dc=com -s sub 'description=*guest*'
      dn: cn=guests,ou=OmRoles,dc=mongo,dc=com
      objectClass: groupOfNames
      cn: guests
      member: uid=guest@mongodb.com,ou=OmUsers,dc=mongo,dc=com
      description: uid=guest@mongodb.com,ou=OmUsers,dc=mongo,dc=com
      
      $
      
    • The search against member returns nothing. This is actually desired behaviour because, as mentioned above, the filter is ignored since member does not define substring matching rule.

      $ ldapsearch -LLL -H ldap://localhost:389 -D cn=Manager,dc=mongo,dc=com -w password -b ou=OmRoles,dc=mongo,dc=com -s sub 'member=*guest*'
      
      $
      
  4. As you might have noted, since the substring matching rule for description is "caseIngore…", the filter is case insensitive: I get the same result using GUEST instead of guest.

    $ ldapsearch -LLL -H ldap://localhost:389 -D cn=Manager,dc=mongo,dc=com -w password -b ou=OmRoles,dc=mongo,dc=com -s sub 'description=*GUEST*'
    dn: cn=guests,ou=OmRoles,dc=mongo,dc=com
    objectClass: groupOfNames
    cn: guests
    member: uid=guest@mongodb.com,ou=OmUsers,dc=mongo,dc=com
    description: uid=guest@mongodb.com,ou=OmUsers,dc=mongo,dc=com
    


blog comments powered by Disqus