Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 

195 righe
6.4 KiB

  1. # -*- coding: utf-8 -*-
  2. import json
  3. from flask import current_app
  4. from six import add_metaclass
  5. from ldap3.utils.dn import safe_dn
  6. from ldap3.utils.conv import check_json_dict, format_json
  7. from ldap3.core.exceptions import LDAPAttributeError
  8. from .query import BaseQuery
  9. from .attribute import LDAPAttribute, LdapField
  10. __all__ = ('LDAPEntry',)
  11. class LDAPEntryMeta(type):
  12. def __init__(cls, name, bases, attr):
  13. cls._fields = {}
  14. for key, value in attr.items():
  15. if isinstance(value, LdapField):
  16. cls._fields[key] = value
  17. for base in bases:
  18. if isinstance(base, LDAPEntryMeta):
  19. cls._fields.update(base._fields)
  20. # Deduplicate object classes
  21. cls.object_classes = list(
  22. set(cls.object_classes + base.object_classes))
  23. @property
  24. def query(cls):
  25. return BaseQuery(cls)
  26. @add_metaclass(LDAPEntryMeta)
  27. class LDAPEntry(object):
  28. base_dn = None
  29. entry_rdn = ['cn']
  30. object_classes = ['top']
  31. sub_tree = True
  32. operational_attributes = False
  33. _changetype = 'add'
  34. def __init__(self, dn=None, changetype='add', **kwargs):
  35. self._attributes = {}
  36. self._dn = dn
  37. self._changetype = changetype
  38. if kwargs:
  39. for key, value in kwargs.items():
  40. self._store_attr(key, value, init=True)
  41. for key, ldap_attr in self._fields.items():
  42. if not self._isstored(key):
  43. self._store_attr(key, [])
  44. @property
  45. def dn(self):
  46. if self._dn is None:
  47. self.generate_dn_from_entry()
  48. return self._dn
  49. def generate_dn_from_entry(self):
  50. rdn_list = list()
  51. for key, attr in self._attributes.items():
  52. if attr.name in self.entry_rdn:
  53. if len(self._attributes[key]) == 1:
  54. rdn = '{attr}={value}'.format(
  55. attr=attr.name,
  56. value=self._attributes[key].value
  57. )
  58. rdn_list.append(rdn)
  59. dn = '{rdn},{base_dn}'.format(rdn='+'.join(rdn_list),
  60. base_dn=self.base_dn)
  61. self._dn = safe_dn(dn)
  62. @classmethod
  63. def _get_field(cls, attr):
  64. return cls._fields.get(attr)
  65. @classmethod
  66. def _get_field_name(cls, attr):
  67. if cls._get_field(attr):
  68. return cls._get_field(attr).name
  69. def _store_attr(self, attr, value=[], init=False):
  70. if not self._get_field(attr):
  71. raise LDAPAttributeError('attribute not found')
  72. if value is None:
  73. value = []
  74. if not self._attributes.get(attr):
  75. self._attributes[attr] = LDAPAttribute(self._get_field_name(attr))
  76. self._attributes[attr].value = value
  77. if init:
  78. self._attributes[attr].__dict__['changetype'] = None
  79. def _isstored(self, attr):
  80. return self._attributes.get(attr)
  81. def _get_attr(self, attr):
  82. if self._isstored(attr):
  83. return self._attributes[attr].value
  84. return None
  85. def __getattribute__(self, item):
  86. if item != '_fields' and item in self._fields:
  87. return self._get_attr(item)
  88. return super(LDAPModel, self).__getattribute__(item)
  89. def __setattr__(self, key, value):
  90. if key != '_fields' and key in self._fields:
  91. self._store_attr(key, value)
  92. else:
  93. return super(LDAPModel, self).__setattr__(key, value)
  94. def get_attributes_dict(self):
  95. return dict((attribute_key, attribute_value.values) for (attribute_key,
  96. attribute_value) in self._attributes.items())
  97. def get_entry_add_dict(self, attr_dict):
  98. add_dict = dict()
  99. for attribute_key, attribute_value in attr_dict.items():
  100. if self._attributes[attribute_key].value != []:
  101. add_dict.update({self._get_field_name(attribute_key): attribute_value})
  102. return add_dict
  103. def get_entry_modify_dict(self, attr_dict):
  104. modify_dict = dict()
  105. for attribute_key in attr_dict.keys():
  106. if self._attributes[attribute_key].changetype is not None:
  107. changes = self._attributes[attribute_key].get_changes_tuple()
  108. modify_dict.update({self._get_field_name(attribute_key): changes})
  109. return modify_dict
  110. @property
  111. def connection(self):
  112. return current_app.extensions.get('ldap_conn')
  113. def delete(self):
  114. '''Delete this entry from LDAP server'''
  115. return self.connection.connection.delete(self.dn)
  116. def save(self):
  117. '''Save the current instance'''
  118. attrs = self.get_attributes_dict()
  119. if self._changetype == 'add':
  120. changes = self.get_entry_add_dict(attrs)
  121. return self.connection.connection.add(self.dn,
  122. self.object_classes,
  123. changes)
  124. elif self._changetype == 'modify':
  125. changes = self.get_entry_modify_dict(attrs)
  126. return self.connection.connection.modify(self.dn, changes)
  127. return False
  128. def authenticate(self, password):
  129. '''Authenticate a user with an LDAPModel class
  130. Args:
  131. password (str): The user password.
  132. '''
  133. return self.connection.authenticate(self.dn, password)
  134. def to_json(self, indent=2, sort=True, str_values=False):
  135. json_entry = dict()
  136. json_entry['dn'] = self.dn
  137. # Get "single values" from attributes as str instead list if
  138. # `str_values=True` else get all attributes as list. This only
  139. # works if `FORCE_ATTRIBUTE_VALUE_AS_LIST` is False (default).
  140. if str_values is True:
  141. json_entry['attributes'] = {}
  142. for attr in self._attributes.keys():
  143. json_entry['attributes'][attr] = self._attributes[attr].value
  144. else:
  145. json_entry['attributes'] = self.get_attributes_dict()
  146. if str == bytes:
  147. check_json_dict(json_entry)
  148. json_output = json.dumps(json_entry,
  149. ensure_ascii=True,
  150. sort_keys=sort,
  151. indent=indent,
  152. check_circular=True,
  153. default=format_json,
  154. separators=(',', ': '))
  155. return json_output
  156. LDAPModel = LDAPEntry