def _findOverRide(self, dn, overrides): while True: for dn_variant in get_strings(dn): if dn_variant in overrides: return overrides[dn] if dn == '': break dn = dn.up() return None
def add(self, key): """ Adding key to the attributes with checking if it exists as byte or unicode string """ for k in get_strings(key): if k in self: return set.add(self, key)
def remove(self, key): """ Removing key from the attributes with checking if it exists as byte or unicode string """ for k in get_strings(key): if k in self: set.remove(self, k) return raise KeyError(key)
def has_key(self, key): for k in get_strings(key): if k in self._attributes: return True return False
def get(self, key, default=None): for k in get_strings(key): if k in self._attributes: return self._attributes[k] return default
def __getitem__(self, key): for k in get_strings(key): if k in self._attributes: return self._attributes[k] raise KeyError(key)
class BaseLDAPEntry(WireStrAlias): dn = None _object_class_keys = set(get_strings('objectClass')) _object_class_lower_keys = set(get_strings('objectclass')) _user_password_keys = set(get_strings('userPassword')) def __init__(self, dn, attributes={}): """ Initialize the object. @param dn: Distinguished Name of the object, as a string. @param attributes: Attributes of the object. A dictionary of attribute types to list of attribute values. """ self._attributes = InsensitiveDict() self.dn = distinguishedname.DistinguishedName(dn) for k, vs in attributes.items(): if k not in self._attributes: self._attributes[k] = [] self._attributes[k].extend(vs) for k, vs in self._attributes.items(): self._attributes[k] = self.buildAttributeSet(k, vs) def buildAttributeSet(self, key, values): return attributeset.LDAPAttributeSet(key, values) def __getitem__(self, key): for k in get_strings(key): if k in self._attributes: return self._attributes[k] raise KeyError(key) def get(self, key, default=None): for k in get_strings(key): if k in self._attributes: return self._attributes[k] return default def has_key(self, key): for k in get_strings(key): if k in self._attributes: return True return False def __contains__(self, key): return self.has_key(key) def __iter__(self): for key in self._attributes.iterkeys(): yield key def keys(self): a = [] for key in self._object_class_keys: if key in self._attributes: a.append(key) l = list(self._attributes.keys()) l.sort(key=to_bytes) for key in l: if key.lower() not in self._object_class_lower_keys: a.append(key) return a def items(self): a = [] for key in self._object_class_keys: objectClasses = list(self._attributes.get(key, [])) objectClasses.sort(key=to_bytes) if objectClasses: a.append((key, objectClasses)) l = list(self._attributes.items()) l.sort(key=lambda x: to_bytes(x[0])) for key, values in l: if key.lower() not in self._object_class_lower_keys: vs = list(values) vs.sort() a.append((key, vs)) return a def toWire(self): a = [] for key in self._object_class_keys: objectClasses = list(self._attributes.get(key, [])) objectClasses.sort(key=to_bytes) a.append((key, objectClasses)) items_gen = ((key, self[key]) for key in self) items = sorted(items_gen, key=lambda x: to_bytes(x[0])) for key, values in items: if key.lower() not in self._object_class_lower_keys: vs = list(values) vs.sort() a.append((key, vs)) return ldif.asLDIF(self.dn.getText(), a) def getLDIF(self): return self.toWire().decode('utf-8') def __eq__(self, other): if not isinstance(other, BaseLDAPEntry): return NotImplemented if self.dn != other.dn: return 0 my = sorted((key for key in self), key=to_bytes) its = sorted((key for key in other), key=to_bytes) if my != its: return 0 for key in my: myAttr = self[key] itsAttr = other[key] if myAttr != itsAttr: return 0 return 1 def __ne__(self, other): return not self == other def __len__(self): return len(self.keys()) def __bool__(self): return True def __nonzero__(self): return self.__bool__() def __repr__(self): keys = sorted((key for key in self), key=to_bytes) a = [] for key in keys: a.append('%s: %s' % (repr(key), repr(list(self[key])))) attributes = ', '.join(a) dn = to_bytes(self.dn.getText()) if six.PY2 else self.dn.getText() return '%s(%s, {%s})' % (self.__class__.__name__, repr(dn), attributes) def diff(self, other): """ Compute differences between this and another LDAP entry. @param other: An LDAPEntry to compare to. @return: None if equal, otherwise a ModifyOp that would make this entry look like other. """ assert self.dn == other.dn if self == other: return None r = [] myKeys = set(key for key in self) otherKeys = set(key for key in other) addedKeys = list(otherKeys - myKeys) addedKeys.sort(key=to_bytes) # for reproducability only for added in addedKeys: r.append(delta.Add(added, other[added])) deletedKeys = list(myKeys - otherKeys) deletedKeys.sort(key=to_bytes) # for reproducability only for deleted in deletedKeys: r.append(delta.Delete(deleted, self[deleted])) sharedKeys = list(myKeys & otherKeys) sharedKeys.sort(key=to_bytes) # for reproducability only for shared in sharedKeys: addedValues = list(other[shared] - self[shared]) if addedValues: addedValues.sort(key=to_bytes) # for reproducability only r.append(delta.Add(shared, addedValues)) deletedValues = list(self[shared] - other[shared]) if deletedValues: deletedValues.sort(key=to_bytes) # for reproducability only r.append(delta.Delete(shared, deletedValues)) return delta.ModifyOp(dn=self.dn, modifications=r) def bind(self, password): return defer.maybeDeferred(self._bind, password) def _bind(self, password): password = to_bytes(password) for key in self._user_password_keys: for digest in self.get(key, ()): digest = to_bytes(digest) if digest.startswith(b'{SSHA}'): raw = base64.decodestring(digest[len(b'{SSHA}'):]) salt = raw[20:] got = sshaDigest(password, salt) if got == digest: return self else: # Plaintext if digest == password: return self raise ldaperrors.LDAPInvalidCredentials() def hasMember(self, dn): for memberDN in self.get('member', []): if memberDN == dn: return True return False def __hash__(self): # FIXME:https://github.com/twisted/ldaptor/issues/101 # The hash should take into consideration any attribute used to # decide the equality. return hash(self.dn)
def match(self, filter): if isinstance(filter, pureldap.LDAPFilter_present): for value in get_strings(filter.value): if value in self: return True return False elif isinstance(filter, pureldap.LDAPFilter_equalityMatch): # TODO case insensitivity depends on different attribute syntaxes for value in get_strings(filter.assertionValue.value.lower()): if value in [val.lower() for val in self.get(filter.attributeDesc.value, [])]: return True return False elif isinstance(filter, pureldap.LDAPFilter_substrings): if filter.type not in self: return False possibleMatches = self[filter.type] substrings = filter.substrings[:] if (substrings and isinstance(filter.substrings[0], pureldap.LDAPFilter_substrings_initial)): possibleMatches = [ x[len(filter.substrings[0].value):] for x in possibleMatches if x.lower().startswith(filter.substrings[0].value.lower()) ] del substrings[0] if (substrings and isinstance(filter.substrings[-1], pureldap.LDAPFilter_substrings_final)): possibleMatches = [ x[:-len(filter.substrings[0].value)] for x in possibleMatches if x.lower().endswith(filter.substrings[-1].value.lower()) ] del substrings[-1] while possibleMatches and substrings: assert isinstance(substrings[0], pureldap.LDAPFilter_substrings_any) r = [] for possible in possibleMatches: i = possible.lower().find(substrings[0].value.lower()) if i >= 0: r.append(possible[i:]) possibleMatches = r del substrings[0] if possibleMatches and not substrings: return True return False elif isinstance(filter, pureldap.LDAPFilter_greaterOrEqual): if filter.attributeDesc.value not in self: return False for value in self[filter.attributeDesc.value]: if value >= filter.assertionValue.value: return True return False elif isinstance(filter, pureldap.LDAPFilter_lessOrEqual): if filter.attributeDesc.value not in self: return False for value in self[filter.attributeDesc.value]: if value <= filter.assertionValue.value: return True return False elif isinstance(filter, pureldap.LDAPFilter_and): for filt in filter: if not self.match(filt): return False return True elif isinstance(filter, pureldap.LDAPFilter_or): for filt in filter: if self.match(filt): return True return False elif isinstance(filter, pureldap.LDAPFilter_not): return not self.match(filter.value) elif isinstance(filter, pureldap.LDAPFilter_extensibleMatch): if filter.matchingRule is None: attrib = filter.type.value match_value = filter.matchValue.value match_value_lower = safelower(match_value) if (match_value_lower in [val.lower() for val in self.get(attrib, [])]): return True for rdn in self.dn.listOfRDNs: for av in rdn.attributeTypesAndValues: if attrib is None or attrib == av.attributeType: if match_value_lower == safelower(av.value): return True return False else: raise ldapsyntax.MatchNotImplemented(filter) else: raise ldapsyntax.MatchNotImplemented(filter)