Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

convert.py 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. """
  2. """
  3. # Created on 2013.07.24
  4. #
  5. # Author: Giovanni Cannata
  6. #
  7. # Copyright 2013 - 2018 Giovanni Cannata
  8. #
  9. # This file is part of ldap3.
  10. #
  11. # ldap3 is free software: you can redistribute it and/or modify
  12. # it under the terms of the GNU Lesser General Public License as published
  13. # by the Free Software Foundation, either version 3 of the License, or
  14. # (at your option) any later version.
  15. #
  16. # ldap3 is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. # GNU Lesser General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU Lesser General Public License
  22. # along with ldap3 in the COPYING and COPYING.LESSER files.
  23. # If not, see <http://www.gnu.org/licenses/>.
  24. from pyasn1.error import PyAsn1Error
  25. from .. import SEQUENCE_TYPES, STRING_TYPES, get_config_parameter
  26. from ..core.exceptions import LDAPControlError, LDAPAttributeError, LDAPObjectClassError, LDAPInvalidValueError
  27. from ..protocol.rfc4511 import Controls, Control
  28. from ..utils.conv import to_raw, to_unicode, escape_filter_chars, is_filter_escaped
  29. from ..protocol.formatters.standard import find_attribute_validator
  30. def attribute_to_dict(attribute):
  31. try:
  32. return {'type': str(attribute['type']), 'values': [str(val) for val in attribute['vals']]}
  33. except PyAsn1Error: # invalid encoding, return bytes value
  34. return {'type': str(attribute['type']), 'values': [bytes(val) for val in attribute['vals']]}
  35. def attributes_to_dict(attributes):
  36. attributes_dict = dict()
  37. for attribute in attributes:
  38. attribute_dict = attribute_to_dict(attribute)
  39. attributes_dict[attribute_dict['type']] = attribute_dict['values']
  40. return attributes_dict
  41. def referrals_to_list(referrals):
  42. return [str(referral) for referral in referrals if referral] if referrals else None
  43. def search_refs_to_list(search_refs):
  44. return [str(search_ref) for search_ref in search_refs if search_ref] if search_refs else None
  45. def search_refs_to_list_fast(search_refs):
  46. return [to_unicode(search_ref) for search_ref in search_refs if search_ref] if search_refs else None
  47. def sasl_to_dict(sasl):
  48. return {'mechanism': str(sasl['mechanism']), 'credentials': bytes(sasl['credentials']) if sasl['credentials'] is not None and sasl['credentials'].hasValue() else None}
  49. def authentication_choice_to_dict(authentication_choice):
  50. return {'simple': str(authentication_choice['simple']) if authentication_choice.getName() == 'simple' else None, 'sasl': sasl_to_dict(authentication_choice['sasl']) if authentication_choice.getName() == 'sasl' else None}
  51. def partial_attribute_to_dict(modification):
  52. try:
  53. return {'type': str(modification['type']), 'value': [str(value) for value in modification['vals']]}
  54. except PyAsn1Error: # invalid encoding, return bytes value
  55. return {'type': str(modification['type']), 'value': [bytes(value) for value in modification['vals']]}
  56. def change_to_dict(change):
  57. return {'operation': int(change['operation']), 'attribute': partial_attribute_to_dict(change['modification'])}
  58. def changes_to_list(changes):
  59. return [change_to_dict(change) for change in changes]
  60. def attributes_to_list(attributes):
  61. return [str(attribute) for attribute in attributes]
  62. def ava_to_dict(ava):
  63. try:
  64. return {'attribute': str(ava['attributeDesc']), 'value': escape_filter_chars(str(ava['assertionValue']))}
  65. except Exception: # invalid encoding, return bytes value
  66. try:
  67. return {'attribute': str(ava['attributeDesc']), 'value': escape_filter_chars(bytes(ava['assertionValue']))}
  68. except Exception:
  69. return {'attribute': str(ava['attributeDesc']), 'value': bytes(ava['assertionValue'])}
  70. def substring_to_dict(substring):
  71. return {'initial': substring['initial'] if substring['initial'] else '', 'any': [middle for middle in substring['any']] if substring['any'] else '', 'final': substring['final'] if substring['final'] else ''}
  72. def prepare_changes_for_request(changes):
  73. prepared = dict()
  74. for change in changes:
  75. attribute_name = change['attribute']['type']
  76. if attribute_name not in prepared:
  77. prepared[attribute_name] = []
  78. prepared[attribute_name].append((change['operation'], change['attribute']['value']))
  79. return prepared
  80. def build_controls_list(controls):
  81. """controls is a sequence of Control() or sequences
  82. each sequence must have 3 elements: the control OID, the criticality, the value
  83. criticality must be a boolean
  84. """
  85. if not controls:
  86. return None
  87. if not isinstance(controls, SEQUENCE_TYPES):
  88. raise LDAPControlError('controls must be a sequence')
  89. built_controls = Controls()
  90. for idx, control in enumerate(controls):
  91. if isinstance(control, Control):
  92. built_controls.setComponentByPosition(idx, control)
  93. elif len(control) == 3 and isinstance(control[1], bool):
  94. built_control = Control()
  95. built_control['controlType'] = control[0]
  96. built_control['criticality'] = control[1]
  97. if control[2] is not None:
  98. built_control['controlValue'] = control[2]
  99. built_controls.setComponentByPosition(idx, built_control)
  100. else:
  101. raise LDAPControlError('control must be a sequence of 3 elements: controlType, criticality (boolean) and controlValue (None if not provided)')
  102. return built_controls
  103. def validate_assertion_value(schema, name, value, auto_escape, auto_encode, validator, check_names):
  104. value = to_unicode(value)
  105. if auto_escape:
  106. if '\\' in value and not is_filter_escaped(value):
  107. value = escape_filter_chars(value)
  108. value = validate_attribute_value(schema, name, value, auto_encode, validator=validator, check_names=check_names)
  109. return value
  110. def validate_attribute_value(schema, name, value, auto_encode, validator=None, check_names=False):
  111. conf_classes_excluded_from_check = [v.lower() for v in get_config_parameter('CLASSES_EXCLUDED_FROM_CHECK')]
  112. conf_attributes_excluded_from_check = [v.lower() for v in get_config_parameter('ATTRIBUTES_EXCLUDED_FROM_CHECK')]
  113. conf_utf8_syntaxes = get_config_parameter('UTF8_ENCODED_SYNTAXES')
  114. conf_utf8_types = [v.lower() for v in get_config_parameter('UTF8_ENCODED_TYPES')]
  115. if schema and schema.attribute_types:
  116. if ';' in name:
  117. name = name.split(';')[0]
  118. if check_names and schema.object_classes and name.lower() == 'objectclass':
  119. if to_unicode(value).lower() not in conf_classes_excluded_from_check and to_unicode(value) not in schema.object_classes:
  120. raise LDAPObjectClassError('invalid class in objectClass attribute: ' + str(value))
  121. elif check_names and name not in schema.attribute_types and name.lower() not in conf_attributes_excluded_from_check:
  122. raise LDAPAttributeError('invalid attribute ' + name)
  123. else: # try standard validators
  124. validator = find_attribute_validator(schema, name, validator)
  125. validated = validator(value)
  126. if validated is False:
  127. try: # checks if the value is a byte value erroneously converted to a string (as "b'1234'"), this is a common case in Python 3 when encoding is not specified
  128. if value[0:2] == "b'" and value [-1] == "'":
  129. value = to_raw(value[2:-1])
  130. validated = validator(value)
  131. except Exception:
  132. raise LDAPInvalidValueError('value \'%s\' non valid for attribute \'%s\'' % (value, name))
  133. if validated is False:
  134. raise LDAPInvalidValueError('value \'%s\' non valid for attribute \'%s\'' % (value, name))
  135. elif validated is not True: # a valid LDAP value equivalent to the actual value
  136. value = validated
  137. # converts to utf-8 for well known Unicode LDAP syntaxes
  138. if auto_encode and ((name in schema.attribute_types and schema.attribute_types[name].syntax in conf_utf8_syntaxes) or name.lower() in conf_utf8_types):
  139. value = to_unicode(value) # tries to convert from local encoding to Unicode
  140. return to_raw(value)
  141. def prepare_filter_for_sending(raw_string):
  142. i = 0
  143. ints = []
  144. raw_string = to_raw(raw_string)
  145. while i < len(raw_string):
  146. if (raw_string[i] == 92 or raw_string[i] == '\\') and i < len(raw_string) - 2: # 92 is backslash
  147. try:
  148. ints.append(int(raw_string[i + 1: i + 3], 16))
  149. i += 2
  150. except ValueError: # not an ldap escaped value, sends as is
  151. ints.append(92) # adds backslash
  152. else:
  153. if str is not bytes: # Python 3
  154. ints.append(raw_string[i])
  155. else: # Python 2
  156. ints.append(ord(raw_string[i]))
  157. i += 1
  158. if str is not bytes: # Python 3
  159. return bytes(ints)
  160. else: # Python 2
  161. return ''.join(chr(x) for x in ints)
  162. def prepare_for_sending(raw_string):
  163. return to_raw(raw_string) if isinstance(raw_string, STRING_TYPES) else raw_string