commit ad3d2dba244926576090e1c8b186cb307a85e3d7 Author: Florian Best Date: Wed Jun 5 16:34:36 2019 +0200 Implement servercontrols for search() res = {}; c = ldap.controls.SimplePagedResultsControl(True, size=10, cookie=''); import univention.uldap, ldap; lo = univention.uldap.getMachineConnection(); lo.searchDn(filter='univentionObjectType=users/user', response=res, serverctrls=[c]); c.cookie = res['ctrls'][0].cookie; print lo.searchDn(filter='univentionObjectType=users/user', response=res, serverctrls=[c]); res = {} c = ldap.controls.SimplePagedResultsControl(True, size=10, cookie='') import univention.uldap, ldap lo = univention.uldap.getMachineConnection() lo.searchDn(filter='univentionObjectType=users/user', response=res, serverctrls=[c]) c.cookie = res['ctrls'][0].cookie print lo.searchDn(filter='univentionObjectType=users/user', response=res, serverctrls=[c]); diff --git a/base/univention-python/modules/uldap.py b/base/univention-python/modules/uldap.py index 96bae27a42..c6fb93a4d4 100644 --- a/base/univention-python/modules/uldap.py +++ b/base/univention-python/modules/uldap.py @@ -417,7 +417,7 @@ class access: raise ldap.NO_SUCH_OBJECT({'desc': 'no object'}) return [] - def search(self, filter='(objectClass=*)', base='', scope='sub', attr=[], unique=False, required=False, timeout=-1, sizelimit=0, serverctrls=None): + def search(self, filter='(objectClass=*)', base='', scope='sub', attr=[], unique=False, required=False, timeout=-1, sizelimit=0, serverctrls=None, response=None): # type: (str, str, str, List[str], bool, bool, int, int, Optional[List[ldap.controls.LDAPControl]]) -> List[Tuple[str, Dict[str, List[str]]]] """ Perform LDAP search and return values. @@ -445,8 +445,8 @@ class access: base = self.base if scope == 'base+one': - res = self.lo.search_ext_s(base, ldap.SCOPE_BASE, filter, attr, serverctrls=serverctrls, clientctrls=None, timeout=timeout, sizelimit=sizelimit) + \ - self.lo.search_ext_s(base, ldap.SCOPE_ONELEVEL, filter, attr, serverctrls=serverctrls, clientctrls=None, timeout=timeout, sizelimit=sizelimit) + res = self.__search(response, base, ldap.SCOPE_BASE, filter, attr, serverctrls=serverctrls, clientctrls=None, timeout=timeout, sizelimit=sizelimit) + \ + self.__search(response, base, ldap.SCOPE_ONELEVEL, filter, attr, serverctrls=serverctrls, clientctrls=None, timeout=timeout, sizelimit=sizelimit) else: if scope == 'sub' or scope == 'domain': ldap_scope = ldap.SCOPE_SUBTREE @@ -454,7 +454,7 @@ class access: ldap_scope = ldap.SCOPE_ONELEVEL else: ldap_scope = ldap.SCOPE_BASE - res = self.lo.search_ext_s(base, ldap_scope, filter, attr, serverctrls=serverctrls, clientctrls=None, timeout=timeout, sizelimit=sizelimit) + res = self.__search(response, base, ldap_scope, filter, attr, serverctrls=serverctrls, clientctrls=None, timeout=timeout, sizelimit=sizelimit) if unique and len(res) > 1: raise ldap.INAPPROPRIATE_MATCHING({'desc': 'more than one object'}) @@ -462,7 +462,20 @@ class access: raise ldap.NO_SUCH_OBJECT({'desc': 'no object'}) return res - def searchDn(self, filter='(objectClass=*)', base='', scope='sub', unique=False, required=False, timeout=-1, sizelimit=0, serverctrls=None): + def __search(self, response, *args, **kwargs): + try: + rtype, rdata, rmsgid, resp_ctrls = self.lo.result3(self.lo.search_ext(*args, **kwargs)) + except ldap.REFERRAL as exc: + if not self.follow_referral: + raise + lo_ref = self._handle_referral(exc) + rtype, rdata, rmsgid, resp_ctrls = lo_ref.result3(lo_ref.search_ext(*args, **kwargs)) + + if kwargs.get('serverctrls') and isinstance(response, dict): + response['ctrls'] = resp_ctrls + return rdata + + def searchDn(self, filter='(objectClass=*)', base='', scope='sub', unique=False, required=False, timeout=-1, sizelimit=0, serverctrls=None, response=None): # type: (str, str, str, bool, bool, int, int, Optional[List[ldap.controls.LDAPControl]]) -> List[str] """ Perform LDAP search and return distinguished names only. @@ -482,7 +495,7 @@ class access: :raises ldap.INAPPROPRIATE_MATCHING: Indicates that the matching rule specified in the search filter does not match a rule defined for the attribute's syntax. """ _d = univention.debug.function('uldap.searchDn filter=%s base=%s scope=%s unique=%d required=%d' % (filter, base, scope, unique, required)) # noqa F841 - return [x[0] for x in self.search(filter, base, scope, ['dn'], unique, required, timeout, sizelimit, serverctrls)] + return [x[0] for x in self.search(filter, base, scope, ['dn'], unique, required, timeout, sizelimit, serverctrls, response)] def getPolicies(self, dn, policies=None, attrs=None, result=None, fixedattrs=None): # type: (str, List[str], Dict[str, List[Any]], Any, Any) -> Dict[str, Dict[str, Any]] diff --git a/management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py b/management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py index 0bde852b46..916cf49eb5 100644 --- a/management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py +++ b/management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py @@ -1691,7 +1691,7 @@ class simpleLdap(object): return containers @classmethod - def lookup(cls, co, lo, filter_s, base='', superordinate=None, scope='sub', unique=False, required=False, timeout=-1, sizelimit=0): # type: (univention.admin.uldap.config, univention.admin.uldap.access, str, str, Optional[str], str, bool, bool, int, int) -> list[simpleLdap] + def lookup(cls, co, lo, filter_s, base='', superordinate=None, scope='sub', unique=False, required=False, timeout=-1, sizelimit=0, serverctrls=None, response=None): # type: (univention.admin.uldap.config, univention.admin.uldap.access, str, str, Optional[str], str, bool, bool, int, int) -> list[simpleLdap] """ Perform a LDAP search and return a list of instances. @@ -1714,7 +1714,7 @@ class simpleLdap(object): filter_str = unicode(filter_s or '') attr = cls._ldap_attributes() result = [] - for dn, attrs in lo.search(filter_str, base, scope, attr, unique, required, timeout, sizelimit): + for dn, attrs in lo.search(filter_str, base, scope, attr, unique, required, timeout, sizelimit, serverctrls=serverctrls, response=response): try: result.append(cls(co, lo, None, dn=dn, superordinate=superordinate, attributes=attrs)) except univention.admin.uexceptions.base as exc: diff --git a/management/univention-directory-manager-modules/modules/univention/admin/uldap.py b/management/univention-directory-manager-modules/modules/univention/admin/uldap.py index cb1b722a9d..473d4acac7 100644 --- a/management/univention-directory-manager-modules/modules/univention/admin/uldap.py +++ b/management/univention-directory-manager-modules/modules/univention/admin/uldap.py @@ -722,7 +722,7 @@ class access: """ return self.lo.getAttr(dn, attr, required) - def search(self, filter='(objectClass=*)', base='', scope='sub', attr=[], unique=False, required=False, timeout=-1, sizelimit=0): + def search(self, filter='(objectClass=*)', base='', scope='sub', attr=[], unique=False, required=False, timeout=-1, sizelimit=0, serverctrls=None, response=None): # type: (str, str, str, List[str], bool, bool, int, int) -> List[Tuple[str, Dict[str, List[str]]]] """ Perform LDAP search and return values. @@ -747,7 +747,7 @@ class access: :raises univention.admin.uexceptions.ldapError: on any other LDAP error. """ try: - return self.lo.search(filter, base, scope, attr, unique, required, timeout, sizelimit) + return self.lo.search(filter, base, scope, attr, unique, required, timeout, sizelimit, serverctrls=serverctrls, response=response) except ldap.NO_SUCH_OBJECT as msg: raise univention.admin.uexceptions.noObject(_err2str(msg)) except ldap.INAPPROPRIATE_MATCHING as msg: @@ -763,7 +763,7 @@ class access: except ldap.LDAPError as msg: raise univention.admin.uexceptions.ldapError(_err2str(msg), original_exception=msg) - def searchDn(self, filter='(objectClass=*)', base='', scope='sub', unique=False, required=False, timeout=-1, sizelimit=0): + def searchDn(self, filter='(objectClass=*)', base='', scope='sub', unique=False, required=False, timeout=-1, sizelimit=0, serverctrls=None, response=None): # type: (str, str, str, bool, bool, int, int) -> List[str] """ Perform LDAP search and return distinguished names only. @@ -788,7 +788,7 @@ class access: :raises univention.admin.uexceptions.ldapError: on any other LDAP error. """ try: - return self.lo.searchDn(filter, base, scope, unique, required, timeout, sizelimit) + return self.lo.searchDn(filter, base, scope, unique, required, timeout, sizelimit, serverctrls=serverctrls, response=response) except ldap.NO_SUCH_OBJECT as msg: raise univention.admin.uexceptions.noObject(_err2str(msg)) except ldap.INAPPROPRIATE_MATCHING as msg: