From e355324df679aa9a03045c7b0948c7f30e1149dd Mon Sep 17 00:00:00 2001 From: CravateRouge Date: Sat, 1 Mar 2025 13:43:50 +0800 Subject: [PATCH 1/2] option to return ldap raw value instead of msldap encoded --- msldap/client.py | 7 +++++-- msldap/connection.py | 9 ++++++--- msldap/protocol/typeconversion.py | 22 ++++++++++++---------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/msldap/client.py b/msldap/client.py index dbc1c0e..9aca66e 100644 --- a/msldap/client.py +++ b/msldap/client.py @@ -156,7 +156,7 @@ async def get_domain_name(self): return domain, err - async def pagedsearch(self, query:str, attributes:List[str], controls:List[Tuple[str, str, str]] = None, tree:str = None, search_scope:int=2): + async def pagedsearch(self, query:str, attributes:List[str], controls:List[Tuple[str, str, str]] = None, tree:str = None, search_scope:int=2, raw: bool = False): """ Performs a paged search on the AD, using the filter and attributes as a normal query does. !The LDAP connection MUST be active before invoking this function! @@ -171,6 +171,8 @@ async def pagedsearch(self, query:str, attributes:List[str], controls:List[Tuple :type tree: str :param search_scope: LDAP search scope :type search_scope: int + :param raw: Return the attributes without conversion + :type raw: bool :return: Async generator which yields (`dict`, None) tuple on success or (None, `Exception`) on error :rtype: Iterator[(:class:`dict`, :class:`Exception`)] @@ -209,7 +211,8 @@ async def pagedsearch(self, query:str, attributes:List[str], controls:List[Tuple size_limit = self.ldap_query_page_size, controls = controls, rate_limit=self.ldap_query_ratelimit, - search_scope=search_scope + search_scope=search_scope, + raw=raw ): if err is not None: diff --git a/msldap/connection.py b/msldap/connection.py index 4789467..299ea70 100644 --- a/msldap/connection.py +++ b/msldap/connection.py @@ -751,7 +751,7 @@ async def search(self, base:str, query:str, attributes:List[bytes], search_scope except Exception as e: yield (None, e) - async def pagedsearch(self, base:str, query:str, attributes:List[bytes], search_scope:int = 2, size_limit:int = 1000, typesOnly:bool = False, derefAliases:bool = 0, timeLimit:int = None, controls:List[Control] = None, rate_limit:int = 0): + async def pagedsearch(self, base:str, query:str, attributes:List[bytes], search_scope:int = 2, size_limit:int = 1000, typesOnly:bool = False, derefAliases:bool = 0, timeLimit:int = None, controls:List[Control] = None, rate_limit:int = 0, raw: bool = False): """ 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. @@ -773,8 +773,11 @@ async def pagedsearch(self, base:str, query:str, attributes:List[bytes], search_ :type timeLimit: int :param controls: additional controls to be passed in the query :type controls: dict - :param rate_limit: time to sleep bwetween each query + :param rate_limit: time to sleep between each query :type rate_limit: float + :param raw: Return the attributes without conversion + :type raw: bool + :return: Async generator which yields (`dict`, None) tuple on success or (None, `Exception`) on error :rtype: Iterator[(:class:`dict`, :class:`Exception`)] """ @@ -835,7 +838,7 @@ async def pagedsearch(self, base:str, query:str, attributes:List[bytes], search_ else: raise Exception('SearchControl missing from server response!') else: - yield (convert_result(res['protocolOp']), None) + yield (convert_result(res['protocolOp'], raw), None) if cookie == b'': break diff --git a/msldap/protocol/typeconversion.py b/msldap/protocol/typeconversion.py index 198b88d..2ad8da5 100644 --- a/msldap/protocol/typeconversion.py +++ b/msldap/protocol/typeconversion.py @@ -430,29 +430,31 @@ def encode_attributes(x): return res -def convert_attributes(x): +def convert_attributes(x, raw=False): t = {} for e in x: #print(e) k = e['type'].decode() #print('k: %s' % k) - - if k in MSLDAP_BUILTIN_ATTRIBUTE_TYPES: - t[k] = MSLDAP_BUILTIN_ATTRIBUTE_TYPES[k](e['attributes'], False) - elif k in LDAP_WELL_KNOWN_ATTRS: - t[k] = LDAP_WELL_KNOWN_ATTRS[k](e['attributes'], False) + if raw: + t[k] = e['attributes'] else: - logger.debug('Unknown type! %s data: %s' % (k, e['attributes'])) - t[k] = e['attributes'] + if k in MSLDAP_BUILTIN_ATTRIBUTE_TYPES: + t[k] = MSLDAP_BUILTIN_ATTRIBUTE_TYPES[k](e['attributes'], False) + elif k in LDAP_WELL_KNOWN_ATTRS: + t[k] = LDAP_WELL_KNOWN_ATTRS[k](e['attributes'], False) + else: + logger.debug('Unknown type! %s data: %s' % (k, e['attributes'])) + t[k] = e['attributes'] return t -def convert_result(x): +def convert_result(x, raw=False): #print(x) #import traceback #traceback.print_stack() return { 'objectName' : x['objectName'].decode(), - 'attributes' : convert_attributes(x['attributes']) + 'attributes' : convert_attributes(x['attributes'], raw) } From 9c9a3b4263beed834be1cd0fa12290cd24725bf1 Mon Sep 17 00:00:00 2001 From: CravateRouge Date: Sat, 1 Mar 2025 06:25:01 +0000 Subject: [PATCH 2/2] Change whitespaces for tabs --- msldap/client.py | 2 +- msldap/connection.py | 2 +- msldap/protocol/typeconversion.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/msldap/client.py b/msldap/client.py index 9aca66e..604b2fe 100644 --- a/msldap/client.py +++ b/msldap/client.py @@ -172,7 +172,7 @@ async def pagedsearch(self, query:str, attributes:List[str], controls:List[Tuple :param search_scope: LDAP search scope :type search_scope: int :param raw: Return the attributes without conversion - :type raw: bool + :type raw: bool :return: Async generator which yields (`dict`, None) tuple on success or (None, `Exception`) on error :rtype: Iterator[(:class:`dict`, :class:`Exception`)] diff --git a/msldap/connection.py b/msldap/connection.py index 299ea70..5a1b84f 100644 --- a/msldap/connection.py +++ b/msldap/connection.py @@ -776,7 +776,7 @@ async def pagedsearch(self, base:str, query:str, attributes:List[bytes], search_ :param rate_limit: time to sleep between each query :type rate_limit: float :param raw: Return the attributes without conversion - :type raw: bool + :type raw: bool :return: Async generator which yields (`dict`, None) tuple on success or (None, `Exception`) on error :rtype: Iterator[(:class:`dict`, :class:`Exception`)] diff --git a/msldap/protocol/typeconversion.py b/msldap/protocol/typeconversion.py index 2ad8da5..d2605f1 100644 --- a/msldap/protocol/typeconversion.py +++ b/msldap/protocol/typeconversion.py @@ -437,7 +437,7 @@ def convert_attributes(x, raw=False): k = e['type'].decode() #print('k: %s' % k) if raw: - t[k] = e['attributes'] + t[k] = e['attributes'] else: if k in MSLDAP_BUILTIN_ATTRIBUTE_TYPES: t[k] = MSLDAP_BUILTIN_ATTRIBUTE_TYPES[k](e['attributes'], False)