Search code examples
ldappython-ldap

python-ldap: Retrieve only a few entries from LDAP search


I wish to mimic the ldapsearch -z flag behavior of retrieving only a specific amount of entries from LDAP using python-ldap.

However, it keeps failing with the exception SIZELIMIT_EXCEEDED.

There are multiple links where the problem is reported, but the suggested solution doesn't seem to work

Python-ldap search: Size Limit Exceeded

LDAP: ldap.SIZELIMIT_EXCEEDED

I am using search_ext_s() with sizelimit parameter set to 1, which I am sure is not more than the server limit

On Wireshark, I see that 1 entry is returned and the server raises SIZELIMIT_EXCEEDED. This is the same as ldapsearch -z behavior

But the following line raises an exception and I don't know how to retrieve the returned entry

conn.search_ext_s(<base>,ldap.SCOPE_SUBTREE,'(cn=demo_user*)',['dn'],sizelimit=1)

Solution

  • Based upon the discussion in the comments, this is how I achieved it:

    import ldap
    
    # These are not mandatory, I just have a habit
    # of setting against Microsoft Active Directory
    
    ldap.set_option(ldap.OPT_REFERRALS, 0)
    ldap.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
    
    conn = ldap.initialize('ldap://<SERVER-IP>')
    conn.simple_bind(<username>, <password>)
    
    # Using async search version
    ldap_result_id = conn.search_ext(<base-dn>, ldap.SCOPE_SUBTREE,
                                     <filter>, [desired-attrs],
                                     sizelimit=<your-desired-sizelimit>)
    result_set = []
    try:
      while 1:
        result_type, result_data = conn.result(ldap_result_id, 0)
        if (result_data == []):
          break
        else:
          # Handle the singular entry anyway you wish.
          # I am appending here
          if result_type == ldap.RES_SEARCH_ENTRY:
            result_set.append(result_data)
    except ldap.SIZELIMIT_EXCEEDED:
      print 'Hitting sizelimit'
    
    print result_set
    

    Sample Output:

    # My server has about 500 entries for 'demo_user' - 1,2,3 etc.
    # My filter is '(cn=demo_user*)', attrs = ['cn'] with sizelimit of 5
    
    $ python ldap_sizelimit.py
    
    Hitting sizelimit
    [[('CN=demo_user0,OU=DemoUsers,DC=ad,DC=local', {'cn': ['demo_user0']})], 
    [('CN=demo_user1,OU=DemoUsers,DC=ad,DC=local', {'cn': ['demo_user1']})], 
    [('CN=demo_user10,OU=DemoUsers,DC=ad,DC=local', {'cn': ['demo_user10']})], 
    [('CN=demo_user100,OU=DemoUsers,DC=ad,DC=local', {'cn': ['demo_user100']})], 
    [('CN=demo_user101,OU=DemoUsers,DC=ad,DC=local', {'cn': ['demo_user101']})]]
    

    You may use play around with more srv controls to sort these etc. but I think the basic idea is conveyed ;)