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.

standard.py 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. """
  2. """
  3. # Created on 2014.10.28
  4. #
  5. # Author: Giovanni Cannata
  6. #
  7. # Copyright 2014 - 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 ... import SEQUENCE_TYPES
  25. from .formatters import format_ad_timestamp, format_binary, format_boolean,\
  26. format_integer, format_sid, format_time, format_unicode, format_uuid, format_uuid_le, format_time_with_0_year
  27. from .validators import validate_integer, validate_time, always_valid,\
  28. validate_generic_single_value, validate_boolean, validate_ad_timestamp,\
  29. validate_uuid_le, validate_uuid, validate_zero_and_minus_one, validate_guid, validate_time_with_0_year
  30. # for each syntax can be specified a format function and a input validation function
  31. standard_formatter = {
  32. '1.2.840.113556.1.4.903': (format_binary, None), # Object (DN-binary) - Microsoft
  33. '1.2.840.113556.1.4.904': (format_unicode, None), # Object (DN-string) - Microsoft
  34. '1.2.840.113556.1.4.905': (format_unicode, None), # String (Teletex) - Microsoft
  35. '1.2.840.113556.1.4.906': (format_integer, validate_integer), # Large integer - Microsoft
  36. '1.2.840.113556.1.4.907': (format_binary, None), # String (NT-sec-desc) - Microsoft
  37. '1.2.840.113556.1.4.1221': (format_binary, None), # Object (OR-name) - Microsoft
  38. '1.2.840.113556.1.4.1362': (format_unicode, None), # String (Case) - Microsoft
  39. '1.3.6.1.4.1.1466.115.121.1.1': (format_binary, None), # ACI item [OBSOLETE]
  40. '1.3.6.1.4.1.1466.115.121.1.2': (format_binary, None), # Access point [OBSOLETE]
  41. '1.3.6.1.4.1.1466.115.121.1.3': (format_unicode, None), # Attribute type description
  42. '1.3.6.1.4.1.1466.115.121.1.4': (format_binary, None), # Audio [OBSOLETE]
  43. '1.3.6.1.4.1.1466.115.121.1.5': (format_binary, None), # Binary [OBSOLETE]
  44. '1.3.6.1.4.1.1466.115.121.1.6': (format_unicode, None), # Bit String
  45. '1.3.6.1.4.1.1466.115.121.1.7': (format_boolean, validate_boolean), # Boolean
  46. '1.3.6.1.4.1.1466.115.121.1.8': (format_binary, None), # Certificate [OBSOLETE]
  47. '1.3.6.1.4.1.1466.115.121.1.9': (format_binary, None), # Certificate List [OBSOLETE]
  48. '1.3.6.1.4.1.1466.115.121.1.10': (format_binary, None), # Certificate Pair [OBSOLETE]
  49. '1.3.6.1.4.1.1466.115.121.1.11': (format_unicode, None), # Country String
  50. '1.3.6.1.4.1.1466.115.121.1.12': (format_unicode, None), # Distinguished name (DN)
  51. '1.3.6.1.4.1.1466.115.121.1.13': (format_binary, None), # Data Quality Syntax [OBSOLETE]
  52. '1.3.6.1.4.1.1466.115.121.1.14': (format_unicode, None), # Delivery method
  53. '1.3.6.1.4.1.1466.115.121.1.15': (format_unicode, None), # Directory string
  54. '1.3.6.1.4.1.1466.115.121.1.16': (format_unicode, None), # DIT Content Rule Description
  55. '1.3.6.1.4.1.1466.115.121.1.17': (format_unicode, None), # DIT Structure Rule Description
  56. '1.3.6.1.4.1.1466.115.121.1.18': (format_binary, None), # DL Submit Permission [OBSOLETE]
  57. '1.3.6.1.4.1.1466.115.121.1.19': (format_binary, None), # DSA Quality Syntax [OBSOLETE]
  58. '1.3.6.1.4.1.1466.115.121.1.20': (format_binary, None), # DSE Type [OBSOLETE]
  59. '1.3.6.1.4.1.1466.115.121.1.21': (format_binary, None), # Enhanced Guide
  60. '1.3.6.1.4.1.1466.115.121.1.22': (format_unicode, None), # Facsimile Telephone Number
  61. '1.3.6.1.4.1.1466.115.121.1.23': (format_binary, None), # Fax
  62. '1.3.6.1.4.1.1466.115.121.1.24': (format_time, validate_time), # Generalized time
  63. '1.3.6.1.4.1.1466.115.121.1.25': (format_binary, None), # Guide [OBSOLETE]
  64. '1.3.6.1.4.1.1466.115.121.1.26': (format_unicode, None), # IA5 string
  65. '1.3.6.1.4.1.1466.115.121.1.27': (format_integer, validate_integer), # Integer
  66. '1.3.6.1.4.1.1466.115.121.1.28': (format_binary, None), # JPEG
  67. '1.3.6.1.4.1.1466.115.121.1.29': (format_binary, None), # Master and Shadow Access Points [OBSOLETE]
  68. '1.3.6.1.4.1.1466.115.121.1.30': (format_unicode, None), # Matching rule description
  69. '1.3.6.1.4.1.1466.115.121.1.31': (format_unicode, None), # Matching rule use description
  70. '1.3.6.1.4.1.1466.115.121.1.32': (format_unicode, None), # Mail Preference [OBSOLETE]
  71. '1.3.6.1.4.1.1466.115.121.1.33': (format_unicode, None), # MHS OR Address [OBSOLETE]
  72. '1.3.6.1.4.1.1466.115.121.1.34': (format_unicode, None), # Name and optional UID
  73. '1.3.6.1.4.1.1466.115.121.1.35': (format_unicode, None), # Name form description
  74. '1.3.6.1.4.1.1466.115.121.1.36': (format_unicode, None), # Numeric string
  75. '1.3.6.1.4.1.1466.115.121.1.37': (format_unicode, None), # Object class description
  76. '1.3.6.1.4.1.1466.115.121.1.38': (format_unicode, None), # OID
  77. '1.3.6.1.4.1.1466.115.121.1.39': (format_unicode, None), # Other mailbox
  78. '1.3.6.1.4.1.1466.115.121.1.40': (format_binary, None), # Octet string
  79. '1.3.6.1.4.1.1466.115.121.1.41': (format_unicode, None), # Postal address
  80. '1.3.6.1.4.1.1466.115.121.1.42': (format_binary, None), # Protocol Information [OBSOLETE]
  81. '1.3.6.1.4.1.1466.115.121.1.43': (format_binary, None), # Presentation Address [OBSOLETE]
  82. '1.3.6.1.4.1.1466.115.121.1.44': (format_unicode, None), # Printable string
  83. '1.3.6.1.4.1.1466.115.121.1.45': (format_binary, None), # Subtree specification [OBSOLETE
  84. '1.3.6.1.4.1.1466.115.121.1.46': (format_binary, None), # Supplier Information [OBSOLETE]
  85. '1.3.6.1.4.1.1466.115.121.1.47': (format_binary, None), # Supplier Or Consumer [OBSOLETE]
  86. '1.3.6.1.4.1.1466.115.121.1.48': (format_binary, None), # Supplier And Consumer [OBSOLETE]
  87. '1.3.6.1.4.1.1466.115.121.1.49': (format_binary, None), # Supported Algorithm [OBSOLETE]
  88. '1.3.6.1.4.1.1466.115.121.1.50': (format_unicode, None), # Telephone number
  89. '1.3.6.1.4.1.1466.115.121.1.51': (format_unicode, None), # Teletex terminal identifier
  90. '1.3.6.1.4.1.1466.115.121.1.52': (format_unicode, None), # Teletex number
  91. '1.3.6.1.4.1.1466.115.121.1.53': (format_time, validate_time), # Utc time (deprecated)
  92. '1.3.6.1.4.1.1466.115.121.1.54': (format_unicode, None), # LDAP syntax description
  93. '1.3.6.1.4.1.1466.115.121.1.55': (format_binary, None), # Modify rights [OBSOLETE]
  94. '1.3.6.1.4.1.1466.115.121.1.56': (format_binary, None), # LDAP Schema Definition [OBSOLETE]
  95. '1.3.6.1.4.1.1466.115.121.1.57': (format_unicode, None), # LDAP Schema Description [OBSOLETE]
  96. '1.3.6.1.4.1.1466.115.121.1.58': (format_unicode, None), # Substring assertion
  97. '1.3.6.1.1.16.1': (format_uuid, validate_uuid), # UUID
  98. '1.3.6.1.1.16.4': (format_uuid, validate_uuid), # entryUUID (RFC 4530)
  99. '2.16.840.1.113719.1.1.4.1.501': (format_uuid, validate_guid), # GUID (Novell)
  100. '2.16.840.1.113719.1.1.5.1.0': (format_binary, None), # Unknown (Novell)
  101. '2.16.840.1.113719.1.1.5.1.6': (format_unicode, None), # Case Ignore List (Novell)
  102. '2.16.840.1.113719.1.1.5.1.12': (format_binary, None), # Tagged Data (Novell)
  103. '2.16.840.1.113719.1.1.5.1.13': (format_binary, None), # Octet List (Novell)
  104. '2.16.840.1.113719.1.1.5.1.14': (format_unicode, None), # Tagged String (Novell)
  105. '2.16.840.1.113719.1.1.5.1.15': (format_unicode, None), # Tagged Name And String (Novell)
  106. '2.16.840.1.113719.1.1.5.1.16': (format_binary, None), # NDS Replica Pointer (Novell)
  107. '2.16.840.1.113719.1.1.5.1.17': (format_unicode, None), # NDS ACL (Novell)
  108. '2.16.840.1.113719.1.1.5.1.19': (format_time, validate_time), # NDS Timestamp (Novell)
  109. '2.16.840.1.113719.1.1.5.1.22': (format_integer, validate_integer), # Counter (Novell)
  110. '2.16.840.1.113719.1.1.5.1.23': (format_unicode, None), # Tagged Name (Novell)
  111. '2.16.840.1.113719.1.1.5.1.25': (format_unicode, None), # Typed Name (Novell)
  112. 'supportedldapversion': (format_integer, None), # supportedLdapVersion (Microsoft)
  113. 'octetstring': (format_binary, validate_uuid_le), # octect string (Microsoft)
  114. '1.2.840.113556.1.4.2': (format_uuid_le, validate_uuid_le), # object guid (Microsoft)
  115. '1.2.840.113556.1.4.13': (format_ad_timestamp, validate_ad_timestamp), # builtinCreationTime (Microsoft)
  116. '1.2.840.113556.1.4.26': (format_ad_timestamp, validate_ad_timestamp), # creationTime (Microsoft)
  117. '1.2.840.113556.1.4.49': (format_ad_timestamp, validate_ad_timestamp), # badPasswordTime (Microsoft)
  118. '1.2.840.113556.1.4.51': (format_ad_timestamp, validate_ad_timestamp), # lastLogoff (Microsoft)
  119. '1.2.840.113556.1.4.52': (format_ad_timestamp, validate_ad_timestamp), # lastLogon (Microsoft)
  120. '1.2.840.113556.1.4.96': (format_ad_timestamp, validate_zero_and_minus_one), # pwdLastSet (Microsoft, can be set to -1 only)
  121. '1.2.840.113556.1.4.146': (format_sid, None), # objectSid (Microsoft)
  122. '1.2.840.113556.1.4.159': (format_ad_timestamp, validate_ad_timestamp), # accountExpires (Microsoft)
  123. '1.2.840.113556.1.4.662': (format_ad_timestamp, validate_ad_timestamp), # lockoutTime (Microsoft)
  124. '1.2.840.113556.1.4.1696': (format_ad_timestamp, validate_ad_timestamp), # lastLogonTimestamp (Microsoft)
  125. '1.3.6.1.4.1.42.2.27.8.1.17': (format_time_with_0_year, validate_time_with_0_year) # pwdAccountLockedTime (Novell)
  126. }
  127. def find_attribute_helpers(attr_type, name, custom_formatter):
  128. """
  129. Tries to format following the OIDs info and format_helper specification.
  130. Search for attribute oid, then attribute name (can be multiple), then attribute syntax
  131. Precedence is:
  132. 1. attribute name
  133. 2. attribute oid(from schema)
  134. 3. attribute names (from oid_info)
  135. 4. attribute syntax (from schema)
  136. Custom formatters can be defined in Server object and have precedence over the standard_formatters
  137. If no formatter is found the raw_value is returned as bytes.
  138. Attributes defined as SINGLE_VALUE in schema are returned as a single object, otherwise are returned as a list of object
  139. Formatter functions can return any kind of object
  140. return a tuple (formatter, validator)
  141. """
  142. formatter = None
  143. if custom_formatter and isinstance(custom_formatter, dict): # if custom formatters are defined they have precedence over the standard formatters
  144. if name in custom_formatter: # search for attribute name, as returned by the search operation
  145. formatter = custom_formatter[name]
  146. if not formatter and attr_type and attr_type.oid in custom_formatter: # search for attribute oid as returned by schema
  147. formatter = custom_formatter[attr_type.oid]
  148. if not formatter and attr_type and attr_type.oid_info:
  149. if isinstance(attr_type.oid_info[2], SEQUENCE_TYPES): # search for multiple names defined in oid_info
  150. for attr_name in attr_type.oid_info[2]:
  151. if attr_name in custom_formatter:
  152. formatter = custom_formatter[attr_name]
  153. break
  154. elif attr_type.oid_info[2] in custom_formatter: # search for name defined in oid_info
  155. formatter = custom_formatter[attr_type.oid_info[2]]
  156. if not formatter and attr_type and attr_type.syntax in custom_formatter: # search for syntax defined in schema
  157. formatter = custom_formatter[attr_type.syntax]
  158. if not formatter and name in standard_formatter: # search for attribute name, as returned by the search operation
  159. formatter = standard_formatter[name]
  160. if not formatter and attr_type and attr_type.oid in standard_formatter: # search for attribute oid as returned by schema
  161. formatter = standard_formatter[attr_type.oid]
  162. if not formatter and attr_type and attr_type.oid_info:
  163. if isinstance(attr_type.oid_info[2], SEQUENCE_TYPES): # search for multiple names defined in oid_info
  164. for attr_name in attr_type.oid_info[2]:
  165. if attr_name in standard_formatter:
  166. formatter = standard_formatter[attr_name]
  167. break
  168. elif attr_type.oid_info[2] in standard_formatter: # search for name defined in oid_info
  169. formatter = standard_formatter[attr_type.oid_info[2]]
  170. if not formatter and attr_type and attr_type.syntax in standard_formatter: # search for syntax defined in schema
  171. formatter = standard_formatter[attr_type.syntax]
  172. if formatter is None:
  173. return None, None
  174. return formatter
  175. def format_attribute_values(schema, name, values, custom_formatter):
  176. if not values: # RFCs states that attributes must always have values, but a flaky server returns empty values too
  177. return []
  178. if not isinstance(values, SEQUENCE_TYPES):
  179. values = [values]
  180. if schema and schema.attribute_types and name in schema.attribute_types:
  181. attr_type = schema.attribute_types[name]
  182. else:
  183. attr_type = None
  184. attribute_helpers = find_attribute_helpers(attr_type, name, custom_formatter)
  185. if not isinstance(attribute_helpers, tuple): # custom formatter
  186. formatter = attribute_helpers
  187. else:
  188. formatter = format_unicode if not attribute_helpers[0] else attribute_helpers[0]
  189. formatted_values = [formatter(raw_value) for raw_value in values] # executes formatter
  190. if formatted_values:
  191. return formatted_values[0] if (attr_type and attr_type.single_value) else formatted_values
  192. else: # RFCs states that attributes must always have values, but AD return empty values in DirSync
  193. return []
  194. def find_attribute_validator(schema, name, custom_validator):
  195. if schema and schema.attribute_types and name in schema.attribute_types:
  196. attr_type = schema.attribute_types[name]
  197. else:
  198. attr_type = None
  199. attribute_helpers = find_attribute_helpers(attr_type, name, custom_validator)
  200. if not isinstance(attribute_helpers, tuple): # custom validator
  201. validator = attribute_helpers
  202. else:
  203. if not attribute_helpers[1]:
  204. if attr_type and attr_type.single_value:
  205. validator = validate_generic_single_value # validate only single value
  206. else:
  207. validator = always_valid # unknown syntax, accepts single and multi value
  208. else:
  209. validator = attribute_helpers[1]
  210. return validator