Created
March 7, 2012 22:35
-
-
Save dnozay/1996782 to your computer and use it in GitHub Desktop.
ldap paged search
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# samples | |
# http://www.grotan.com/ldap/python-ldap-samples.html | |
# useraccountcontrol | |
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms680832(v=vs.85).aspx | |
# paging search | |
# http://www.novell.com/coolsolutions/tip/18274.html | |
import ldap | |
from ldap.controls import SimplePagedResultsControl | |
class LDAPConf: | |
''' | |
This contains all details that pertain to our ldap instance | |
''' | |
url = 'changeme' | |
# don't chase referrals since MSAD does not like it. | |
chase_referrals = 0 | |
protocol_version = ldap.VERSION3 | |
bind_dn = 'changeme' | |
bind_password = 'changeme' | |
base_dn = 'changeme' | |
search_scope = ldap.SCOPE_SUBTREE | |
# search all active accounts | |
search_filter = '(&(objectcategory=person)(objectclass=user)'\ | |
'(!(|(useraccountcontrol:1.2.840.113556.1.4.803:=2)'\ | |
'(useraccountcontrol:1.2.840.113556.1.4.803:=65536))))' | |
# retrieve all attributes | |
retrieve_attrs = None | |
# page search results | |
page_size = 100 | |
# size limit | |
size_limit = 0 | |
def connect(): | |
''' | |
setup the connection. | |
This should take care of all details that pertain to our ldap instance | |
''' | |
global conn | |
conn = ldap.open(LDAPConf.url) | |
conn.set_option(ldap.OPT_REFERRALS, LDAPConf.chase_referrals) | |
conn.set_option(ldap.OPT_SIZELIMIT, LDAPConf.size_limit) | |
conn.simple_bind_s(LDAPConf.bind_dn, LDAPConf.bind_password) | |
conn.protocol_version = LDAPConf.protocol_version | |
def disconnect(): | |
''' | |
close the connection. | |
This should take care of all details that pertain to our ldap instance | |
''' | |
conn.unbind_s() | |
class SearchCounter(object): | |
''' | |
Simple callback counter. | |
For non-paged search, callback will increase the counts. | |
''' | |
def __init__(self): | |
self.result_count, self.ref_count = 0, 0 | |
def callback(self, result_type, result_data): | |
''' | |
handle a search result. | |
This will increment the appropriate counter. | |
''' | |
if result_type == ldap.RES_SEARCH_ENTRY: | |
self.result_count += 1 | |
elif result_type == ldap.RES_SEARCH_REFERENCE: | |
self.ref_count += 1 | |
def search(result_callback, *args, **kwargs): | |
''' | |
Simple non-paged search. | |
See ldap.search_ext for parameters. | |
See ldap.result for callback parameters. | |
''' | |
ldap_result_id = conn.search_ext(*args, **kwargs) | |
try: | |
while True: | |
result_type, result_data = conn.result(ldap_result_id, 0) | |
if result_data == []: | |
break | |
result_callback(result_type, result_data) | |
except ldap.SIZELIMIT_EXCEEDED: | |
conn.abandon_ext(ldap_result_id) | |
def paged_search(*args, **kwargs): | |
''' | |
Paged search. | |
This is a generator function which will yield results one at a time. | |
See ldap.search_ext for parameters. | |
See ldap.result3 for implementation details. | |
''' | |
results_control = SimplePagedResultsControl( | |
ldap.LDAP_CONTROL_PAGE_OID, True, (LDAPConf.page_size, '')) | |
while True: | |
serverctrls = [results_control] | |
msgid = conn.search_ext(*args, serverctrls=serverctrls, **kwargs) | |
_, results, _, serverctrls = conn.result3(msgid=msgid) | |
for result in results: | |
yield result | |
cookie = None | |
# look for the cookie to continue the search | |
for serverctrl in serverctrls: | |
if serverctrl.controlType == ldap.LDAP_CONTROL_PAGE_OID: | |
_, cookie = serverctrl.controlValue | |
if cookie: | |
results_control.controlValue = (LDAPConf.page_size, cookie) | |
break | |
# no cookie = search complete. | |
if not cookie: | |
break | |
# example | |
if __name__ == '__main__': | |
try: | |
connect() | |
counter = SearchCounter() | |
search(counter.callback, | |
LDAPConf.base_dn, LDAPConf.search_scope, | |
LDAPConf.search_filter, LDAPConf.retrieve_attrs) | |
print 'result_count', counter.result_count | |
count = 0 | |
for item in paged_search( | |
LDAPConf.base_dn, LDAPConf.search_scope, | |
LDAPConf.search_filter, LDAPConf.retrieve_attrs): | |
count += 1 | |
print 'paged_result_count', count | |
print 'last item', item | |
except ldap.LDAPError, e: | |
print e | |
raise | |
finally: | |
disconnect() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment