async def pagedsearch(self, base, query, attributes, search_scope=2, size_limit=1000, typesOnly=False, derefAliases=0, timeLimit=None, controls=None): """ Paged search is the same as the search operation and uses it under the hood. Adds automatic control to read all results in a paged manner. :param base: base tree on which the search should be performed :type base: str :param query: filter query that defines what should be searched for :type query: str :param attributes: a list of attributes to be included in the response :type attributes: List[str] :param search_scope: Specifies the search operation's scope. Default: 2 (Subtree) :type search_scope: int :param types_only: indicates whether the entries returned should include attribute types only or both types and values. Default: False (both) :type types_only: bool :param size_limit: Size limit of result elements per query. Default: 1000 :type size_limit: int :param derefAliases: Specifies the behavior on how aliases are dereferenced. Default: 0 (never) :type derefAliases: int :param timeLimit: Maximum time the search should take. If time limit reached the server SHOULD return an error :type timeLimit: int :param controls: additional controls to be passed in the query :type controls: dict :return: Async generator which yields (`dict`, None) tuple on success or (None, `Exception`) on error :rtype: Iterator[(:class:`dict`, :class:`Exception`)] """ if self.status != MSLDAPClientStatus.RUNNING: yield None, Exception( 'Connection not running! Probably encountered an error') return try: cookie = b'' while True: ctrl_list_temp = [ Control({ 'controlType': b'1.2.840.113556.1.4.319', 'controlValue': SearchControlValue({ 'size': size_limit, 'cookie': cookie }).dump() }) ] if controls is not None: ctrl_list_temp.extend(controls) ctrs = Controls(ctrl_list_temp) async for res, err in self.search(base, query, attributes, search_scope=search_scope, size_limit=size_limit, types_only=typesOnly, derefAliases=derefAliases, timeLimit=timeLimit, controls=ctrs, return_done=True): if err is not None: yield (None, err) return if 'resultCode' in res['protocolOp']: for control in res['controls']: if control[ 'controlType'] == b'1.2.840.113556.1.4.319': try: cookie = SearchControlValue.load( control['controlValue'] ).native['cookie'] except Exception as e: raise e break else: raise Exception( 'SearchControl missing from server response!') else: yield (convert_result(res['protocolOp']), None) if cookie == b'': break except Exception as e: yield (None, e)
async def pagedsearch(self, base, filter, attributes, search_scope=2, paged_size=1000, typesOnly=False, derefAliases=0, timeLimit=None, controls=None): if self.status != MSLDAPClientStatus.RUNNING: yield None, Exception( 'Connection not running! Probably encountered an error') return try: cookie = b'' while True: ctrl_list_temp = [ Control({ 'controlType': b'1.2.840.113556.1.4.319', 'controlValue': SearchControlValue({ 'size': paged_size, 'cookie': cookie }).dump() }) ] if controls is not None: ctrl_list_temp.extend(controls) ctrs = Controls(ctrl_list_temp) async for res, err in self.search(base, filter, attributes, search_scope=search_scope, paged_size=paged_size, typesOnly=typesOnly, derefAliases=derefAliases, timeLimit=timeLimit, controls=ctrs, return_done=True): if err is not None: yield (None, err) return if 'resultCode' in res['protocolOp']: for control in res['controls']: if control[ 'controlType'] == b'1.2.840.113556.1.4.319': try: cookie = SearchControlValue.load( control['controlValue'] ).native['cookie'] except Exception as e: raise e break else: raise Exception( 'SearchControl missing from server response!') else: yield (convert_result(res['protocolOp']), None) if cookie == b'': break except Exception as e: yield (None, e)
async def search(self, base, query, attributes, search_scope=2, size_limit=1000, types_only=False, derefAliases=0, timeLimit=None, controls=None, return_done=False): """ Performs the search operation. :param base: base tree on which the search should be performed :type base: str :param query: filter query that defines what should be searched for :type query: str :param attributes: a list of attributes to be included in the response :type attributes: List[str] :param search_scope: Specifies the search operation's scope. Default: 2 (Subtree) :type search_scope: int :param types_only: indicates whether the entries returned should include attribute types only or both types and values. Default: False (both) :type types_only: bool :param size_limit: Size limit of result elements per query. Default: 1000 :type size_limit: int :param derefAliases: Specifies the behavior on how aliases are dereferenced. Default: 0 (never) :type derefAliases: int :param timeLimit: Maximum time the search should take. If time limit reached the server SHOULD return an error :type timeLimit: int :param controls: additional controls to be passed in the query :type controls: dict :param return_done: Controls wether the final 'done' LDAP message should be returned, or just the actual results :type return_done: bool :return: Async generator which yields (`LDAPMessage`, None) tuple on success or (None, `Exception`) on error :rtype: Iterator[(:class:`LDAPMessage`, :class:`Exception`)] """ if self.status != MSLDAPClientStatus.RUNNING: yield None, Exception( 'Connection not running! Probably encountered an error') return try: if timeLimit is None: timeLimit = 600 #not sure flt = query_syntax_converter(query) searchreq = { 'baseObject': base.encode(), 'scope': search_scope, 'derefAliases': derefAliases, 'sizeLimit': size_limit, 'timeLimit': timeLimit, 'typesOnly': types_only, 'filter': flt, 'attributes': attributes, } br = {'searchRequest': SearchRequest(searchreq)} msg = {'protocolOp': protocolOp(br)} if controls is not None: msg['controls'] = controls msg_id = await self.send_message(msg) while True: results = await self.recv_message(msg_id) for message in results: msg_type = message['protocolOp'].name message = message.native if msg_type == 'searchResDone': #print(message) #print('BREAKING!') if return_done is True: yield (message, None) break elif msg_type == 'searchResRef': #TODO: Check if we need to deal with this further continue if return_done is True: yield (message, None) else: yield (convert_result(message['protocolOp']), None) else: continue break except Exception as e: yield (None, e)
async def search(self, base, filter, attributes, search_scope=2, paged_size=1000, typesOnly=False, derefAliases=0, timeLimit=None, controls=None, return_done=False): """ This function is a generator!!!!! Dont just call it but use it with "async for" """ if self.status != MSLDAPClientStatus.RUNNING: yield None, Exception( 'Connection not running! Probably encountered an error') return try: if timeLimit is None: timeLimit = 600 #not sure searchreq = { 'baseObject': base, 'scope': search_scope, 'derefAliases': derefAliases, 'sizeLimit': paged_size, 'timeLimit': timeLimit, 'typesOnly': typesOnly, 'filter': filter, 'attributes': attributes, } br = {'searchRequest': SearchRequest(searchreq)} msg = {'protocolOp': protocolOp(br)} if controls is not None: msg['controls'] = controls msg_id = await self.send_message(msg) while True: results = await self.recv_message(msg_id) for message in results: msg_type = message['protocolOp'].name message = message.native if msg_type == 'searchResDone': #print(message) #print('BREAKING!') if return_done is True: yield (message, None) break elif msg_type == 'searchResRef': #TODO: Check if we need to deal with this further continue if return_done is True: yield (message, None) else: yield (convert_result(message['protocolOp']), None) else: continue break except Exception as e: yield (None, e)