diff options
author | Jan Cholasta <jcholast@redhat.com> | 2013-10-31 12:31:24 +0000 |
---|---|---|
committer | Petr Viktorin <pviktori@redhat.com> | 2013-11-27 13:46:41 +0100 |
commit | a9bf18ab9554cb541f6f5f31c6860a3610df5e13 (patch) | |
tree | 040e3340c726fc7feb1582f7ec3f81376e09aa12 | |
parent | 8013056194755d44105b512960951d723cc706d7 (diff) | |
download | freeipa-a9bf18ab9554cb541f6f5f31c6860a3610df5e13.tar.gz freeipa-a9bf18ab9554cb541f6f5f31c6860a3610df5e13.tar.xz freeipa-a9bf18ab9554cb541f6f5f31c6860a3610df5e13.zip |
Support searches with paged results control in LDAPClient.
https://fedorahosted.org/freeipa/ticket/3971
-rw-r--r-- | ipapython/ipaldap.py | 75 | ||||
-rw-r--r-- | ipaserver/plugins/ldap2.py | 4 |
2 files changed, 61 insertions, 18 deletions
diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py index 83daa6a7a..39d0edb1c 100644 --- a/ipapython/ipaldap.py +++ b/ipapython/ipaldap.py @@ -31,6 +31,7 @@ import ldap import ldap.sasl import ldap.filter from ldap.ldapobject import SimpleLDAPObject +from ldap.controls import SimplePagedResultsControl import ldapurl from ipalib import errors, _ @@ -1380,7 +1381,7 @@ class LDAPClient(object): def find_entries(self, filter=None, attrs_list=None, base_dn=None, scope=ldap.SCOPE_SUBTREE, time_limit=None, - size_limit=None, search_refs=False): + size_limit=None, search_refs=False, paged_search=False): """ Return a list of entries and indication of whether the results were truncated ([(dn, entry_attrs)], truncated) matching specified search @@ -1396,6 +1397,7 @@ class LDAPClient(object): (default unlimited) search_refs -- allow search references to be returned (default skips these entries) + paged_search -- search using paged results control """ if base_dn is None: base_dn = DN() @@ -1417,24 +1419,65 @@ class LDAPClient(object): if attrs_list: attrs_list = [a.lower() for a in set(attrs_list)] + sctrls = None + cookie = '' + page_size = (size_limit if size_limit > 0 else 2000) - 1 + if page_size == 0: + paged_search = False + # pass arguments to python-ldap with self.error_handler(): - try: - id = self.conn.search_ext( - base_dn, scope, filter, attrs_list, timeout=time_limit, - sizelimit=size_limit - ) - while True: - (objtype, res_list) = self.conn.result(id, 0) - if not res_list: + while True: + if paged_search: + sctrls = [SimplePagedResultsControl(0, page_size, cookie)] + + try: + id = self.conn.search_ext( + base_dn, scope, filter, attrs_list, + serverctrls=sctrls, timeout=time_limit, + sizelimit=size_limit + ) + while True: + result = self.conn.result3(id, 0) + objtype, res_list, res_id, res_ctrls = result + if not res_list: + break + if (objtype == ldap.RES_SEARCH_ENTRY or + (search_refs and + objtype == ldap.RES_SEARCH_REFERENCE)): + res.append(res_list[0]) + + if paged_search: + # Get cookie for the next page + for ctrl in res_ctrls: + if isinstance(ctrl, SimplePagedResultsControl): + cookie = ctrl.cookie + break + else: + cookie = '' + except ldap.LDAPError, e: + # If paged search is in progress, try to cancel it + if paged_search and cookie: + sctrls = [SimplePagedResultsControl(0, 0, cookie)] + try: + self.conn.search_ext_s( + base_dn, scope, filter, attrs_list, + serverctrls=sctrls, timeout=time_limit, + sizelimit=size_limit) + except ldap.LDAPError, e: + self.log.warning( + "Error cancelling paged search: %s", e) + cookie = '' + + try: + raise e + except (ldap.ADMINLIMIT_EXCEEDED, ldap.TIMELIMIT_EXCEEDED, + ldap.SIZELIMIT_EXCEEDED): + truncated = True break - if (objtype == ldap.RES_SEARCH_ENTRY or - (search_refs and - objtype == ldap.RES_SEARCH_REFERENCE)): - res.append(res_list[0]) - except (ldap.ADMINLIMIT_EXCEEDED, ldap.TIMELIMIT_EXCEEDED, - ldap.SIZELIMIT_EXCEEDED), e: - truncated = True + + if not paged_search or not cookie: + break if not res and not truncated: raise errors.NotFound(reason='no such entry') diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index e62f74b90..d05ab393c 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -183,7 +183,7 @@ class ldap2(LDAPClient, CrudBackend): def find_entries(self, filter=None, attrs_list=None, base_dn=None, scope=_ldap.SCOPE_SUBTREE, time_limit=None, - size_limit=None, search_refs=False): + size_limit=None, search_refs=False, paged_search=False): if time_limit is None or size_limit is None: config = self.get_ipa_config() if time_limit is None: @@ -194,7 +194,7 @@ class ldap2(LDAPClient, CrudBackend): res, truncated = super(ldap2, self).find_entries( filter=filter, attrs_list=attrs_list, base_dn=base_dn, scope=scope, time_limit=time_limit, size_limit=size_limit, - search_refs=search_refs) + search_refs=search_refs, paged_search=paged_search) if attrs_list and ( 'memberindirect' in attrs_list or '*' in attrs_list): |