Search code examples
python-ldap

Turn off search continuation results in python-ldap?


Using python-ldap.search_s() function (https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap.html#ldap.LDAPObject.search_s) with params...

base = DC=myorg,DC=local
filterstr = (&(sAMAccountName={login})(|(memberOf=CN=zone1,OU=zones,OU=datagroups,DC=myorg,DC=local)(memberOf=CN=zone2,OU=zones,OU=datagroups,DC=myorg,DC=local)))

...to try to match against a specific AD user. Yet when I look at the result returned (with login = myuser), I see something like:

[
   (u'CN=zone1,OU=zones,OU=datagroups,DC=myorg,DC=local', {u'sAMAccountName': ['myuser']}), 
   (None, [u'ldap://DomainDnsZones.myorg.local/DC=DomainDnsZones,DC=myorg,DC=local']), 
   (None, [u'ldap://ForestDnsZones.myorg.local/DC=ForestDnsZones,DC=myorg,DC=local']), 
   (None, [u'ldap://myorg.local/CN=Configuration,DC=myorg,DC=local'])
]

where there are multiple other hits in the list (besides the myuser sAMAccountName match) that have nothing to do with the search filter. Looking at the docs (https://www.python-ldap.org/en/python-ldap-3.3.0/faq.html) these appear to be "search continuations" / referrals that are included when the search base is at the domain level and it says that they can be turned off by including the code like...

l = ldap.initialize('ldap://foobar')
l.set_option(ldap.OPT_REFERRALS,0)

as well as trying

ldap.set_option(ldap.OPT_REFERRALS,0)
l = ldap.initialize('ldap://foobar')

...yet adding this code does not change the behavior at all and I get the same results (see https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap.html?highlight=set_option#ldap.set_option).

Am I misunderstanding something here? Anyone know how to get these to stop popping up? Anyone know the structure of the tuples that this function returns (the docs do not describe)?


Solution

  • Just talked to someone else more familiar with python-ldap and was told that OPT_REFERRALS is controlling if you automatically follow the referral, but it doesn't stop AD from sending them.

    For now, the only approach they recommended was to filter these values with something like:

    results = ldap.search_s(...)
    results = [ x for x in results if x[0] is not None ]
    

    Noting that the structure of the results returned from search_s() is

    [
        ( dn, {
             attrname: [ value, value, ... ],
             attrname: [ value, value, ... ],
        }),
    ]
    

    When it's a referral it's a DN of None and the entry dict is replaced with an array of URI's.

    * (Note that in the search_s call you can request specific attributes to be returned in your search too)

    * (Note that since my base DN is a domain level path, using the ldap.set_option(ldap.OPT_REFERRALS,0) snippet was still useful just to stop the search_s() from actually going down the referral paths (which was adding a few seconds to the search time))

    Again, I believe that this problem is due to the base DN being a domain level path (unless there is some other base_dn or search.filter I could use for that fact that the group users are scattered across various AD paths in the domain that I'm missing).