83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
import ldap
|
|
import six
|
|
from ldap.controls import SimplePagedResultsControl
|
|
from ldap.ldapobject import ReconnectLDAPObject
|
|
|
|
|
|
class PagedResultsSearchObject:
|
|
page_size = 500
|
|
|
|
def paged_search_ext_s(
|
|
self,
|
|
base,
|
|
scope,
|
|
filterstr='(objectClass=*)',
|
|
attrlist=None,
|
|
attrsonly=0,
|
|
serverctrls=None,
|
|
clientctrls=None,
|
|
timeout=-1,
|
|
sizelimit=0,
|
|
):
|
|
"""
|
|
Behaves exactly like LDAPObject.search_ext_s() but internally uses the
|
|
simple paged results control to retrieve search results in chunks.
|
|
|
|
This is non-sense for really large results sets which you would like
|
|
to process one-by-one
|
|
"""
|
|
|
|
while True: # loop for reconnecting if necessary
|
|
req_ctrl = SimplePagedResultsControl(True, size=self.page_size, cookie='')
|
|
try:
|
|
# Send first search request
|
|
msgid = self.search_ext(
|
|
base,
|
|
scope,
|
|
filterstr=filterstr,
|
|
attrlist=attrlist,
|
|
attrsonly=attrsonly,
|
|
serverctrls=(serverctrls or []) + [req_ctrl],
|
|
clientctrls=clientctrls,
|
|
timeout=timeout,
|
|
sizelimit=sizelimit,
|
|
)
|
|
|
|
while True:
|
|
rtype, rdata, rmsgid, rctrls = self.result3(msgid)
|
|
yield from rdata
|
|
# Extract the simple paged results response control
|
|
pctrls = [
|
|
c for c in rctrls if c.controlType == SimplePagedResultsControl.controlType
|
|
]
|
|
if pctrls and pctrls[0].cookie:
|
|
# Copy cookie from response control to request control
|
|
req_ctrl.cookie = pctrls[0].cookie
|
|
msgid = self.search_ext(
|
|
base,
|
|
scope,
|
|
filterstr=filterstr,
|
|
attrlist=attrlist,
|
|
attrsonly=attrsonly,
|
|
serverctrls=(serverctrls or []) + [req_ctrl],
|
|
clientctrls=clientctrls,
|
|
timeout=timeout,
|
|
sizelimit=sizelimit,
|
|
)
|
|
continue
|
|
break # no more pages available
|
|
except ldap.SERVER_DOWN:
|
|
self.reconnect(self._uri)
|
|
else:
|
|
break
|
|
|
|
|
|
class PagedLDAPObject(ReconnectLDAPObject, PagedResultsSearchObject):
|
|
def __init__(self, *args, **kwargs):
|
|
if six.PY2 and map(int, ldap.__version__.split('.')) >= [3]:
|
|
if 'bytes_mode' not in kwargs:
|
|
kwargs['bytes_mode'] = False
|
|
if 'bytes_strictness' not in kwargs:
|
|
kwargs['bytes_strictness'] = 'silent'
|
|
ReconnectLDAPObject.__init__(self, *args, **kwargs)
|