codekingpro/portable-devtools
114k
1"""
2"""
3
4# Created on 2013.06.02
5#
6# Author: Giovanni Cannata
7#
8# Copyright 2013 - 2020 Giovanni Cannata
9#
10# This file is part of ldap3.
11#
12# ldap3 is free software: you can redistribute it and/or modify
13# it under the terms of the GNU Lesser General Public License as published
14# by the Free Software Foundation, either version 3 of the License, or
15# (at your option) any later version.
16#
17# ldap3 is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU Lesser General Public License for more details.
21#
22# You should have received a copy of the GNU Lesser General Public License
23# along with ldap3 in the COPYING and COPYING.LESSER files.
24# If not, see <http://www.gnu.org/licenses/>.
25
26from string import whitespace
27from os import linesep
28
29from .. import DEREF_NEVER, BASE, LEVEL, SUBTREE, DEREF_SEARCH, DEREF_BASE, DEREF_ALWAYS, NO_ATTRIBUTES, SEQUENCE_TYPES, get_config_parameter, STRING_TYPES
30
31from ..core.exceptions import LDAPInvalidFilterError, LDAPAttributeError, LDAPInvalidScopeError, LDAPInvalidDereferenceAliasesError
32from ..utils.ciDict import CaseInsensitiveDict
33from ..protocol.rfc4511 import SearchRequest, LDAPDN, Scope, DerefAliases, Integer0ToMax, TypesOnly, \
34 AttributeSelection, Selector, EqualityMatch, AttributeDescription, AssertionValue, Filter, \
35 Not, And, Or, ApproxMatch, GreaterOrEqual, LessOrEqual, ExtensibleMatch, Present, SubstringFilter, \
36 Substrings, Final, Initial, Any, ResultCode, Substring, MatchingRule, Type, MatchValue, DnAttributes
37from ..operation.bind import referrals_to_list
38from ..protocol.convert import ava_to_dict, attributes_to_list, search_refs_to_list, validate_assertion_value, prepare_filter_for_sending, search_refs_to_list_fast
39from ..protocol.formatters.standard import format_attribute_values
40from ..utils.conv import to_unicode, to_raw
41
42ROOT = 0
43AND = 1
44OR = 2
45NOT = 3
46MATCH_APPROX = 4
47MATCH_GREATER_OR_EQUAL = 5
48MATCH_LESS_OR_EQUAL = 6
49MATCH_EXTENSIBLE = 7
50MATCH_PRESENT = 8
51MATCH_SUBSTRING = 9
52MATCH_EQUAL = 10
53
54SEARCH_OPEN = 20
55SEARCH_OPEN_OR_CLOSE = 21
56SEARCH_MATCH_OR_CLOSE = 22
57SEARCH_MATCH_OR_CONTROL = 23
58
59
60class FilterNode(object):
61 def __init__(self, tag=None, assertion=None):
62 self.tag = tag
63 self.parent = None
64 self.assertion = assertion
65 self.elements = []
66
67 def append(self, filter_node):
68 filter_node.parent = self
69 self.elements.append(filter_node)
70 return filter_node
71
72 def __str__(self, pos=0):
73 self.__repr__(pos)
74
75 def __repr__(self, pos=0):
76 node_tags = ['ROOT', 'AND', 'OR', 'NOT', 'MATCH_APPROX', 'MATCH_GREATER_OR_EQUAL', 'MATCH_LESS_OR_EQUAL', 'MATCH_EXTENSIBLE', 'MATCH_PRESENT', 'MATCH_SUBSTRING', 'MATCH_EQUAL']
77 representation = ' ' * pos + 'tag: ' + node_tags[self.tag] + ' - assertion: ' + str(self.assertion)
78 if self.elements:
79 representation += ' - elements: ' + str(len(self.elements))
80 for element in self.elements:
81 representation += linesep + ' ' * pos + element.__repr__(pos + 2)
82 return representation
83
84
85def evaluate_match(match, schema, auto_escape, auto_encode, validator, check_names):
86 left_part, equal_sign, right_part = match.strip().partition('=')
87 if not equal_sign:
88 raise LDAPInvalidFilterError('invalid matching assertion')
89 if left_part.endswith('~'): # approximate match '~='
90 tag = MATCH_APPROX
91 left_part = left_part[:-1].strip()
92 right_part = right_part.strip()
93 assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode, validator, check_names)}
94 elif left_part.endswith('>'): # greater or equal match '>='
95 tag = MATCH_GREATER_OR_EQUAL
96 left_part = left_part[:-1].strip()
97 right_part = right_part.strip()
98 assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode, validator, check_names)}
99 elif left_part.endswith('<'): # less or equal match '<='
100 tag = MATCH_LESS_OR_EQUAL
101 left_part = left_part[:-1].strip()
102 right_part = right_part.strip()
103 assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode, validator, check_names)}
104 elif left_part.endswith(':'): # extensible match ':='
105 tag = MATCH_EXTENSIBLE
106 left_part = left_part[:-1].strip()
107 right_part = right_part.strip()
108 extended_filter_list = left_part.split(':')
109 matching_rule = False
110 dn_attributes = False
111 attribute_name = False
112 if extended_filter_list[0] == '': # extensible filter format [:dn]:matchingRule:=assertionValue
113 if len(extended_filter_list) == 2 and extended_filter_list[1].lower().strip() != 'dn':
114 matching_rule = extended_filter_list[1]
115 elif len(extended_filter_list) == 3 and extended_filter_list[1].lower().strip() == 'dn':
116 dn_attributes = True
117 matching_rule = extended_filter_list[2]
118 else:
119 raise LDAPInvalidFilterError('invalid extensible filter')
120 elif len(extended_filter_list) <= 3: # extensible filter format attr[:dn][:matchingRule]:=assertionValue
121 if len(extended_filter_list) == 1:
122 attribute_name = extended_filter_list[0]
123 elif len(extended_filter_list) == 2:
124 attribute_name = extended_filter_list[0]
125 if extended_filter_list[1].lower().strip() == 'dn':
126 dn_attributes = True
127 else:
128 matching_rule = extended_filter_list[1]
129 elif len(extended_filter_list) == 3 and extended_filter_list[1].lower().strip() == 'dn':
130 attribute_name = extended_filter_list[0]
131 dn_attributes = True
132 matching_rule = extended_filter_list[2]
133 else:
134 raise LDAPInvalidFilterError('invalid extensible filter')
135
136 if not attribute_name and not matching_rule:
137 raise LDAPInvalidFilterError('invalid extensible filter')
138 attribute_name = attribute_name.strip() if attribute_name else False
139 matching_rule = matching_rule.strip() if matching_rule else False
140 assertion = {'attr': attribute_name, 'value': validate_assertion_value(schema, attribute_name, right_part, auto_escape, auto_encode, validator, check_names), 'matchingRule': matching_rule, 'dnAttributes': dn_attributes}
141 elif right_part == '*': # attribute present match '=*'
142 tag = MATCH_PRESENT
143 left_part = left_part.strip()
144 assertion = {'attr': left_part}
145 elif '*' in right_part: # substring match '=initial*substring*substring*final'
146 tag = MATCH_SUBSTRING
147 left_part = left_part.strip()
148 right_part = right_part.strip()
149 substrings = right_part.split('*')
150 initial = validate_assertion_value(schema, left_part, substrings[0], auto_escape, auto_encode, validator, check_names) if substrings[0] else None
151 final = validate_assertion_value(schema, left_part, substrings[-1], auto_escape, auto_encode, validator, check_names) if substrings[-1] else None
152 any_string = [validate_assertion_value(schema, left_part, substring, auto_escape, auto_encode, validator, check_names) for substring in substrings[1:-1] if substring]
153 #assertion = {'attr': left_part, 'initial': initial, 'any': any_string, 'final': final}
154 assertion = {'attr': left_part}
155 if initial:
156 assertion['initial'] = initial
157 if any_string:
158 assertion['any'] = any_string
159 if final:
160 assertion['final'] = final
161 else: # equality match '='
162 tag = MATCH_EQUAL
163 left_part = left_part.strip()
164 right_part = right_part.strip()
165 assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode, validator, check_names)}
166
167 return FilterNode(tag, assertion)
168
169
170def parse_filter(search_filter, schema, auto_escape, auto_encode, validator, check_names):
171 if str is not bytes and isinstance(search_filter, bytes): # python 3 with byte filter
172 search_filter = to_unicode(search_filter)
173 search_filter = search_filter.strip()
174 if search_filter and search_filter.count('(') == search_filter.count(')') and search_filter.startswith('(') and search_filter.endswith(')'):
175 state = SEARCH_OPEN_OR_CLOSE
176 root = FilterNode(ROOT)
177 current_node = root
178 start_pos = None
179 skip_white_space = True
180 just_closed = False
181 for pos, c in enumerate(search_filter):
182 if skip_white_space and c in whitespace:
183 continue
184 elif (state == SEARCH_OPEN or state == SEARCH_OPEN_OR_CLOSE) and c == '(':
185 state = SEARCH_MATCH_OR_CONTROL
186 just_closed = False
187 elif state == SEARCH_MATCH_OR_CONTROL and c in '&!|':
188 if c == '&':
189 current_node = current_node.append(FilterNode(AND))
190 elif c == '|':
191 current_node = current_node.append(FilterNode(OR))
192 elif c == '!':
193 current_node = current_node.append(FilterNode(NOT))
194 state = SEARCH_OPEN
195 elif (state == SEARCH_MATCH_OR_CLOSE or state == SEARCH_OPEN_OR_CLOSE) and c == ')':
196 if just_closed:
197 current_node = current_node.parent
198 else:
199 just_closed = True
200 skip_white_space = True
201 end_pos = pos
202 if start_pos:
203 if current_node.tag == NOT and len(current_node.elements) > 0:
204 raise LDAPInvalidFilterError('NOT (!) clause in filter cannot be multiple')
205 current_node.append(evaluate_match(search_filter[start_pos:end_pos], schema, auto_escape, auto_encode, validator, check_names))
206 start_pos = None
207 state = SEARCH_OPEN_OR_CLOSE
208 elif (state == SEARCH_MATCH_OR_CLOSE or state == SEARCH_MATCH_OR_CONTROL) and c not in '()':
209 skip_white_space = False
210 if not start_pos:
211 start_pos = pos
212 state = SEARCH_MATCH_OR_CLOSE
213 else:
214 raise LDAPInvalidFilterError('malformed filter')
215 if len(root.elements) != 1:
216 raise LDAPInvalidFilterError('missing boolean operator in filter')
217 return root
218 else:
219 raise LDAPInvalidFilterError('invalid filter')
220
221
222def compile_filter(filter_node):
223 """Builds ASN1 structure for filter, converts from filter LDAP escaping to bytes"""
224 compiled_filter = Filter()
225 if filter_node.tag == AND:
226 boolean_filter = And()
227 pos = 0
228 for element in filter_node.elements:
229 boolean_filter[pos] = compile_filter(element)
230 pos += 1
231 compiled_filter['and'] = boolean_filter
232 elif filter_node.tag == OR:
233 boolean_filter = Or()
234 pos = 0
235 for element in filter_node.elements:
236 boolean_filter[pos] = compile_filter(element)
237 pos += 1
238 compiled_filter['or'] = boolean_filter
239 elif filter_node.tag == NOT:
240 boolean_filter = Not()
241 boolean_filter['innerNotFilter'] = compile_filter(filter_node.elements[0])
242 compiled_filter.setComponentByName('notFilter', boolean_filter, verifyConstraints=False) # do not verify constraints because of hack for recursive filters in rfc4511
243
244 elif filter_node.tag == MATCH_APPROX:
245 matching_filter = ApproxMatch()
246 matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
247 matching_filter['assertionValue'] = AssertionValue(prepare_filter_for_sending(filter_node.assertion['value']))
248 compiled_filter['approxMatch'] = matching_filter
249 elif filter_node.tag == MATCH_GREATER_OR_EQUAL:
250 matching_filter = GreaterOrEqual()
251 matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
252 matching_filter['assertionValue'] = AssertionValue(prepare_filter_for_sending(filter_node.assertion['value']))
253 compiled_filter['greaterOrEqual'] = matching_filter
254 elif filter_node.tag == MATCH_LESS_OR_EQUAL:
255 matching_filter = LessOrEqual()
256 matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
257 matching_filter['assertionValue'] = AssertionValue(prepare_filter_for_sending(filter_node.assertion['value']))
258 compiled_filter['lessOrEqual'] = matching_filter
259 elif filter_node.tag == MATCH_EXTENSIBLE:
260 matching_filter = ExtensibleMatch()
261 if filter_node.assertion['matchingRule']:
262 matching_filter['matchingRule'] = MatchingRule(filter_node.assertion['matchingRule'])
263 if filter_node.assertion['attr']:
264 matching_filter['type'] = Type(filter_node.assertion['attr'])
265 matching_filter['matchValue'] = MatchValue(prepare_filter_for_sending(filter_node.assertion['value']))
266 matching_filter['dnAttributes'] = DnAttributes(filter_node.assertion['dnAttributes'])
267 compiled_filter['extensibleMatch'] = matching_filter
268 elif filter_node.tag == MATCH_PRESENT:
269 matching_filter = Present(AttributeDescription(filter_node.assertion['attr']))
270 compiled_filter['present'] = matching_filter
271 elif filter_node.tag == MATCH_SUBSTRING:
272 matching_filter = SubstringFilter()
273 matching_filter['type'] = AttributeDescription(filter_node.assertion['attr'])
274 substrings = Substrings()
275 pos = 0
276 if 'initial' in filter_node.assertion and filter_node.assertion['initial']:
277 substrings[pos] = Substring().setComponentByName('initial', Initial(prepare_filter_for_sending(filter_node.assertion['initial'])))
278 pos += 1
279 if 'any' in filter_node.assertion and filter_node.assertion['any']:
280 for substring in filter_node.assertion['any']:
281 substrings[pos] = Substring().setComponentByName('any', Any(prepare_filter_for_sending(substring)))
282 pos += 1
283 if 'final' in filter_node.assertion and filter_node.assertion['final']:
284 substrings[pos] = Substring().setComponentByName('final', Final(prepare_filter_for_sending(filter_node.assertion['final'])))
285 matching_filter['substrings'] = substrings
286 compiled_filter['substringFilter'] = matching_filter
287 elif filter_node.tag == MATCH_EQUAL:
288 matching_filter = EqualityMatch()
289 matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
290 matching_filter['assertionValue'] = AssertionValue(prepare_filter_for_sending(filter_node.assertion['value']))
291 compiled_filter.setComponentByName('equalityMatch', matching_filter)
292 else:
293 raise LDAPInvalidFilterError('unknown filter node tag')
294
295 return compiled_filter
296
297
298def build_attribute_selection(attribute_list, schema):
299 conf_attributes_excluded_from_check = [v.lower() for v in get_config_parameter('ATTRIBUTES_EXCLUDED_FROM_CHECK')]
300
301 attribute_selection = AttributeSelection()
302 for index, attribute in enumerate(attribute_list):
303 if schema and schema.attribute_types:
304 if ';' in attribute: # exclude tags from validation
305 if not attribute[0:attribute.index(';')] in schema.attribute_types and attribute.lower() not in conf_attributes_excluded_from_check:
306 raise LDAPAttributeError('invalid attribute type in attribute list: ' + attribute)
307 else:
308 if attribute not in schema.attribute_types and attribute.lower() not in conf_attributes_excluded_from_check:
309 raise LDAPAttributeError('invalid attribute type in attribute list: ' + attribute)
310 attribute_selection[index] = Selector(attribute)
311
312 return attribute_selection
313
314
315def search_operation(search_base,
316 search_filter,
317 search_scope,
318 dereference_aliases,
319 attributes,
320 size_limit,
321 time_limit,
322 types_only,
323 auto_escape,
324 auto_encode,
325 schema=None,
326 validator=None,
327 check_names=False):
328 # SearchRequest ::= [APPLICATION 3] SEQUENCE {
329 # baseObject LDAPDN,
330 # scope ENUMERATED {
331 # baseObject (0),
332 # singleLevel (1),
333 # wholeSubtree (2),
334 # ... },
335 # derefAliases ENUMERATED {
336 # neverDerefAliases (0),
337 # derefInSearching (1),
338 # derefFindingBaseObj (2),
339 # derefAlways (3) },
340 # sizeLimit INTEGER (0 .. maxInt),
341 # timeLimit INTEGER (0 .. maxInt),
342 # typesOnly BOOLEAN,
343 # filter Filter,
344 # attributes AttributeSelection }
345 request = SearchRequest()
346 request['baseObject'] = LDAPDN(search_base)
347
348 if search_scope == BASE or search_scope == 0:
349 request['scope'] = Scope('baseObject')
350 elif search_scope == LEVEL or search_scope == 1:
351 request['scope'] = Scope('singleLevel')
352 elif search_scope == SUBTREE or search_scope == 2:
353 request['scope'] = Scope('wholeSubtree')
354 else:
355 raise LDAPInvalidScopeError('invalid scope type')
356
357 if dereference_aliases == DEREF_NEVER or dereference_aliases == 0:
358 request['derefAliases'] = DerefAliases('neverDerefAliases')
359 elif dereference_aliases == DEREF_SEARCH or dereference_aliases == 1:
360 request['derefAliases'] = DerefAliases('derefInSearching')
361 elif dereference_aliases == DEREF_BASE or dereference_aliases == 2:
362 request['derefAliases'] = DerefAliases('derefFindingBaseObj')
363 elif dereference_aliases == DEREF_ALWAYS or dereference_aliases == 3:
364 request['derefAliases'] = DerefAliases('derefAlways')
365 else:
366 raise LDAPInvalidDereferenceAliasesError('invalid dereference aliases type')
367
368 request['sizeLimit'] = Integer0ToMax(size_limit)
369 request['timeLimit'] = Integer0ToMax(time_limit)
370 request['typesOnly'] = TypesOnly(True) if types_only else TypesOnly(False)
371 request['filter'] = compile_filter(parse_filter(search_filter, schema, auto_escape, auto_encode, validator, check_names).elements[0]) # parse the searchFilter string and compile it starting from the root node
372 if not isinstance(attributes, SEQUENCE_TYPES):
373 attributes = [NO_ATTRIBUTES]
374
375 request['attributes'] = build_attribute_selection(attributes, schema)
376
377 return request
378
379
380def decode_vals(vals):
381 try:
382 return [str(val) for val in vals if val] if vals else None
383 except UnicodeDecodeError:
384 return decode_raw_vals(vals)
385
386def decode_vals_fast(vals):
387 try:
388 return [to_unicode(val[3], from_server=True) for val in vals if val] if vals else None
389 except UnicodeDecodeError:
390 return [val[3] for val in vals if val] if vals else None
391
392
393def attributes_to_dict(attribute_list):
394 conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
395 attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
396 for attribute in attribute_list:
397 attributes[str(attribute['type'])] = decode_vals(attribute['vals'])
398 return attributes
399
400
401def attributes_to_dict_fast(attribute_list):
402 conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
403 attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
404 for attribute in attribute_list:
405 attributes[to_unicode(attribute[3][0][3], from_server=True)] = decode_vals_fast(attribute[3][1][3])
406
407 return attributes
408
409
410def decode_raw_vals(vals):
411 return [bytes(val) for val in vals] if vals else None
412
413
414def decode_raw_vals_fast(vals):
415 return [bytes(val[3]) for val in vals] if vals else None
416
417
418def raw_attributes_to_dict(attribute_list):
419 conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
420
421 attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
422 for attribute in attribute_list:
423 attributes[str(attribute['type'])] = decode_raw_vals(attribute['vals'])
424
425 return attributes
426
427
428def raw_attributes_to_dict_fast(attribute_list):
429 conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
430 attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
431 for attribute in attribute_list:
432 attributes[to_unicode(attribute[3][0][3], from_server=True)] = decode_raw_vals_fast(attribute[3][1][3])
433
434 return attributes
435
436
437def checked_attributes_to_dict(attribute_list, schema=None, custom_formatter=None):
438 conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
439
440 checked_attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
441 for attribute in attribute_list:
442 name = str(attribute['type'])
443 checked_attributes[name] = format_attribute_values(schema, name, decode_raw_vals(attribute['vals']) or [], custom_formatter)
444 return checked_attributes
445
446
447def checked_attributes_to_dict_fast(attribute_list, schema=None, custom_formatter=None):
448 conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
449
450 checked_attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
451 for attribute in attribute_list:
452 name = to_unicode(attribute[3][0][3], from_server=True)
453 checked_attributes[name] = format_attribute_values(schema, name, decode_raw_vals_fast(attribute[3][1][3]) or [], custom_formatter)
454 return checked_attributes
455
456
457def matching_rule_assertion_to_string(matching_rule_assertion):
458 return str(matching_rule_assertion)
459
460
461def filter_to_string(filter_object):
462 filter_type = filter_object.getName()
463 filter_string = '('
464 if filter_type == 'and':
465 filter_string += '&'
466 for f in filter_object['and']:
467 filter_string += filter_to_string(f)
468 elif filter_type == 'or':
469 filter_string += '|'
470 for f in filter_object['or']:
471 filter_string += filter_to_string(f)
472 elif filter_type == 'notFilter':
473 filter_string += '!' + filter_to_string(filter_object['notFilter']['innerNotFilter'])
474 elif filter_type == 'equalityMatch':
475 ava = ava_to_dict(filter_object['equalityMatch'])
476 filter_string += ava['attribute'] + '=' + ava['value']
477 elif filter_type == 'substringFilter':
478 attribute = filter_object['substringFilter']['type']
479 filter_string += str(attribute) + '='
480 for substring in filter_object['substringFilter']['substrings']:
481 component = substring.getName()
482 if substring[component] is not None and substring[component].hasValue():
483 if component == 'initial':
484 filter_string += str(substring['initial']) + '*'
485 elif component == 'any':
486 filter_string += str(substring['any']) if filter_string.endswith('*') else '*' + str(substring['any'])
487 filter_string += '*'
488 elif component == 'final':
489 filter_string += '*' + str(substring['final'])
490 elif filter_type == 'greaterOrEqual':
491 ava = ava_to_dict(filter_object['greaterOrEqual'])
492 filter_string += ava['attribute'] + '>=' + ava['value']
493 elif filter_type == 'lessOrEqual':
494 ava = ava_to_dict(filter_object['lessOrEqual'])
495 filter_string += ava['attribute'] + '<=' + ava['value']
496 elif filter_type == 'present':
497 filter_string += str(filter_object['present']) + '=*'
498 elif filter_type == 'approxMatch':
499 ava = ava_to_dict(filter_object['approxMatch'])
500 filter_string += ava['attribute'] + '~=' + ava['value']
501 elif filter_type == 'extensibleMatch':
502 filter_string += matching_rule_assertion_to_string(filter_object['extensibleMatch'])
503 else:
504 raise LDAPInvalidFilterError('error converting filter to string')
505 filter_string += ')'
506
507 if str is bytes: # Python2, forces conversion to Unicode
508 filter_string = to_unicode(filter_string)
509
510 return filter_string
511
512
513def search_request_to_dict(request):
514 return {'base': str(request['baseObject']),
515 'scope': int(request['scope']),
516 'dereferenceAlias': int(request['derefAliases']),
517 'sizeLimit': int(request['sizeLimit']),
518 'timeLimit': int(request['timeLimit']),
519 'typesOnly': bool(request['typesOnly']),
520 'filter': filter_to_string(request['filter']),
521 'attributes': attributes_to_list(request['attributes'])}
522
523
524def search_result_entry_response_to_dict(response, schema, custom_formatter, check_names):
525 entry = dict()
526 # entry['dn'] = str(response['object'])
527 if response['object']:
528 if isinstance(response['object'], STRING_TYPES): # mock strategies return string not a PyAsn1 object
529 entry['raw_dn'] = to_raw(response['object'])
530 entry['dn'] = to_unicode(response['object'])
531 else:
532 entry['raw_dn'] = str(response['object'])
533 entry['dn'] = to_unicode(bytes(response['object']), from_server=True)
534 else:
535 entry['raw_dn'] = b''
536 entry['dn'] = ''
537 entry['raw_attributes'] = raw_attributes_to_dict(response['attributes'])
538 if check_names:
539 entry['attributes'] = checked_attributes_to_dict(response['attributes'], schema, custom_formatter)
540 else:
541 entry['attributes'] = attributes_to_dict(response['attributes'])
542
543 return entry
544
545
546def search_result_done_response_to_dict(response):
547 result = {'result': int(response['resultCode']),
548 'description': ResultCode().getNamedValues().getName(response['resultCode']),
549 'message': str(response['diagnosticMessage']),
550 'dn': str(response['matchedDN']),
551 'referrals': referrals_to_list(response['referral'])}
552
553 if 'controls' in response: # used for returning controls in Mock strategies
554 result['controls'] = dict()
555 for control in response['controls']:
556 result['controls'][control[0]] = control[1]
557
558 return result
559
560
561def search_result_reference_response_to_dict(response):
562 return {'uri': search_refs_to_list(response)}
563
564
565def search_result_entry_response_to_dict_fast(response, schema, custom_formatter, check_names):
566 entry_dict = dict()
567 entry_dict['raw_dn'] = response[0][3]
568 entry_dict['dn'] = to_unicode(response[0][3], from_server=True)
569 entry_dict['raw_attributes'] = raw_attributes_to_dict_fast(response[1][3]) # attributes
570 if check_names:
571 entry_dict['attributes'] = checked_attributes_to_dict_fast(response[1][3], schema, custom_formatter) # attributes
572 else:
573 entry_dict['attributes'] = attributes_to_dict_fast(response[1][3]) # attributes
574
575 return entry_dict
576
577
578def search_result_reference_response_to_dict_fast(response):
579 return {'uri': search_refs_to_list_fast([r[3] for r in response])}
580 