Source code for ldaptor.protocols.ldap.distinguishedname

# See rfc2253

# Note that RFC 2253 sections 2.4 and 3 disagree whether "=" needs to
# be quoted. Let's trust the syntax, slapd refuses to accept unescaped
# "=" in RDN values.
escapedChars = r',+"\<>;='
escapedChars_leading = r' #'
escapedChars_trailing = r' #'

[docs]def escape(s): r='' r_trailer='' if s and s[0] in escapedChars_leading: r='\\'+s[0] s=s[1:] if s and s[-1] in escapedChars_trailing: r_trailer='\\'+s[-1] s=s[:-1] for c in s: if c in escapedChars: r=r+'\\'+c elif ord(c)<=31: r=r+'\\%02X' % ord(c) else: r=r+c return r+r_trailer
[docs]def unescape(s): r='' while s: if s[0]=='\\': if s[1] in '0123456789abcdef': r=r+chr(int(s[1:3], 16)) s=s[3:] else: r=r+s[1] s=s[2:] else: r=r+s[0] s=s[1:] return r
def _splitOnNotEscaped(s, separator): if not s: return [] r=[''] while s: if s[0]=='\\': r[-1]=r[-1]+s[:2] s=s[2:] else: if s[0] in separator: r.append('') s=s[1:] while s[0]==' ': s=s[1:] else: r[-1]=r[-1]+s[0] s=s[1:] return r
[docs]class InvalidRelativeDistinguishedName(Exception): """Invalid relative distinguished name.""" def __init__(self, rdn): Exception.__init__(self) self.rdn = rdn def __str__(self): return "Invalid relative distinguished name %s." \ % repr(self.rdn)
[docs]class LDAPAttributeTypeAndValue: # TODO I should be used everywhere attributeType = None value = None def __init__(self, stringValue=None, attributeType=None, value=None): if stringValue is None: assert attributeType is not None assert value is not None self.attributeType = attributeType self.value = value else: assert attributeType is None assert value is None if '=' not in stringValue: raise InvalidRelativeDistinguishedName, stringValue self.attributeType, self.value = stringValue.split('=', 1) def __str__(self): return '='.join((escape(self.attributeType), escape(self.value))) def __repr__(self): return (self.__class__.__name__ + '(attributeType=' + repr(self.attributeType) + ', value=' + repr(self.value) + ')') def __hash__(self): return hash((self.attributeType, self.value)) def __eq__(self, other): if not isinstance(other, LDAPAttributeTypeAndValue): return NotImplemented return (self.attributeType == other.attributeType and self.value == other.value) def __ne__(self, other): return not (self == other) def __lt__(self, other): if not isinstance(other, self.__class__): return False if self.attributeType != other.attributeType: return self.attributeType < other.attributeType else: return self.value < other.value def __gt__(self, other): return (self != other and self > other) def __le__(self, other): return not self > other def __ge__(self, other): return not self < other
[docs]class RelativeDistinguishedName: """LDAP Relative Distinguished Name.""" attributeTypesAndValues = None def __init__(self, magic=None, stringValue=None, attributeTypesAndValues=None): if magic is not None: assert stringValue is None assert attributeTypesAndValues is None if isinstance(magic, RelativeDistinguishedName): attributeTypesAndValues = magic.split() elif isinstance(magic, basestring): stringValue = magic else: attributeTypesAndValues = magic if stringValue is None: assert attributeTypesAndValues is not None import types assert not isinstance(attributeTypesAndValues, types.StringType) self.attributeTypesAndValues = tuple(attributeTypesAndValues) else: assert attributeTypesAndValues is None self.attributeTypesAndValues = tuple([LDAPAttributeTypeAndValue(stringValue=unescape(x)) for x in _splitOnNotEscaped(stringValue, '+')])
[docs] def split(self): return self.attributeTypesAndValues
def __str__(self): return '+'.join([str(x) for x in self.attributeTypesAndValues]) def __repr__(self): return (self.__class__.__name__ + '(attributeTypesAndValues=' + repr(self.attributeTypesAndValues) + ')') def __hash__(self): return hash(self.attributeTypesAndValues) def __eq__(self, other): if not isinstance(other, RelativeDistinguishedName): return NotImplemented return self.split() == other.split() def __ne__(self, other): return not (self == other) def __lt__(self, other): if not isinstance(other, self.__class__): return False return self.split() < other.split() def __gt__(self, other): return (self != other and self >= other) def __le__(self, other): return not self > other def __ge__(self, other): return not self < other
[docs] def count(self): return len(self.attributeTypesAndValues)
[docs]class DistinguishedName: """LDAP Distinguished Name.""" listOfRDNs = None def __init__(self, magic=None, stringValue=None, listOfRDNs=None): assert (magic is not None or stringValue is not None or listOfRDNs is not None) if magic is not None: assert stringValue is None assert listOfRDNs is None if isinstance(magic, DistinguishedName): listOfRDNs = magic.split() elif isinstance(magic, basestring): stringValue = magic else: listOfRDNs = magic if stringValue is None: assert listOfRDNs is not None for x in listOfRDNs: assert isinstance(x, RelativeDistinguishedName) self.listOfRDNs = tuple(listOfRDNs) else: assert listOfRDNs is None self.listOfRDNs = tuple([RelativeDistinguishedName(stringValue=x) for x in _splitOnNotEscaped(stringValue, ',')])
[docs] def split(self): return self.listOfRDNs
[docs] def up(self): return DistinguishedName(listOfRDNs=self.listOfRDNs[1:])
def __str__(self): return ','.join([str(x) for x in self.listOfRDNs]) def __repr__(self): return (self.__class__.__name__ + '(listOfRDNs=' + repr(self.listOfRDNs) + ')') def __hash__(self): return hash(str(self)) def __eq__(self, other): if isinstance(other, basestring): return str(self) == other if not isinstance(other, DistinguishedName): return NotImplemented return self.split() == other.split() def __ne__(self, other): return not (self == other) def __cmp__(self, other): if isinstance(other, basestring): return cmp(str(self), other) if not isinstance(other, DistinguishedName): return NotImplemented return cmp(self.split(), other.split())
[docs] def getDomainName(self): domainParts = [] l=list(self.listOfRDNs) l.reverse() for rdn in l: if rdn.count() != 1: break attributeTypeAndValue = rdn.split()[0] if attributeTypeAndValue.attributeType.upper() != 'DC': break domainParts.insert(0, attributeTypeAndValue.value) if domainParts: return '.'.join(domainParts) else: return None
[docs] def contains(self, other): """Does the tree rooted at DN contain or equal the other DN.""" if self == other: return 1 if not isinstance(other, DistinguishedName): other=DistinguishedName(other) its=list(other.split()) mine=list(self.split()) while mine and its: m=mine.pop() i=its.pop() if m!=i: return 0 if mine: return 0 return 1