ldaptor-0.0.43/ 0000755 0001750 0001750 00000000000 11306701242 011341 5 ustar jan jan ldaptor-0.0.43/ldaptor/ 0000755 0001750 0001750 00000000000 10403234314 013004 5 ustar jan jan ldaptor-0.0.43/ldaptor/samba/ 0000755 0001750 0001750 00000000000 10403234305 014067 5 ustar jan jan ldaptor-0.0.43/ldaptor/samba/__init__.py 0000644 0001750 0001750 00000000000 07542426337 016210 0 ustar jan jan ldaptor-0.0.43/ldaptor/samba/smbpassword.py 0000644 0001750 0001750 00000004642 10104536552 017022 0 ustar jan jan import string, warnings
from ldaptor import md4, config
lower='abcdefghijklmnopqrstuvwxyz'
upper=lower.upper()
toupper=string.maketrans(lower, upper)
def nthash(password=''):
"""Generates nt md4 password hash for a given password."""
password=password[:128]
password=''.join([c+'\000' for c in password])
return md4.new(password).hexdigest().translate(toupper);
def lmhash_locked(password=''):
"""
Generates a lanman password hash that matches no password.
Note that the author thinks LanMan hashes should be banished from
the face of the earth.
"""
return 32*'X'
def _no_lmhash(password=''):
if config.useLMhash():
warnings.warn("Cannot import Crypto.Cipher.DES, lmhash passwords disabled.")
return lmhash_locked()
def _have_lmhash(password=''):
"""
Generates lanman password hash for a given password.
Note that the author thinks LanMan hashes should be banished from
the face of the earth.
"""
if not config.useLMhash():
return lmhash_locked()
password = (password+14*'\0')[:14]
password = password.upper()
return _deshash(password[:7]) + _deshash(password[7:])
try:
from Crypto.Cipher import DES
except ImportError:
lmhash = _no_lmhash
else:
lmhash = _have_lmhash
LM_MAGIC = "KGS!@#$%"
def _deshash(p):
# Insert parity bits. I'm not going to bother myself with smart
# implementations.
bits = []
for byte in [ord(c) for c in p]:
bits.extend([bool(byte & 128),
bool(byte & 64),
bool(byte & 32),
bool(byte & 16),
bool(byte & 8),
bool(byte & 4),
bool(byte & 2),
bool(byte & 1)])
def _pack(bits):
x = ((bits[0] << 7)
+ (bits[1] << 6)
+ (bits[2] << 5)
+ (bits[3] << 4)
+ (bits[4] << 3)
+ (bits[5] << 2)
+ (bits[6] << 1))
return x
bytes = (_pack(bits[:7]),
_pack(bits[7:14]),
_pack(bits[14:21]),
_pack(bits[21:28]),
_pack(bits[28:35]),
_pack(bits[35:42]),
_pack(bits[42:49]),
_pack(bits[49:]))
bytes = ''.join([chr(x) for x in bytes])
cipher = DES.new(bytes, DES.MODE_ECB)
raw = cipher.encrypt(LM_MAGIC)
l = ['%02X' % ord(x) for x in raw]
return ''.join(l)
ldaptor-0.0.43/ldaptor/weave.py 0000644 0001750 0001750 00000011126 10345073240 014472 0 ustar jan jan from zope.interface import implements
from nevow import tags, compy, inevow, flat
from ldaptor.protocols.ldap import ldapsyntax, distinguishedname
from ldaptor import interfaces
def keyvalue(context, data):
"""
Render items in a mapping using patterns found in the children
of the element.
Keyvalue recognizes the following patterns:
- header: Rendered at the start, before the first item. If
multiple header patterns are provided they are rendered
together in the order they were defined.
- footer: Just like the header only renderer at the end, after
the last item.
- item: Rendered once for each item in the sequence. Can contain
subpatterns key and value.
If multiple item patterns are provided then the pattern is
cycled in the order defined.
- divider: Rendered once between each item in the
sequence. Multiple divider patterns are cycled.
- empty: Rendered instead of item and divider patterns when the
sequence contains no items.
Example::
name
email
name goes here
email goes here
name goes here
email goes here
they've all gone!
"""
headers = context.tag.allPatterns('header')
item = context.tag.patternGenerator('item')
divider = context.tag.patternGenerator('divider', default=tags.invisible)
content = []
for key, value in data.items():
content.append(item(data=(key, value)))
content.append(divider(data=(key, value)))
if not content:
content = context.tag.allPatterns('empty')
else:
## No divider after the last thing.
del content[-1]
footers = context.tag.allPatterns('footer')
return context.tag.clear()[ headers, content, footers ]
def keyvalue_item(context, data):
key, value = data
k = context.tag.patternGenerator('key')
v = context.tag.patternGenerator('value')
return context.tag.clear()[ k(data=key), v(data=value) ]
class _DictLike(object):
implements(inevow.IContainer)
def __init__(self, original):
self.original = original
def child(self, context, name):
return self.original.get(name, None)
def items(self):
return self.original.items()
class LDAPEntryContainer(object):
implements(inevow.IContainer)
def __init__(self, original):
self.original = original
def child(self, context, name):
if name == 'dn':
return self.original.dn
elif name == 'attributes':
return _DictLike(self.original)
else:
return None
compy.registerAdapter(LDAPEntryContainer, ldapsyntax.LDAPEntryWithClient, inevow.IContainer)
def dnSerializer(original, context):
return flat.serialize(str(original), context)
flat.registerFlattener(dnSerializer,
distinguishedname.DistinguishedName)
def entrySerializer(original, context):
ul = tags.ul()
for a,l in original.items():
if len(l)==0:
ul[tags.li[a, ': none']]
elif len(l)==1:
for attr in l:
first = attr
break
ul[tags.li[a, ': ', first]]
else:
li=tags.li[a, ':']
ul[li]
liul=tags.ul()
li[liul]
for i in l:
liul[tags.li[i]]
return flat.serialize(ul, context)
flat.registerFlattener(entrySerializer,
interfaces.ILDAPEntry)
class IZebraStyle(compy.Interface):
"""Marker interface for zebra."""
pass
def zebra(styles=['zebra-odd', 'zebra-even']):
"""
Provide alternating background colors for e.g. zebra tables.
@param styles: Two or more CSS class names to iterate.
Use like this::
render_zebra = weave.zebra()
foo
bar
baz
"""
styles = list(styles)
def f(self, ctx, data):
request = inevow.IRequest(ctx)
state = IZebraStyle(request, styles)
r = ctx.tag(class_="%s" % state[0])
request.setComponent(IZebraStyle, state[1:]+state[:1])
return r
return f
ldaptor-0.0.43/ldaptor/dns.py 0000644 0001750 0001750 00000002636 10344535643 014166 0 ustar jan jan """DNS-related utilities."""
from socket import inet_aton, inet_ntoa
def aton_octets(ip):
s=inet_aton(ip)
octets=map(None, s)
n=0L
for o in octets:
n=n<<8
n+=ord(o)
return n
def aton_numbits(num):
n=0L
while num>0:
n>>=1
n |= 2**31
num-=1
return n
def aton(ip):
try:
i=int(ip)
except ValueError:
return aton_octets(ip)
else:
return aton_numbits(i)
def ntoa(n):
s=(
chr((n>>24)&0xFF)
+ chr((n>>16)&0xFF)
+ chr((n>>8)&0xFF)
+ chr(n&0xFF)
)
ip=inet_ntoa(s)
return ip
def netmaskToNumbits(netmask):
bits = aton(netmask)
i = 2**31
n = 0
while bits and i > 0:
if (bits & i) == 0:
if bits:
raise RuntimeError, "Invalid netmask: %s" % netmask
n += 1
bits -= i
i = i >> 1
return n
def ptrSoaName(ip, netmask):
"""
Convert an IP address and netmask to a CIDR delegation
-style zone name.
"""
net = aton(ip) & aton(netmask)
nmBits = netmaskToNumbits(netmask)
bytes, bits = divmod(nmBits, 8)
octets = ntoa(net).split('.')
octets.reverse()
if not bits:
octets = octets[-bytes:]
else:
partial = octets[-bytes-1]
octets = octets[-bytes:]
octets.insert(0, '%s/%d' % (partial, nmBits))
return '.'.join(octets)+'.in-addr.arpa.'
ldaptor-0.0.43/ldaptor/ldapfilter.py 0000644 0001750 0001750 00000017564 10344535643 015536 0 ustar jan jan #!/usr/bin/python
from ldaptor.protocols import pureldap
"""
RFC2254:
filter = "(" filtercomp ")"
filtercomp = and / or / not / item
and = "&" filterlist
or = "|" filterlist
not = "!" filter
filterlist = 1*filter
item = simple / present / substring / extensible
simple = attr filtertype value
filtertype = equal / approx / greater / less
equal = "="
approx = "~="
greater = ">="
less = "<="
extensible = attr [":dn"] [":" matchingrule] ":=" value
/ [":dn"] ":" matchingrule ":=" value
present = attr "=*"
substring = attr "=" [initial] any [final]
initial = value
any = "*" *(value "*")
final = value
attr = AttributeDescription from Section 4.1.5 of [1]
matchingrule = MatchingRuleId from Section 4.1.9 of [1]
value = AttributeValue from Section 4.1.6 of [1]
"""
class InvalidLDAPFilter(Exception):
def __init__(self, msg, loc, text):
Exception.__init__(self)
self.msg=msg
self.loc=loc
self.text=text
def __str__(self):
return "Invalid LDAP filter: %s at point %d in %r" \
% (self.msg, self.loc, self.text)
def parseExtensible(attr, s):
raise NotImplementedError
from pyparsing import Word, Literal, Optional, ZeroOrMore, Suppress, \
Group, Forward, OneOrMore, ParseException, \
CharsNotIn, Combine, StringStart, \
StringEnd, delimitedList
import copy, string
filter_ = Forward()
attr = Word(string.ascii_letters,
string.ascii_letters + string.digits + ';-',)
attr.leaveWhitespace()
attr.setName('attr')
hexdigits = Word(string.hexdigits, exact=2)
hexdigits.setName('hexdigits')
escaped = Suppress(Literal('\\'))+hexdigits
escaped.setName('escaped')
def _p_escaped(s,l,t):
text=t[0]
return chr(int(text, 16))
escaped.setParseAction(_p_escaped)
value = Combine(OneOrMore(CharsNotIn('*()\\\0') | escaped))
value.setName('value')
equal = Literal("=")
equal.setParseAction(lambda s,l,t: pureldap.LDAPFilter_equalityMatch)
approx = Literal("~=")
approx.setParseAction(lambda s,l,t: pureldap.LDAPFilter_approxMatch)
greater = Literal(">=")
greater.setParseAction(lambda s,l,t: pureldap.LDAPFilter_greaterOrEqual)
less = Literal("<=")
less.setParseAction(lambda s,l,t: pureldap.LDAPFilter_lessOrEqual)
filtertype = equal | approx | greater | less
filtertype.setName('filtertype')
simple = attr + filtertype + value
simple.leaveWhitespace()
simple.setName('simple')
def _p_simple(s,l,t):
attr, filtertype, value = t
return filtertype(attributeDesc=pureldap.LDAPAttributeDescription(attr),
assertionValue=pureldap.LDAPAssertionValue(value))
simple.setParseAction(_p_simple)
present = attr + "=*"
present.setParseAction(lambda s,l,t: pureldap.LDAPFilter_present(t[0]))
initial = copy.copy(value)
initial.setParseAction(lambda s,l,t: pureldap.LDAPFilter_substrings_initial(t[0]))
initial.setName('initial')
any_value = value + Suppress(Literal("*"))
any_value.setParseAction(lambda s,l,t: pureldap.LDAPFilter_substrings_any(t[0]))
any = Suppress(Literal("*")) + ZeroOrMore(any_value)
any.setName('any')
final = copy.copy(value)
final.setName('final')
final.setParseAction(lambda s,l,t: pureldap.LDAPFilter_substrings_final(t[0]))
substring = attr + Suppress(Literal("=")) + Group(Optional(initial) + any + Optional(final))
substring.setName('substring')
def _p_substring(s,l,t):
attrtype, substrings = t
return pureldap.LDAPFilter_substrings(
type=attrtype,
substrings=substrings)
substring.setParseAction(_p_substring)
keystring = Word(string.ascii_letters,
string.ascii_letters + string.digits + ';-')
keystring.setName('keystring')
numericoid = delimitedList(Word(string.digits), delim='.', combine=True)
numericoid.setName('numericoid')
oid = numericoid | keystring
oid.setName('oid')
matchingrule = copy.copy(oid)
matchingrule.setName('matchingrule')
extensible_dn = Optional(":dn")
def _p_extensible_dn(s,l,t):
return bool(t)
extensible_dn.setParseAction(_p_extensible_dn)
matchingrule_or_none = Optional(Suppress(":") + matchingrule)
def _p_matchingrule_or_none(s,l,t):
if not t:
return [None]
else:
return t[0]
matchingrule_or_none.setParseAction(_p_matchingrule_or_none)
extensible_attr = attr + extensible_dn + matchingrule_or_none + Suppress(":=") + value
extensible_attr.setName('extensible_attr')
def _p_extensible_attr(s,l,t):
return list(t)
extensible_attr.setParseAction(_p_extensible_attr)
extensible_noattr = extensible_dn + Suppress(":") + matchingrule + Suppress(":=") + value
extensible_noattr.setName('extensible_noattr')
def _p_extensible_noattr(s,l,t):
return [None]+list(t)
extensible_noattr.setParseAction(_p_extensible_noattr)
extensible = extensible_attr | extensible_noattr
extensible.setName('extensible')
def _p_extensible(s,l,t):
attr, dn, matchingRule, value = t
return pureldap.LDAPFilter_extensibleMatch(
matchingRule=matchingRule,
type=attr,
matchValue=value,
dnAttributes=dn)
extensible.setParseAction(_p_extensible)
item = simple ^ present ^ substring ^ extensible
item.setName('item')
item.leaveWhitespace()
not_ = Suppress(Literal('!')) + filter_
not_.setParseAction(lambda s,l,t: pureldap.LDAPFilter_not(t[0]))
not_.setName('not')
filterlist = OneOrMore(filter_)
or_ = Suppress(Literal('|')) + filterlist
or_.setParseAction(lambda s,l,t: pureldap.LDAPFilter_or(t))
or_.setName('or')
and_ = Suppress(Literal('&')) + filterlist
and_.setParseAction(lambda s,l,t: pureldap.LDAPFilter_and(t))
and_.setName('and')
filtercomp = and_ | or_ | not_ | item
filtercomp.setName('filtercomp')
filter_ << (Suppress(Literal('(').leaveWhitespace())
+ filtercomp
+ Suppress(Literal(')').leaveWhitespace()))
filter_.setName('filter')
filtercomp.leaveWhitespace()
filter_.leaveWhitespace()
toplevel = (StringStart().leaveWhitespace()
+ filter_
+ StringEnd().leaveWhitespace())
toplevel.leaveWhitespace()
toplevel.setName('toplevel')
def parseFilter(s):
try:
x=toplevel.parseString(s)
except ParseException, e:
raise InvalidLDAPFilter, (e.msg,
e.loc,
e.line)
assert len(x)==1
return x[0]
maybeSubString_value = Combine(OneOrMore(CharsNotIn('*\\\0') | escaped))
maybeSubString_simple = copy.copy(maybeSubString_value)
def _p_maybeSubString_simple(s,l,t):
return (lambda attr:
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(attr),
assertionValue=pureldap.LDAPAssertionValue(t[0])))
maybeSubString_simple.setParseAction(_p_maybeSubString_simple)
maybeSubString_present = Literal("*")
def _p_maybeSubString_present(s,l,t):
return (lambda attr:
pureldap.LDAPFilter_present(attr))
maybeSubString_present.setParseAction(_p_maybeSubString_present)
maybeSubString_substring = Optional(initial) + any + Optional(final)
def _p_maybeSubString_substring(s,l,t):
return (lambda attr:
pureldap.LDAPFilter_substrings(
type=attr,
substrings=t))
maybeSubString_substring.setParseAction(_p_maybeSubString_substring)
maybeSubString = (maybeSubString_simple
^ maybeSubString_present
^ maybeSubString_substring
)
def parseMaybeSubstring(attrType, s):
try:
x=maybeSubString.parseString(s)
except ParseException, e:
raise InvalidLDAPFilter, (e.msg,
e.loc,
e.line)
assert len(x)==1
fn = x[0]
return fn(attrType)
if __name__=='__main__':
import sys
for filt in sys.argv[1:]:
print repr(parseFilter(filt))
print
ldaptor-0.0.43/ldaptor/inmemory.py 0000644 0001750 0001750 00000015005 10352535700 015224 0 ustar jan jan from zope.interface import implements
from twisted.internet import defer, error
from twisted.python.failure import Failure
from ldaptor import interfaces, entry, entryhelpers
from ldaptor.protocols.ldap import distinguishedname, ldaperrors, ldifprotocol
class LDAPCannotRemoveRootError(ldaperrors.LDAPNamingViolation):
"""Cannot remove root of LDAP tree"""
class ReadOnlyInMemoryLDAPEntry(entry.EditableLDAPEntry,
entryhelpers.DiffTreeMixin,
entryhelpers.SubtreeFromChildrenMixin,
entryhelpers.MatchMixin,
entryhelpers.SearchByTreeWalkingMixin,
):
implements(interfaces.IConnectedLDAPEntry)
def __init__(self, *a, **kw):
entry.BaseLDAPEntry.__init__(self, *a, **kw)
self._parent = None
self._children = []
def parent(self):
return self._parent
def children(self, callback=None):
if callback is None:
return defer.succeed(self._children[:])
else:
for c in self._children:
callback(c)
return defer.succeed(None)
def _lookup(self, dn):
if not self.dn.contains(dn):
raise ldaperrors.LDAPNoSuchObject(dn)
if dn == self.dn:
return defer.succeed(self)
for c in self._children:
if c.dn.contains(dn):
return c.lookup(dn)
raise ldaperrors.LDAPNoSuchObject(dn)
def lookup(self, dn):
return defer.maybeDeferred(self._lookup, dn)
def fetch(self, *attributes):
return defer.succeed(self)
def addChild(self, rdn, attributes):
"""TODO ugly API. Returns the created entry."""
rdn = distinguishedname.RelativeDistinguishedName(rdn)
for c in self._children:
if c.dn.split()[0] == rdn:
raise ldaperrors.LDAPEntryAlreadyExists, c.dn
dn = distinguishedname.DistinguishedName(listOfRDNs=
(rdn,)
+self.dn.split())
e = ReadOnlyInMemoryLDAPEntry(dn, attributes)
e._parent = self
self._children.append(e)
return e
def _delete(self):
if self._parent is None:
raise LDAPCannotRemoveRootError
if self._children:
raise ldaperrors.LDAPNotAllowedOnNonLeaf, self.dn
return self._parent.deleteChild(self.dn.split()[0])
def delete(self):
return defer.maybeDeferred(self._delete)
def _deleteChild(self, rdn):
if not isinstance(rdn, distinguishedname.RelativeDistinguishedName):
rdn = distinguishedname.RelativeDistinguishedName(stringValue=rdn)
for c in self._children:
if c.dn.split()[0] == rdn:
self._children.remove(c)
return c
raise ldaperrors.LDAPNoSuchObject, rdn
def deleteChild(self, rdn):
return defer.maybeDeferred(self._deleteChild, rdn)
def _move(self, newDN):
if not isinstance(newDN, distinguishedname.DistinguishedName):
newDN = distinguishedname.DistinguishedName(stringValue=newDN)
if newDN.up() != self.dn.up():
# climb up the tree to root
root = self
while root._parent is not None:
root = root._parent
d = defer.maybeDeferred(root.lookup, newDN.up())
else:
d = defer.succeed(None)
d.addCallback(self._move2, newDN)
return d
def _move2(self, newParent, newDN):
if newParent is not None:
newParent._children.append(self)
self._parent._children.remove(self)
# remove old RDN attributes
for attr in self.dn.split()[0].split():
self[attr.attributeType].remove(attr.value)
# add new RDN attributes
for attr in newDN.split()[0].split():
# TODO what if the key does not exist?
self[attr.attributeType].add(attr.value)
self.dn = newDN
return self
def move(self, newDN):
return defer.maybeDeferred(self._move, newDN)
def commit(self):
return defer.succeed(self)
class InMemoryLDIFProtocol(ldifprotocol.LDIF):
"""
Receive LDIF data and gather results into an ReadOnlyInMemoryLDAPEntry.
You can override lookupFailed and addFailed to provide smarter
error handling. They are called as Deferred errbacks; returning
the reason causes error to pass onward and abort the whole
operation. Returning None from lookupFailed skips that entry, but
continues loading.
When the full LDIF data has been read, the completed Deferred will
trigger.
"""
def __init__(self):
self.db = None #do not access this via db, just to make sure you respect the ordering
self._deferred = defer.Deferred()
self.completed = defer.Deferred()
def _addEntry(self, db, entry):
d = db.lookup(entry.dn.up())
d.addErrback(self.lookupFailed, entry)
def _add(parent, entry):
if parent is not None:
parent.addChild(rdn=entry.dn.split()[0],
attributes=entry)
d.addCallback(_add, entry)
d.addErrback(self.addFailed, entry)
def _passDB(_, db):
return db
d.addCallback(_passDB, db)
return d
def gotEntry(self, entry):
if self.db is None:
# first entry, create the db, prepare to process the rest
self.db = ReadOnlyInMemoryLDAPEntry(
dn=entry.dn,
attributes=entry)
self._deferred.callback(self.db)
else:
self._deferred.addCallback(self._addEntry, entry)
def lookupFailed(self, reason, entry):
return reason # pass the error (abort) by default
def addFailed(self, reason, entry):
return reason # pass the error (abort) by default
def connectionLost(self, reason):
super(InMemoryLDIFProtocol, self).connectionLost(reason)
if not reason.check(error.ConnectionDone):
self._deferred.addCallback(lambda db: reason)
else:
self._deferred.chainDeferred(self.completed)
del self._deferred # invalidate it to flush out bugs
def fromLDIFFile(f):
"""Read LDIF data from a file."""
p = InMemoryLDIFProtocol()
while 1:
data = f.read()
if not data:
break
p.dataReceived(data)
p.connectionLost(Failure(error.ConnectionDone()))
return p.completed
ldaptor-0.0.43/ldaptor/testutil.py 0000644 0001750 0001750 00000010314 10345261504 015240 0 ustar jan jan """Utilities for writing Twistedy unit tests and debugging."""
from twisted.internet import defer
from twisted.trial import unittest
from twisted.test import proto_helpers
from ldaptor import config
def mustRaise(dummy):
raise unittest.FailTest('Should have raised an exception.')
def calltrace():
"""Print out all function calls. For debug use only."""
def printfuncnames(frame, event, arg):
print "|%s: %s:%d:%s" % (event,
frame.f_code.co_filename,
frame.f_code.co_firstlineno,
frame.f_code.co_name)
import sys
sys.setprofile(printfuncnames)
class FakeTransport:
def __init__(self, proto):
self.proto = proto
def loseConnection(self):
self.proto.connectionLost()
class LDAPClientTestDriver:
"""
A test driver that looks somewhat like a real LDAPClient.
Pass in a list of lists of LDAPProtocolResponses. For each sent
LDAP message, the first item of said list is iterated through, and
all the items are sent as responses to the callback. The sent LDAP
messages are stored in self.sent, so you can assert that the sent
messages are what they are supposed to be.
"""
def __init__(self, *responses):
self.sent=[]
self.responses=list(responses)
self.connected = None
self.transport = FakeTransport(self)
def send(self, op):
self.sent.append(op)
l = self._response()
assert len(l) == 1, \
"got %d responses for a .send()" % len(l)
return defer.succeed(l[0])
def send_multiResponse(self, op, handler, *args, **kwargs):
self.sent.append(op)
responses = self._response()
while responses:
r = responses.pop(0)
ret = handler(r, *args, **kwargs)
if responses:
assert not ret, \
"got %d responses still to give, but handler wants none (got %r)." % (len(responses), ret)
else:
assert ret, \
"no more responses to give, but handler still wants more (got %r)." % ret
def send_noResponse(self, op):
responses = self.responses.pop(0)
assert not responses
self.sent.append(op)
def _response(self):
assert self.responses, 'Ran out of responses'
responses = self.responses.pop(0)
return responses
def assertNothingSent(self):
# just a bit more explicit
self.assertSent()
def assertSent(self, *shouldBeSent):
shouldBeSent = list(shouldBeSent)
assert self.sent == shouldBeSent, \
'%s expected to send %r but sent %r' % (
self.__class__.__name__,
shouldBeSent,
self.sent)
sentStr = ''.join([str(x) for x in self.sent])
shouldBeSentStr = ''.join([str(x) for x in shouldBeSent])
assert sentStr == shouldBeSentStr, \
'%s expected to send data %r but sent %r' % (
self.__class__.__name__,
shouldBeSentStr,
sentStr)
def connectionMade(self):
"""TCP connection has opened"""
self.connected = 1
def connectionLost(self, reason=None):
"""Called when TCP connection has been lost"""
assert not self.responses, \
"connectionLost called even when have responses left: %r" % self.responses
self.connected = 0
def unbind(self):
assert self.connected
r='fake-unbind-by-LDAPClientTestDriver'
self.send_noResponse(r)
self.transport.loseConnection()
def createServer(proto, *responses, **kw):
def createClient(factory):
factory.doStart()
#TODO factory.startedConnecting(c)
proto = factory.buildProtocol(addr=None)
proto.connectionMade()
cfg = config.loadConfig(
configFiles=[],
reload=True)
overrides = kw.setdefault('serviceLocationOverrides', {})
overrides.setdefault('', createClient)
conf = config.LDAPConfig(**kw)
server = proto(conf)
server.protocol = lambda : LDAPClientTestDriver(*responses)
server.transport = proto_helpers.StringTransport()
server.connectionMade()
return server
ldaptor-0.0.43/ldaptor/__init__.py 0000644 0001750 0001750 00000000000 07516345760 015126 0 ustar jan jan ldaptor-0.0.43/ldaptor/attributeset.py 0000644 0001750 0001750 00000003221 10344535643 016110 0 ustar jan jan import sets
from copy import deepcopy
class LDAPAttributeSet(sets.Set):
def __init__(self, key, *a, **kw):
self.key = key
super(LDAPAttributeSet, self).__init__(*a, **kw)
def __repr__(self):
values=list(self)
values.sort()
attributes=', '.join([repr(x) for x in values])
return '%s(%r, [%s])' % (
self.__class__.__name__,
self.key,
attributes)
def __eq__(self, other):
"""
Note that LDAPAttributeSets can also be compared against any
iterator. In that case the attributeType will be ignored.
"""
if isinstance(other, LDAPAttributeSet):
if self.key != other.key:
return False
return super(LDAPAttributeSet, self).__eq__(other)
else:
me=list(self)
me.sort()
him=list(other)
him.sort()
return me == him
def __ne__(self, other):
return not self==other
def difference(self, other):
return sets.Set(self) - sets.Set(other)
def union(self, other):
return sets.Set(self) | sets.Set(other)
def intersection(self, other):
return sets.Set(self) & sets.Set(other)
def symmetric_difference(self, other):
return sets.Set(self) ^ sets.Set(other)
def copy(self):
result = self.__class__(self.key)
result.update(self)
return result
__copy__ = copy
def __deepcopy__(self, memo):
result = self.__class__(self.key)
memo[id(self)] = result
data = deepcopy(sets.Set(self), memo)
result.update(data)
return result
ldaptor-0.0.43/ldaptor/test/ 0000755 0001750 0001750 00000000000 10403234303 013761 5 ustar jan jan ldaptor-0.0.43/ldaptor/test/test_proxy.py 0000644 0001750 0001750 00000007774 10344407651 016606 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.proxy module.
"""
from twisted.trial import unittest
from twisted.internet import reactor, error
from ldaptor.protocols.ldap import proxy, ldaperrors
from ldaptor.protocols import pureldap
from ldaptor import testutil
class Proxy(unittest.TestCase):
def createServer(self, *responses):
return testutil.createServer(proxy.Proxy, *responses)
def test_bind(self):
server = self.createServer([ pureldap.LDAPBindResponse(resultCode=0),
])
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(), id=4)))
reactor.iterate() #TODO
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=0), id=4)))
def test_search(self):
server = self.createServer([ pureldap.LDAPBindResponse(resultCode=0),
],
[ pureldap.LDAPSearchResultEntry('cn=foo,dc=example,dc=com', [('a', ['b'])]),
pureldap.LDAPSearchResultEntry('cn=bar,dc=example,dc=com', [('b', ['c'])]),
pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode),
],
)
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(), id=2)))
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPSearchRequest(), id=3)))
reactor.iterate() #TODO
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=0), id=2))
+str(pureldap.LDAPMessage(pureldap.LDAPSearchResultEntry('cn=foo,dc=example,dc=com', [('a', ['b'])]), id=3))
+str(pureldap.LDAPMessage(pureldap.LDAPSearchResultEntry('cn=bar,dc=example,dc=com', [('b', ['c'])]), id=3))
+str(pureldap.LDAPMessage(pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode), id=3)))
def test_unbind_clientUnbinds(self):
server = self.createServer([ pureldap.LDAPBindResponse(resultCode=0),
],
[],
)
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(), id=2)))
reactor.iterate() #TODO
client = server.client
client.assertSent(pureldap.LDAPBindRequest())
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=0), id=2)))
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPUnbindRequest(), id=3)))
server.connectionLost(error.ConnectionDone)
reactor.iterate() #TODO
client.assertSent(pureldap.LDAPBindRequest(),
pureldap.LDAPUnbindRequest())
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=0), id=2)))
def test_unbind_clientEOF(self):
server = self.createServer([ pureldap.LDAPBindResponse(resultCode=0),
],
[],
)
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(), id=2)))
reactor.iterate() #TODO
client = server.client
client.assertSent(pureldap.LDAPBindRequest())
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=0), id=2)))
server.connectionLost(error.ConnectionDone)
reactor.iterate() #TODO
client.assertSent(pureldap.LDAPBindRequest(),
'fake-unbind-by-LDAPClientTestDriver')
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=0), id=2)))
ldaptor-0.0.43/ldaptor/test/test_smbpassword.py 0000644 0001750 0001750 00000004310 10344535643 017753 0 ustar jan jan """
Test cases for the ldaptor.samba.smbpassword module.
"""
from twisted.trial import unittest
from ldaptor.samba import smbpassword
from ldaptor import config
class TestNTHash(unittest.TestCase):
knownValues=( # password, expected_result
('', '31D6CFE0D16AE931B73C59D7E0C089C0'),
('foo', 'AC8E657F83DF82BEEA5D43BDAF7800CC'),
(127*'x', '25900FAB94A048BCF438615217776562'),
(128*'x', '65681023D0CB5E7E96FF662150EF060D'),
(129*'x', '65681023D0CB5E7E96FF662150EF060D'),
(1000*'x', '65681023D0CB5E7E96FF662150EF060D'),
)
def testKnownValues(self):
"""nthash(...) gives known results"""
for password, expected_result in self.knownValues:
result = smbpassword.nthash(password)
if result != expected_result:
raise AssertionError, 'nthash(%s)=%s, expected %s' \
% (repr(password), repr(result), repr(expected_result))
class TestLMHash(unittest.TestCase):
knownValues=( # password, expected_result
('', 'AAD3B435B51404EEAAD3B435B51404EE'),
('foo', '5BFAFBEBFB6A0942AAD3B435B51404EE'),
(13*'x', '3AA62DBBEFDB676366B4159AF5A7C45C'),
(14*'x', '3AA62DBBEFDB67633AA62DBBEFDB6763'),
(15*'x', '3AA62DBBEFDB67633AA62DBBEFDB6763'),
(100*'x', '3AA62DBBEFDB67633AA62DBBEFDB6763'),
('1234567abcdefg', '0182BD0BD4444BF8E0C510199CC66ABD'),
('XXXXXXXabcdefg', '3AA62DBBEFDB6763E0C510199CC66ABD'),
('1234567XXXXXXX', '0182BD0BD4444BF83AA62DBBEFDB6763'),
)
def testKnownValues(self):
"""lmhash(...) gives known results"""
cfg = config.loadConfig()
for password, expected_result in self.knownValues:
cfg.set('samba', 'use-lmhash', 'no')
disabled = smbpassword.lmhash(password)
self.assertEquals(disabled, 32*'X',
"Disabled lmhash must be X's: %r" % disabled)
cfg.set('samba', 'use-lmhash', 'yes')
result = smbpassword.lmhash(password)
if result != expected_result:
raise AssertionError, 'lmhash(%s)=%s, expected %s' \
% (repr(password), repr(result), repr(expected_result))
ldaptor-0.0.43/ldaptor/test/test_config.py 0000644 0001750 0001750 00000003522 10173563735 016663 0 ustar jan jan """
Test cases for the ldaptor.config module.
"""
from twisted.trial import unittest
import os
from ldaptor import config
def writeFile(path, content):
f = file(path, 'w')
f.write(content)
f.close()
class TestConfig(unittest.TestCase):
def testSomething(self):
self.dir = self.mktemp()
os.mkdir(self.dir)
self.f1 = os.path.join(self.dir, 'one.cfg')
writeFile(self.f1, """\
[fooSection]
fooVar = val
[barSection]
barVar = anotherVal
""")
self.f2 = os.path.join(self.dir, 'two.cfg')
writeFile(self.f2, """\
[fooSection]
fooVar = val2
""")
self.cfg = config.loadConfig(
configFiles=[self.f1, self.f2],
reload=True)
val = self.cfg.get('fooSection', 'fooVar')
self.assertEquals(val, 'val2')
val = self.cfg.get('barSection', 'barVar')
self.assertEquals(val, 'anotherVal')
class IdentitySearch(unittest.TestCase):
def setUp(self):
self.dir = self.mktemp()
os.mkdir(self.dir)
self.f1 = os.path.join(self.dir, 'one.cfg')
writeFile(self.f1, """\
[authentication]
identity-search = (something=%(name)s)
""")
self.cfg = config.loadConfig(
configFiles=[self.f1],
reload=True)
self.config = config.LDAPConfig()
def testConfig(self):
self.assertEquals(self.config.getIdentitySearch('foo'),
'(something=foo)')
def testCopy(self):
conf = self.config.copy(identitySearch='(&(bar=baz)(quux=%(name)s))')
self.assertEquals(conf.getIdentitySearch('foo'),
'(&(bar=baz)(quux=foo))')
def testInitArg(self):
conf = config.LDAPConfig(identitySearch='(&(bar=thud)(quux=%(name)s))')
self.assertEquals(conf.getIdentitySearch('foo'),
'(&(bar=thud)(quux=foo))')
ldaptor-0.0.43/ldaptor/test/test_ldiftree.py 0000644 0001750 0001750 00000063452 10402661536 017215 0 ustar jan jan """
Test cases for LDIF directory tree writing/reading.
"""
from twisted.trial import unittest
import os, random, errno, shutil, sets
from ldaptor import ldiftree, entry, delta, testutil
from ldaptor.entry import BaseLDAPEntry
from ldaptor.protocols.ldap import ldaperrors, ldifprotocol
def writeFile(path, content):
f = file(path, 'w')
f.write(content)
f.close()
class RandomizeListdirMixin(object):
def randomListdir(self, *args, **kwargs):
r = self.__listdir(*args, **kwargs)
random.shuffle(r)
return r
def setUpClass(self):
self.__listdir = os.listdir
os.listdir = self.randomListdir
def tearDownClass(self):
os.listdir = self.__listdir
class Dir2LDIF(RandomizeListdirMixin, unittest.TestCase):
def setUp(self):
self.tree = self.mktemp()
os.mkdir(self.tree)
com = os.path.join(self.tree, 'dc=com.dir')
os.mkdir(com)
example = os.path.join(com, 'dc=example.dir')
os.mkdir(example)
writeFile(os.path.join(example, 'cn=foo.ldif'),
"""\
dn: cn=foo,dc=example,dc=com
cn: foo
objectClass: top
""")
writeFile(os.path.join(example, 'cn=bad-two-entries.ldif'),
"""\
dn: cn=bad-two-entries,dc=example,dc=com
cn: bad-two-entries
objectClass: top
dn: cn=more,dc=example,dc=com
cn: more
objectClass: top
""")
writeFile(os.path.join(example, 'cn=bad-missing-end.ldif'),
"""\
dn: cn=bad-missing-end,dc=example,dc=com
cn: bad-missing-end
objectClass: top
""")
writeFile(os.path.join(example, 'cn=bad-empty.ldif'), '')
writeFile(os.path.join(example, 'cn=bad-only-newline.ldif'), '\n')
sales = os.path.join(example, 'ou=Sales.dir')
os.mkdir(sales)
writeFile(os.path.join(sales, 'cn=sales-thingie.ldif'),
"""\
dn: cn=sales-thingie,ou=Sales,dc=example,dc=com
cn: sales-thingie
objectClass: top
""")
def testSimpleRead(self):
want = BaseLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['top'],
'cn': ['foo'],
})
d = ldiftree.get(self.tree, want.dn)
d.addCallback(self.failUnlessEqual, want)
return d
def testNoAccess(self):
os.chmod(os.path.join(self.tree,
'dc=com.dir',
'dc=example.dir',
'cn=foo.ldif'),
0)
d = ldiftree.get(self.tree, 'cn=foo,dc=example,dc=com')
def eb(fail):
fail.trap(IOError)
self.assertEquals(fail.value.errno, errno.EACCES)
d.addCallbacks(testutil.mustRaise, eb)
return d
if os.getuid() == 0:
testNoAccess.skip = "Can't test as root"
def gettingDNRaises(self, dn, exceptionClass):
d = ldiftree.get(self.tree, dn)
def eb(fail):
fail.trap(exceptionClass)
d.addCallbacks(testutil.mustRaise, eb)
return d
def testMultipleError(self):
return self.gettingDNRaises(
'cn=bad-two-entries,dc=example,dc=com',
ldiftree.LDIFTreeEntryContainsMultipleEntries)
def testMissingEndError(self):
return self.gettingDNRaises(
'cn=bad-missing-end,dc=example,dc=com',
ldiftree.LDIFTreeEntryContainsNoEntries)
def testEmptyError(self):
return self.gettingDNRaises(
'cn=bad-empty,dc=example,dc=com',
ldiftree.LDIFTreeEntryContainsNoEntries)
def testOnlyNewlineError(self):
return self.gettingDNRaises(
'cn=bad-only-newline,dc=example,dc=com',
ldifprotocol.LDIFLineWithoutSemicolonError)
def testTreeBranches(self):
want = BaseLDAPEntry(dn='cn=sales-thingie,ou=Sales,dc=example,dc=com',
attributes={
'objectClass': ['top'],
'cn': ['sales-thingie'],
})
d = ldiftree.get(self.tree, want.dn)
d.addCallback(self.failUnlessEqual, want)
return d
class LDIF2Dir(RandomizeListdirMixin, unittest.TestCase):
def setUp(self):
self.tree = self.mktemp()
os.mkdir(self.tree)
com = os.path.join(self.tree, 'dc=com.dir')
os.mkdir(com)
example = os.path.join(com, 'dc=example.dir')
os.mkdir(example)
writeFile(os.path.join(example, 'cn=pre-existing.ldif'),
"""\
dn: cn=pre-existing,dc=example,dc=com
cn: pre-existing
objectClass: top
""")
writeFile(os.path.join(example, 'ou=OrgUnit.ldif'),
"""\
dn: ou=OrgUnit,dc=example,dc=com
ou: OrgUnit
objectClass: organizationalUnit
""")
def testSimpleWrite(self):
e = BaseLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['top'],
'cn': ['foo'],
})
d = ldiftree.put(self.tree, e)
d.addCallback(self._cb_testSimpleWrite)
return d
def _cb_testSimpleWrite(self, entry):
path = os.path.join(self.tree, 'dc=com.dir', 'dc=example.dir', 'cn=foo.ldif')
self.failUnless(os.path.isfile(path))
self.failUnlessEqual(file(path).read(),
"""\
dn: cn=foo,dc=example,dc=com
objectClass: top
cn: foo
""")
def testDirCreation(self):
e = BaseLDAPEntry(dn='cn=create-me,ou=OrgUnit,dc=example,dc=com',
attributes={
'objectClass': ['top'],
'cn': ['create-me'],
})
d = ldiftree.put(self.tree, e)
d.addCallback(self._cb_testDirCreation)
return d
def _cb_testDirCreation(self, entry):
path = os.path.join(self.tree, 'dc=com.dir', 'dc=example.dir',
'ou=OrgUnit.dir', 'cn=create-me.ldif')
self.failUnless(os.path.isfile(path))
self.failUnlessEqual(file(path).read(),
"""\
dn: cn=create-me,ou=OrgUnit,dc=example,dc=com
objectClass: top
cn: create-me
""")
def testDirExists(self):
e = BaseLDAPEntry(dn='cn=create-me,ou=OrgUnit,dc=example,dc=com',
attributes={
'objectClass': ['top'],
'cn': ['create-me'],
})
dirpath = os.path.join(self.tree, 'dc=com.dir', 'dc=example.dir',
'ou=OrgUnit.dir')
os.mkdir(dirpath)
d = ldiftree.put(self.tree, e)
d.addCallback(self._cb_testDirExists, dirpath)
return d
def _cb_testDirExists(self, entry, dirpath):
path = os.path.join(dirpath, 'cn=create-me.ldif')
self.failUnless(os.path.isfile(path))
self.failUnlessEqual(file(path).read(),
"""\
dn: cn=create-me,ou=OrgUnit,dc=example,dc=com
objectClass: top
cn: create-me
""")
def testMissingLinkError(self):
e = BaseLDAPEntry(dn='cn=bad-create,ou=NoSuchOrgUnit,dc=example,dc=com',
attributes={
'objectClass': ['top'],
'cn': ['bad-create'],
})
d = ldiftree.put(self.tree, e)
d.addCallbacks(self._cb_testMissingLinkError,
self._eb_testMissingLinkError)
return d
def _cb_testMissingLinkError(self):
raise unittest.FailTest('Should have raised an exception.')
def _eb_testMissingLinkError(self, fail):
fail.trap(ldiftree.LDIFTreeNoSuchObject)
def testAddTopLevel(self):
e = BaseLDAPEntry(dn='dc=org',
attributes={
'objectClass': ['dcObject'],
'dc': ['org'],
})
d = ldiftree.put(self.tree, e)
d.addCallback(self._cb_testAddTopLevel)
return d
def _cb_testAddTopLevel(self, entry):
path = os.path.join(self.tree, 'dc=org.ldif')
self.failUnless(os.path.isfile(path))
self.failUnlessEqual(file(path).read(),
"""\
dn: dc=org
objectClass: dcObject
dc: org
""")
class Tree(RandomizeListdirMixin, unittest.TestCase):
# TODO share the actual tests with inmemory and any other
# implementations of the same interface
def setUp(self):
self.tree = self.mktemp()
os.mkdir(self.tree)
com = os.path.join(self.tree, 'dc=com.dir')
os.mkdir(com)
example = os.path.join(com, 'dc=example.dir')
os.mkdir(example)
meta = os.path.join(example, 'ou=metasyntactic.dir')
os.mkdir(meta)
writeFile(os.path.join(example, 'ou=metasyntactic.ldif'),
"""\
dn: ou=metasyntactic,dc=example,dc=com
objectClass: a
objectClass: b
ou: metasyntactic
""")
foo = os.path.join(meta, 'cn=foo.dir')
writeFile(os.path.join(meta, 'cn=foo.ldif'),
"""\
dn: cn=foo,ou=metasyntactic,dc=example,dc=com
objectClass: a
objectClass: b
cn: foo
""")
bar = os.path.join(meta, 'cn=bar.dir')
writeFile(os.path.join(meta, 'cn=bar.ldif'),
"""\
dn: cn=bar,ou=metasyntactic,dc=example,dc=com
objectClass: a
objectClass: b
cn: bar
""")
empty = os.path.join(example, 'ou=empty.dir')
writeFile(os.path.join(example, 'ou=empty.ldif'),
"""\
dn: ou=empty,dc=example,dc=com
objectClass: a
objectClass: b
ou: empty
""")
oneChild = os.path.join(example, 'ou=oneChild.dir')
os.mkdir(oneChild)
writeFile(os.path.join(example, 'ou=oneChild.ldif'),
"""\
dn: ou=oneChild,dc=example,dc=com
objectClass: a
objectClass: b
ou: oneChild
""")
theChild = os.path.join(oneChild, 'cn=theChild.dir')
writeFile(os.path.join(oneChild, 'cn=theChild.ldif'),
"""\
dn: cn=theChild,ou=oneChild,dc=example,dc=com
objectClass: a
objectClass: b
cn: theChild
""")
self.root = ldiftree.LDIFTreeEntry(self.tree)
self.example = ldiftree.LDIFTreeEntry(example, 'dc=example,dc=com')
self.empty = ldiftree.LDIFTreeEntry(empty, 'ou=empty,dc=example,dc=com')
self.meta = ldiftree.LDIFTreeEntry(meta, 'ou=metasyntactic,dc=example,dc=com')
self.foo = ldiftree.LDIFTreeEntry(foo, 'cn=foo,ou=metasyntactic,dc=example,dc=com')
self.bar = ldiftree.LDIFTreeEntry(bar, 'cn=bar,ou=metasyntactic,dc=example,dc=com')
self.oneChild = ldiftree.LDIFTreeEntry(oneChild, 'ou=oneChild,dc=example,dc=com')
self.theChild = ldiftree.LDIFTreeEntry(theChild, 'cn=theChild,ou=oneChild,dc=example,dc=com')
def test_children_empty(self):
d = self.empty.children()
def cb(children):
self.assertEquals(children, [])
d.addCallback(cb)
return d
def test_children_oneChild(self):
d = self.oneChild.children()
d.addCallback(self._cb_test_children_oneChild)
return d
def _cb_test_children_oneChild(self, children):
self.assertEquals(len(children), 1)
got = [e.dn for e in children]
want = ['cn=theChild,ou=oneChild,dc=example,dc=com']
got.sort()
want.sort()
self.assertEquals(got, want)
def test_children_repeat(self):
"""Test that .children() returns a copy of the data so that modifying it does not affect behaviour."""
d = self.oneChild.children()
d.addCallback(self._cb_test_children_repeat_1)
return d
def _cb_test_children_repeat_1(self, children1):
self.assertEquals(len(children1), 1)
children1.pop()
d = self.oneChild.children()
d.addCallback(self._cb_test_children_repeat_2)
return d
def _cb_test_children_repeat_2(self, children2):
self.assertEquals(len(children2), 1)
def test_children_twoChildren(self):
d = self.meta.children()
d.addCallback(self._cb_test_children_twoChildren)
return d
def _cb_test_children_twoChildren(self, children):
self.assertEquals(len(children), 2)
want = [
'cn=foo,ou=metasyntactic,dc=example,dc=com',
'cn=bar,ou=metasyntactic,dc=example,dc=com',
]
got = [e.dn for e in children]
got.sort()
want.sort()
self.assertEquals(got, want)
def test_children_twoChildren_callback(self):
children = []
d = self.meta.children(callback=children.append)
d.addCallback(self._cb_test_children_twoChildren_callback, children)
return d
def _cb_test_children_twoChildren_callback(self, r, children):
self.assertIdentical(r, None)
self.assertEquals(len(children), 2)
want = [
'cn=foo,ou=metasyntactic,dc=example,dc=com',
'cn=bar,ou=metasyntactic,dc=example,dc=com',
]
got = [e.dn for e in children]
got.sort()
want.sort()
self.assertEquals(got, want)
def test_children_noAccess_dir_noRead(self):
os.chmod(self.meta.path, 0300)
d = self.meta.children()
def eb(fail):
fail.trap(OSError)
self.assertEquals(fail.value.errno, errno.EACCES)
os.chmod(self.meta.path, 0755)
d.addCallbacks(testutil.mustRaise, eb)
return d
if os.getuid() == 0:
test_children_noAccess_dir_noRead.skip = "Can't test as root"
def test_children_noAccess_dir_noExec(self):
os.chmod(self.meta.path, 0600)
d = self.meta.children()
def eb(fail):
fail.trap(IOError)
self.assertEquals(fail.value.errno, errno.EACCES)
os.chmod(self.meta.path, 0755)
d.addCallbacks(testutil.mustRaise, eb)
return d
if os.getuid() == 0:
test_children_noAccess_dir_noExec.skip = "Can't test as root"
def test_children_noAccess_file(self):
os.chmod(os.path.join(self.meta.path, 'cn=foo.ldif'), 0)
d = self.meta.children()
def eb(fail):
fail.trap(IOError)
self.assertEquals(fail.value.errno, errno.EACCES)
d.addCallbacks(testutil.mustRaise, eb)
return d
if os.getuid() == 0:
test_children_noAccess_file.skip = "Can't test as root"
def test_addChild(self):
self.empty.addChild(
rdn='a=b',
attributes={
'objectClass': ['a', 'b'],
'a': 'b',
})
d = self.empty.children()
d.addCallback(self._cb_test_addChild)
return d
def _cb_test_addChild(self, children):
self.assertEquals(len(children), 1)
got = [e.dn for e in children]
want = [
'a=b,ou=empty,dc=example,dc=com',
]
got.sort()
want.sort()
self.assertEquals(got, want)
def test_addChild_Exists(self):
self.assertRaises(ldaperrors.LDAPEntryAlreadyExists,
self.meta.addChild,
rdn='cn=foo',
attributes={
'objectClass': ['a'],
'cn': 'foo',
})
def test_parent(self):
self.assertEquals(self.foo.parent(), self.meta)
self.assertEquals(self.meta.parent(), self.example)
self.assertEquals(self.root.parent(), None)
def test_subtree_empty(self):
d = self.empty.subtree()
d.addCallback(self._cb_test_subtree_empty)
return d
def _cb_test_subtree_empty(self, entries):
self.assertEquals(len(entries), 1)
def test_subtree_oneChild(self):
d = self.oneChild.subtree()
d.addCallback(self._cb_test_subtree_oneChild)
return d
def _cb_test_subtree_oneChild(self, results):
got = results
want = [
self.oneChild,
self.theChild,
]
self.assertEquals(got, want)
def test_subtree_oneChild_cb(self):
got = []
d = self.oneChild.subtree(got.append)
d.addCallback(self._cb_test_subtree_oneChild_cb, got)
return d
def _cb_test_subtree_oneChild_cb(self, r, got):
self.assertEquals(r, None)
want = [
self.oneChild,
self.theChild,
]
self.assertEquals(got, want)
def test_subtree_many(self):
d = self.example.subtree()
d.addCallback(self._cb_test_subtree_many)
return d
def _cb_test_subtree_many(self, results):
got = results
want = [
self.example,
self.oneChild,
self.theChild,
self.empty,
self.meta,
self.bar,
self.foo,
]
got.sort()
want.sort()
self.assertEquals(got, want)
def test_subtree_many_cb(self):
got = []
d = self.example.subtree(callback=got.append)
d.addCallback(self._cb_test_subtree_many_cb, got)
return d
def _cb_test_subtree_many_cb(self, r, got):
self.assertEquals(r, None)
want = [
self.example,
self.oneChild,
self.theChild,
self.empty,
self.meta,
self.bar,
self.foo,
]
got.sort()
want.sort()
self.assertEquals(got, want)
def test_lookup_fail(self):
dn = 'cn=thud,ou=metasyntactic,dc=example,dc=com'
d = self.root.lookup(dn)
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
self.assertEquals(fail.value.message, dn)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_lookup_fail_outOfTree(self):
dn = 'dc=invalid'
d = self.root.lookup(dn)
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
self.assertEquals(fail.value.message, dn)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_lookup_fail_outOfTree_2(self):
dn = 'dc=invalid'
d = self.example.lookup(dn)
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
self.assertEquals(fail.value.message, dn)
d.addCallbacks(testutil.mustRaise, eb)
def test_lookup_fail_multipleError(self):
writeFile(os.path.join(self.example.path,
'cn=bad-two-entries.ldif'),
"""\
dn: cn=bad-two-entries,dc=example,dc=com
cn: bad-two-entries
objectClass: top
dn: cn=more,dc=example,dc=com
cn: more
objectClass: top
""")
self.assertRaises(
ldiftree.LDIFTreeEntryContainsMultipleEntries,
self.example.lookup,
'cn=bad-two-entries,dc=example,dc=com')
def test_lookup_fail_emptyError(self):
writeFile(os.path.join(self.example.path,
'cn=bad-empty.ldif'),
"")
self.assertRaises(
ldiftree.LDIFTreeEntryContainsNoEntries,
self.example.lookup,
'cn=bad-empty,dc=example,dc=com')
def test_lookup_deep(self):
dn = 'cn=bar,ou=metasyntactic,dc=example,dc=com'
d = self.root.lookup(dn)
d.addCallback(self._cb_test_lookup_deep)
return d
def _cb_test_lookup_deep(self, r):
self.assertEquals(r, self.bar)
def test_delete_root(self):
d = self.root.delete()
def eb(fail):
fail.trap(ldiftree.LDAPCannotRemoveRootError)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_delete_nonLeaf(self):
d = self.meta.delete()
def eb(fail):
fail.trap(ldaperrors.LDAPNotAllowedOnNonLeaf)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_delete(self):
d = self.foo.delete()
d.addCallback(self._cb_test_delete_1)
return d
def _cb_test_delete_1(self, r):
self.assertEquals(r, self.foo)
d = self.meta.children()
d.addCallback(self._cb_test_delete_2)
return d
def _cb_test_delete_2(self, r):
self.assertEquals(r, [self.bar])
def test_deleteChild(self):
d = self.meta.deleteChild('cn=bar')
d.addCallback(self._cb_test_deleteChild_1)
return d
def _cb_test_deleteChild_1(self, r):
self.assertEquals(r, self.bar)
d = self.meta.children()
d.addCallback(self._cb_test_deleteChild_2)
return d
def _cb_test_deleteChild_2(self, r):
self.assertEquals(r, [self.foo])
def test_deleteChild_NonExisting(self):
d = self.root.deleteChild('cn=not-exist')
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_setPassword(self):
self.foo.setPassword('s3krit', salt='\xf2\x4a')
self.failUnless('userPassword' in self.foo)
self.assertEquals(self.foo['userPassword'],
['{SSHA}0n/Iw1NhUOKyaI9gm9v5YsO3ZInySg=='])
def test_setPassword_noSalt(self):
self.foo.setPassword('s3krit')
self.failUnless('userPassword' in self.foo)
d = self.foo.bind('s3krit')
d.addCallback(self.assertIdentical, self.foo)
d.addCallback(lambda _: self.foo.bind('s4krit'))
def eb(fail):
fail.trap(ldaperrors.LDAPInvalidCredentials)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_diffTree_self(self):
d = self.root.diffTree(self.root)
d.addCallback(self.assertEquals, [])
return d
def test_diffTree_copy(self):
otherDir = self.mktemp()
shutil.copytree(self.tree, otherDir)
other = ldiftree.LDIFTreeEntry(otherDir)
d = self.root.diffTree(other)
d.addCallback(self.assertEquals, [])
return d
def test_diffTree_addChild(self):
otherDir = self.mktemp()
shutil.copytree(self.tree, otherDir)
other = ldiftree.LDIFTreeEntry(otherDir)
e = entry.BaseLDAPEntry(dn='cn=foo,dc=example,dc=com')
d = ldiftree.put(otherDir, e)
def cb1(dummy):
return other.lookup('cn=foo,dc=example,dc=com')
d.addCallback(cb1)
def cb2(r):
d = self.root.diffTree(other)
d.addCallback(self.assertEquals, [delta.AddOp(r)])
return d
d.addCallback(cb2)
return d
def test_diffTree_delChild(self):
otherDir = self.mktemp()
shutil.copytree(self.tree, otherDir)
other = ldiftree.LDIFTreeEntry(otherDir)
d = other.lookup('ou=empty,dc=example,dc=com')
def cb1(otherEmpty):
return otherEmpty.delete()
d.addCallback(cb1)
def cb2(dummy):
return self.root.diffTree(other)
d.addCallback(cb2)
def cb3(got):
self.assertEquals(got, [delta.DeleteOp(self.empty)])
d.addCallback(cb3)
return d
def test_diffTree_edit(self):
otherDir = self.mktemp()
shutil.copytree(self.tree, otherDir)
other = ldiftree.LDIFTreeEntry(otherDir)
d = other.lookup('ou=empty,dc=example,dc=com')
def cb1(otherEmpty):
otherEmpty['foo'] = ['bar']
return otherEmpty.commit()
d.addCallback(cb1)
def cb2(dummy):
return self.root.diffTree(other)
d.addCallback(cb2)
def cb3(got):
self.assertEquals(got, [
delta.ModifyOp(self.empty.dn,
[delta.Add('foo', ['bar'])],
),
])
d.addCallback(cb3)
return d
def test_move_noChildren_sameSuperior(self):
d = self.empty.move('ou=moved,dc=example,dc=com')
def getChildren(dummy):
return self.example.children()
d.addCallback(getChildren)
d.addCallback(sets.Set)
d.addCallback(self.assertEquals, sets.Set([
self.meta,
BaseLDAPEntry(
dn='ou=moved,dc=example,dc=com',
attributes={ 'objectClass': ['a', 'b'],
'ou': ['moved'],
}),
self.oneChild,
]))
return d
def test_move_children_sameSuperior(self):
d = self.meta.move('ou=moved,dc=example,dc=com')
def getChildren(dummy):
return self.example.children()
d.addCallback(getChildren)
d.addCallback(sets.Set)
d.addCallback(self.assertEquals, sets.Set([
BaseLDAPEntry(dn='ou=moved,dc=example,dc=com',
attributes={ 'objectClass': ['a', 'b'],
'ou': ['moved'],
}),
self.empty,
self.oneChild,
]))
return d
def test_move_noChildren_newSuperior(self):
d = self.empty.move('ou=moved,ou=oneChild,dc=example,dc=com')
def getChildren(dummy):
return self.example.children()
d.addCallback(getChildren)
d.addCallback(sets.Set)
d.addCallback(self.assertEquals, sets.Set([
self.meta,
self.oneChild,
]))
def getChildren2(dummy):
return self.oneChild.children()
d.addCallback(getChildren2)
d.addCallback(sets.Set)
d.addCallback(self.assertEquals, sets.Set([
self.theChild,
BaseLDAPEntry(
dn='ou=moved,ou=oneChild,dc=example,dc=com',
attributes={ 'objectClass': ['a', 'b'],
'ou': ['moved'],
}),
]))
return d
def test_move_children_newSuperior(self):
d = self.meta.move('ou=moved,ou=oneChild,dc=example,dc=com')
def getChildren(dummy):
return self.example.children()
d.addCallback(getChildren)
d.addCallback(sets.Set)
d.addCallback(self.assertEquals, sets.Set([
self.empty,
self.oneChild,
]))
def getChildren2(dummy):
return self.oneChild.children()
d.addCallback(getChildren2)
d.addCallback(sets.Set)
d.addCallback(self.assertEquals, sets.Set([
self.theChild,
BaseLDAPEntry(dn='ou=moved,ou=oneChild,dc=example,dc=com',
attributes={ 'objectClass': ['a', 'b'],
'ou': ['moved'],
}),
]))
return d
ldaptor-0.0.43/ldaptor/test/test_ldapsyntax.py 0000755 0001750 0001750 00000163670 10352474314 017614 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.ldapsyntax module.
"""
from twisted.trial import unittest
from ldaptor import config, testutil, delta
from ldaptor.protocols.ldap import ldapsyntax, ldaperrors
from ldaptor.protocols import pureldap, pureber
from twisted.internet import defer
from twisted.python import failure
from ldaptor.testutil import LDAPClientTestDriver
class LDAPSyntaxBasics(unittest.TestCase):
def testCreation(self):
"""Creating an LDAP object should succeed."""
client = LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
self.failUnlessEqual(o['objectClass'], ['a', 'b'])
self.failUnlessEqual(o['aValue'], ['a'])
self.failUnlessEqual(o['bValue'], ['b'])
client.assertNothingSent()
def testKeys(self):
"""Iterating over the keys of an LDAP object gives expected results."""
client = LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
seen={}
for k in o.keys():
assert not seen.has_key(k)
seen[k]=1
assert seen == {'objectClass': 1,
'aValue': 1,
'bValue': 1,
}
def testItems(self):
"""Iterating over the items of an LDAP object gives expected results."""
client = LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
seen={}
for k,vs in o.items():
assert not seen.has_key(k)
seen[k]=vs
assert seen == {'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
}
def testIn(self):
"""Key in object gives expected results."""
client=LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
assert 'objectClass' in o
assert 'aValue' in o
assert 'bValue' in o
assert 'foo' not in o
assert '' not in o
assert None not in o
assert 'a' in o['objectClass']
assert 'b' in o['objectClass']
assert 'foo' not in o['objectClass']
assert '' not in o['objectClass']
assert None not in o['objectClass']
assert 'a' in o['aValue']
assert 'foo' not in o['aValue']
assert '' not in o['aValue']
assert None not in o['aValue']
class LDAPSyntaxAttributes(unittest.TestCase):
def testAttributeSetting(self):
client=LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
o['aValue']=['foo', 'bar']
self.failUnlessEqual(o['aValue'], ['foo', 'bar'])
o['aValue']=['quux']
self.failUnlessEqual(o['aValue'], ['quux'])
self.failUnlessEqual(o['bValue'], ['b'])
o['cValue']=['thud']
self.failUnlessEqual(o['aValue'], ['quux'])
self.failUnlessEqual(o['bValue'], ['b'])
self.failUnlessEqual(o['cValue'], ['thud'])
def testAttributeDelete(self):
client=LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
o['aValue']=['quux']
del o['aValue']
del o['bValue']
self.failIf(o.has_key('aValue'))
self.failIf(o.has_key('bValue'))
def testAttributeAdd(self):
client=LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
o['aValue'].add('foo')
self.failUnlessEqual(o['aValue'], ['a', 'foo'])
def testAttributeItemDelete(self):
client=LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a', 'b', 'c'],
'bValue': ['b'],
})
o['aValue'].remove('b')
self.failUnlessEqual(o['aValue'], ['a', 'c'])
def testUndo(self):
"""Undo should forget the modifications."""
client=LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
'cValue': ['c'],
})
o['aValue']=['foo', 'bar']
o['aValue']=['quux']
del o['cValue']
o.undo()
self.failUnlessEqual(o['aValue'], ['a'])
self.failUnlessEqual(o['bValue'], ['b'])
self.failUnlessEqual(o['cValue'], ['c'])
def testUndoJournaling(self):
"""Journaling should still work after undo."""
client=LDAPClientTestDriver(
[ pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
'cValue': ['c'],
})
o['aValue']=['foo', 'bar']
o['aValue']=['quux']
del o['cValue']
o.undo()
o['aValue'].update(['newValue', 'anotherNewValue'])
d=o.commit()
def cb(dummy):
self.failUnlessEqual(o['aValue'], ['a', 'newValue', 'anotherNewValue'])
self.failUnlessEqual(o['bValue'], ['b'])
self.failUnlessEqual(o['cValue'], ['c'])
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Add('aValue', ['newValue', 'anotherNewValue']),
]).asLDAP())
d.addCallback(cb)
return d
def testUndoAfterCommit(self):
"""Undo should not undo things that have been commited."""
client=LDAPClientTestDriver(
[ pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(
client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
'cValue': ['c'],
})
o['aValue']=['foo', 'bar']
o['bValue']=['quux']
del o['cValue']
d=o.commit()
def cb(dummy):
o.undo()
self.failUnlessEqual(o['aValue'], ['foo', 'bar'])
self.failUnlessEqual(o['bValue'], ['quux'])
self.failIf(o.has_key('cValue'))
d.addCallback(cb)
return d
class LDAPSyntaxAttributesModificationOnWire(unittest.TestCase):
def testAdd(self):
"""Modify & commit should write the right data to the server."""
client = LDAPClientTestDriver(
[ pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
})
o['aValue'].update(['newValue', 'anotherNewValue'])
d=o.commit()
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Add('aValue', ['newValue', 'anotherNewValue']),
]).asLDAP())
d.addCallback(cb)
return d
def testAddSeparate(self):
"""Modify & commit should write the right data to the server."""
client = LDAPClientTestDriver(
[ pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
})
o['aValue'].add('newValue')
o['aValue'].add('anotherNewValue')
d=o.commit()
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Add('aValue', ['newValue']),
delta.Add('aValue', ['anotherNewValue']),
]).asLDAP())
d.addCallback(cb)
return d
def testDeleteAttribute(self):
"""Modify & commit should write the right data to the server."""
client = LDAPClientTestDriver(
[ pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
})
o['aValue'].remove('a')
d=o.commit()
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Delete('aValue', ['a']),
]).asLDAP())
d.addCallback(cb)
return d
def testDeleteAllAttribute(self):
"""Modify & commit should write the right data to the server."""
client = LDAPClientTestDriver(
[ pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a1', 'a2'],
'bValue': ['b1', 'b2'],
})
del o['aValue']
o['bValue'].clear()
d=o.commit()
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Delete('aValue'),
delta.Delete('bValue'),
]).asLDAP())
d.addCallback(cb)
return d
def testReplaceAttributes(self):
"""Modify & commit should write the right data to the server."""
client = LDAPClientTestDriver(
[ pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
})
o['aValue']=['foo', 'bar']
d=o.commit()
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('aValue', ['foo', 'bar']),
]).asLDAP())
d.addCallback(cb)
return d
class LDAPSyntaxSearch(unittest.TestCase):
def testSearch(self):
"""Test searches."""
client=LDAPClientTestDriver([
pureldap.LDAPSearchResultEntry(
objectName='cn=foo,dc=example,dc=com',
attributes=(('foo', ['a']),
('bar', ['b', 'c']),
),
),
pureldap.LDAPSearchResultEntry(
objectName='cn=bar,dc=example,dc=com',
attributes=(('foo', ['a']),
('bar', ['d', 'e']),
),
),
pureldap.LDAPSearchResultDone(
resultCode=0,
matchedDN='',
errorMessage='')
])
o=ldapsyntax.LDAPEntry(client=client,
dn='dc=example,dc=com',
attributes={
'objectClass': ['organizationalUnit'],
})
d=o.search(filterText='(foo=a)',
attributes=['foo', 'bar'])
def cb(val):
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_wholeSubtree,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='foo'),
assertionValue=pureldap.LDAPAssertionValue(value='a')),
attributes=['foo', 'bar']))
self.failUnlessEqual(len(val), 2)
self.failUnlessEqual(val[0],
ldapsyntax.LDAPEntry(
client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'foo': ['a'],
'bar': ['b', 'c'],
}))
self.failUnlessEqual(val[1],
ldapsyntax.LDAPEntry(
client=client,
dn='cn=bar,dc=example,dc=com',
attributes={
'foo': ['a'],
'bar': ['d', 'e'],
}))
d.addCallback(cb)
return d
def testSearch_defaultAttributes(self):
"""Search without explicit list of attributes returns all attributes."""
client=LDAPClientTestDriver([
pureldap.LDAPSearchResultEntry(
objectName='cn=foo,dc=example,dc=com',
attributes=(('foo', ['a']),
('bar', ['b', 'c']),
),
),
pureldap.LDAPSearchResultEntry(
objectName='cn=bar,dc=example,dc=com',
attributes=(('foo', ['a']),
('bar', ['d', 'e']),
),
),
pureldap.LDAPSearchResultDone(
resultCode=0,
matchedDN='',
errorMessage='')
])
o=ldapsyntax.LDAPEntry(client=client,
dn='dc=example,dc=com',
attributes={
'objectClass': ['organizationalUnit'],
})
d=o.search(filterText='(foo=a)')
def cb(val):
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_wholeSubtree,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='foo'),
assertionValue=pureldap.LDAPAssertionValue(value='a')),
attributes=[]))
self.failUnlessEqual(len(val), 2)
self.failUnlessEqual(val[0],
ldapsyntax.LDAPEntry(
client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'foo': ['a'],
'bar': ['b', 'c'],
}))
self.failUnless(val[0].complete)
self.failUnlessEqual(val[1],
ldapsyntax.LDAPEntry(
client=client,
dn='cn=bar,dc=example,dc=com',
attributes={
'foo': ['a'],
'bar': ['d', 'e'],
}))
self.failUnless(val[1].complete)
d.addCallback(cb)
return d
def testSearch_noAttributes(self):
"""Search with attributes=None returns no attributes."""
client=LDAPClientTestDriver([
pureldap.LDAPSearchResultEntry('cn=foo,dc=example,dc=com',
attributes=()),
pureldap.LDAPSearchResultEntry('cn=bar,dc=example,dc=com',
attributes=()),
pureldap.LDAPSearchResultDone(
resultCode=0,
matchedDN='',
errorMessage='')
])
o=ldapsyntax.LDAPEntry(client=client,
dn='dc=example,dc=com',
attributes={
'objectClass': ['organizationalUnit'],
})
d=o.search(filterText='(foo=a)',
attributes=None)
def cb(val):
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_wholeSubtree,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='foo'),
assertionValue=pureldap.LDAPAssertionValue(value='a')),
attributes=['1.1']))
self.failUnlessEqual(len(val), 2)
self.failUnlessEqual(val[0],
ldapsyntax.LDAPEntry(
client=client,
dn='cn=foo,dc=example,dc=com'))
self.failIf(val[0].complete)
self.failUnlessEqual(val[1],
ldapsyntax.LDAPEntry(
client=client,
dn='cn=bar,dc=example,dc=com'))
self.failIf(val[1].complete)
d.addCallback(cb)
return d
def testSearch_ImmediateProcessing(self):
"""Test searches with the immediate processing feature."""
client=LDAPClientTestDriver([
pureldap.LDAPSearchResultEntry(
objectName='cn=foo,dc=example,dc=com',
attributes=(('bar', ['b', 'c']),
),
),
pureldap.LDAPSearchResultEntry(
objectName='cn=bar,dc=example,dc=com',
attributes=(('bar', ['b', 'c']),
),
),
pureldap.LDAPSearchResultDone(
resultCode=0,
matchedDN='',
errorMessage='')
])
o=ldapsyntax.LDAPEntry(client=client,
dn='dc=example,dc=com',
attributes={
'objectClass': ['organizationalUnit'],
})
seen=[]
def process(o):
seen.append(o)
d=o.search(filterText='(foo=a)',
attributes=['bar'],
callback=process)
def cb(val):
self.assertEquals(val, None)
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_wholeSubtree,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='foo'),
assertionValue=pureldap.LDAPAssertionValue(value='a')),
attributes=['bar']))
self.failUnlessEqual(seen,
[
ldapsyntax.LDAPEntry(
client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'bar': ['b', 'c'],
}),
ldapsyntax.LDAPEntry(
client=client,
dn='cn=bar,dc=example,dc=com',
attributes={
'bar': ['b', 'c'],
})])
d.addCallback(cb)
return d
def testSearch_fail(self):
client=LDAPClientTestDriver([
pureldap.LDAPSearchResultDone(
resultCode=ldaperrors.LDAPBusy.resultCode,
matchedDN='',
errorMessage='Go away')
])
o=ldapsyntax.LDAPEntry(client=client, dn='dc=example,dc=com')
d=o.search(filterText='(foo=a)')
def eb(fail):
fail.trap(ldaperrors.LDAPBusy)
self.assertEquals(fail.value.message, 'Go away')
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_wholeSubtree,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='foo'),
assertionValue=pureldap.LDAPAssertionValue(value='a')),
))
d.addCallbacks(testutil.mustRaise, eb)
return d
class LDAPSyntaxDNs(unittest.TestCase):
def testDNKeyExistenceSuccess(self):
client = LDAPClientTestDriver()
ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'cn': ['foo'],
})
def TODOtestDNKeyExistenceFailure(self):
client = LDAPClientTestDriver()
self.failUnlessRaises(ldapsyntax.DNNotPresentError,
ldapsyntax.LDAPEntry,
client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'foo': ['bar'],
})
class LDAPSyntaxLDIF(unittest.TestCase):
def testLDIFConversion(self):
client = LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a', 'b'],
'bValue': ['c'],
})
self.failUnlessEqual(str(o),
'\n'.join((
"dn: cn=foo,dc=example,dc=com",
"objectClass: a",
"objectClass: b",
"aValue: a",
"aValue: b",
"bValue: c",
"\n")))
class LDAPSyntaxDelete(unittest.TestCase):
def testDeleteInvalidates(self):
"""Deleting an LDAPEntry invalidates it."""
client = LDAPClientTestDriver(
[pureldap.LDAPDelResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a'],
})
d=o.delete()
def cb(dummy):
self.failUnlessRaises(
ldapsyntax.ObjectDeletedError,
o.search,
filterText='(foo=a)')
self.failUnlessRaises(
ldapsyntax.ObjectDeletedError,
o.get,
'objectClass')
d.addCallback(cb)
return d
def testDeleteOnWire(self):
"""LDAPEntry.delete should write the right data to the server."""
client = LDAPClientTestDriver(
[pureldap.LDAPDelResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a'],
})
d=o.delete()
def cb(dummy):
client.assertSent(pureldap.LDAPDelRequest(
entry='cn=foo,dc=example,dc=com',
))
d.addCallback(cb)
return d
def testErrorHandling(self):
"""LDAPEntry.delete should pass LDAP errors to it's deferred."""
client = LDAPClientTestDriver(
[pureldap.LDAPDelResponse(resultCode=ldaperrors.LDAPBusy.resultCode,
matchedDN='',
errorMessage='Go away'),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a'],
})
d=o.delete()
def eb(fail):
fail.trap(ldaperrors.LDAPBusy)
self.assertEquals(fail.value.message, 'Go away')
client.assertSent(pureldap.LDAPDelRequest(
entry='cn=foo,dc=example,dc=com',
))
d.addCallbacks(testutil.mustRaise, eb)
return d
def testErrorHandling_extended(self):
"""LDAPEntry.delete should pass even non-LDAPDelResponse errors to it's deferred."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=ldaperrors.LDAPProtocolError.resultCode,
responseName='1.3.6.1.4.1.1466.20036',
errorMessage='Unknown request')
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a'],
})
d=o.delete()
def eb(fail):
fail.trap(ldaperrors.LDAPProtocolError)
self.assertEquals(fail.value.message, 'Unknown request')
client.assertSent(pureldap.LDAPDelRequest(
entry='cn=foo,dc=example,dc=com',
))
d.addCallbacks(testutil.mustRaise, eb)
return d
class LDAPSyntaxAddChild(unittest.TestCase):
def testAddChildOnWire(self):
"""LDAPEntry.addChild should write the right data to the server."""
client = LDAPClientTestDriver(
[pureldap.LDAPAddResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='ou=things,dc=example,dc=com',
attributes={
'objectClass': ['organizationalUnit'],
'ou': ['things'],
})
d=o.addChild(
rdn='givenName=Firstname+surname=Lastname',
attributes={'objectClass': ['person', 'otherStuff'],
'givenName': ['Firstname'],
'surname': ['Lastname'],
})
def cb(dummy):
client.assertSent(pureldap.LDAPAddRequest(
entry='givenName=Firstname+surname=Lastname,ou=things,dc=example,dc=com',
attributes=[ (pureldap.LDAPAttributeDescription('objectClass'),
pureber.BERSet([pureldap.LDAPAttributeValue('person'),
pureldap.LDAPAttributeValue('otherStuff'),
])),
(pureldap.LDAPAttributeDescription('givenName'),
pureber.BERSet([pureldap.LDAPAttributeValue('Firstname')])),
(pureldap.LDAPAttributeDescription('surname'),
pureber.BERSet([pureldap.LDAPAttributeValue('Lastname')])),
],
))
d.addCallback(cb)
return d
class LDAPSyntaxContainingNamingContext(unittest.TestCase):
def testNamingContext(self):
"""LDAPEntry.namingContext returns the naming context that contains this object (via a Deferred)."""
client=LDAPClientTestDriver(
[ pureldap.LDAPSearchResultEntry(
objectName='',
attributes=[('namingContexts',
('dc=foo,dc=example',
'dc=example,dc=com',
'dc=bar,dc=example',
))]),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage='')
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,ou=bar,dc=example,dc=com',
attributes={
'objectClass': ['a'],
})
d=o.namingContext()
def cb(p):
assert isinstance(p, ldapsyntax.LDAPEntry)
assert p.client == o.client
assert str(p.dn) == 'dc=example,dc=com'
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='',
scope=pureldap.LDAP_SCOPE_baseObject,
filter=pureldap.LDAPFilter_present('objectClass'),
attributes=['namingContexts'],
))
d.addCallback(cb)
return d
class LDAPSyntaxPasswords(unittest.TestCase):
def setUp(self):
cfg = config.loadConfig()
cfg.set('samba', 'use-lmhash', 'no')
def testPasswordSetting_ExtendedOperation(self):
"""LDAPEntry.setPassword_ExtendedOperation(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
d=o.setPassword_ExtendedOperation(newPasswd='new')
def cb(dummy):
client.assertSent(pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
)
d.addCallback(cb)
return d
def testPasswordSetting_Samba_sambaAccount(self):
"""LDAPEntry.setPassword_Samba(newPasswd=...,
style='sambaAccount') changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
d=o.setPassword_Samba(newPasswd='new', style='sambaAccount')
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('ntPassword',
['89963F5042E5041A59C249282387A622']),
delta.Replace('lmPassword',
['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']),
]).asLDAP())
d.addCallback(cb)
return d
def testPasswordSetting_Samba_sambaSamAccount(self):
"""LDAPEntry.setPassword_Samba(newPasswd=..., style='sambaSamAccount') changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
d=o.setPassword_Samba(newPasswd='new', style='sambaSamAccount')
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('sambaNTPassword',
['89963F5042E5041A59C249282387A622']),
delta.Replace('sambaLMPassword',
['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']),
]).asLDAP())
d.addCallback(cb)
return d
def testPasswordSetting_Samba_defaultStyle(self):
"""LDAPEntry.setPassword_Samba(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
d=o.setPassword_Samba(newPasswd='new')
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('sambaNTPassword',
['89963F5042E5041A59C249282387A622']),
delta.Replace('sambaLMPassword',
['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']),
]).asLDAP())
d.addCallback(cb)
return d
def testPasswordSetting_Samba_badStyle(self):
"""LDAPEntry.setPassword_Samba(..., style='foo') fails."""
client = LDAPClientTestDriver(
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
d=defer.maybeDeferred(o.setPassword_Samba, newPasswd='new', style='foo')
def eb(fail):
fail.trap(RuntimeError)
self.assertEquals(fail.getErrorMessage(),
"Unknown samba password style 'foo'")
client.assertNothingSent()
d.addCallbacks(testutil.mustRaise, eb)
return d
def testPasswordSettingAll_noSamba(self):
"""LDAPEntry.setPassword(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['foo'],
},
complete=1)
d=o.setPassword(newPasswd='new')
def cb(dummy):
client.assertSent(pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
)
d.addCallback(cb)
return d
def testPasswordSettingAll_hasSamba(self):
"""LDAPEntry.setPassword(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['foo', 'sambaAccount'],
},
complete=1)
d=o.setPassword(newPasswd='new')
def cb(dummy):
client.assertSent(pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('ntPassword',
['89963F5042E5041A59C249282387A622']),
delta.Replace('lmPassword',
['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']),
]).asLDAP())
d.addCallback(cb)
return d
def testPasswordSettingAll_hasSambaSam(self):
"""LDAPEntry.setPassword(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['foo', 'sambaSamAccount'],
},
complete=1)
d=o.setPassword(newPasswd='new')
def cb(dummy):
client.assertSent(pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('sambaNTPassword',
['89963F5042E5041A59C249282387A622']),
delta.Replace('sambaLMPassword',
['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']),
]).asLDAP())
d.addCallback(cb)
return d
def testPasswordSettingAll_hasSamba_differentCase(self):
"""LDAPEntry.setPassword(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['foo', 'saMBaAccOuNT'],
},
complete=1)
d=o.setPassword(newPasswd='new')
def cb(dummy):
client.assertSent(pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('ntPassword',
['89963F5042E5041A59C249282387A622']),
delta.Replace('lmPassword',
['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']),
]).asLDAP())
d.addCallback(cb)
return d
def testPasswordSettingAll_hasSambaSam_differentCase(self):
"""LDAPEntry.setPassword(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['foo', 'sAmbASAmaccoUnt'],
},
complete=1)
d=o.setPassword(newPasswd='new')
def cb(dummy):
client.assertSent(pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('sambaNTPassword',
['89963F5042E5041A59C249282387A622']),
delta.Replace('sambaLMPassword',
['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']),
]).asLDAP())
d.addCallback(cb)
return d
def testPasswordSettingAll_maybeSamba_WillFind(self):
"""LDAPEntry.setPassword(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
[
pureldap.LDAPSearchResultEntry(objectName='',
attributes=[('objectClass',
('foo',
'sambaAccount',
'bar'))]),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),
],
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client, dn='cn=foo,dc=example,dc=com')
d=o.setPassword(newPasswd='new')
def cb(dummy):
client.assertSent(
pureldap.LDAPPasswordModifyRequest(userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
pureldap.LDAPSearchRequest(baseObject='cn=foo,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilterMatchAll,
attributes=('objectClass',)),
delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('ntPassword', ['89963F5042E5041A59C249282387A622']),
delta.Replace('lmPassword', ['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX']),
]).asLDAP(),
)
d.addCallback(cb)
return d
def testPasswordSettingAll_maybeSamba_WillNotFind(self):
"""LDAPEntry.setPassword(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
[pureldap.LDAPSearchResultEntry(objectName='',
attributes=[('objectClass',
('foo',
'bar'))]),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),
],
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client, dn='cn=foo,dc=example,dc=com')
d=o.setPassword(newPasswd='new')
def cb(dummy):
client.assertSent(
pureldap.LDAPPasswordModifyRequest(userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
pureldap.LDAPSearchRequest(baseObject='cn=foo,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilterMatchAll,
attributes=('objectClass',)),
)
d.addCallback(cb)
return d
def testPasswordSettingAll_maybeSamba_WillNotFindAnything(self):
"""LDAPEntry.setPassword(newPasswd=...) changes the password."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=0,
matchedDN='',
errorMessage='')],
[
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),
],
[pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client, dn='cn=foo,dc=example,dc=com')
d=o.setPassword(newPasswd='new')
def checkError(fail):
fail.trap(ldapsyntax.PasswordSetAggregateError)
l=fail.value.errors
assert len(l)==1
assert len(l[0])==2
assert l[0][0]=='Samba'
assert isinstance(l[0][1], failure.Failure)
l[0][1].trap(ldapsyntax.DNNotPresentError)
return 'This test run should succeed'
def chainMustErrback(dummy):
raise 'Should never get here'
d.addCallbacks(callback=chainMustErrback, errback=checkError)
d.addCallback(self.assertEquals, 'This test run should succeed')
def cb(dummy):
client.assertSent(
pureldap.LDAPPasswordModifyRequest(userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
pureldap.LDAPSearchRequest(baseObject='cn=foo,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilterMatchAll,
attributes=('objectClass',)),
)
d.addCallback(cb)
return d
def testPasswordSetting_abortsOnFirstError(self):
"""LDAPEntry.setPassword() aborts on first error (does not parallelize, as it used to)."""
client = LDAPClientTestDriver(
[pureldap.LDAPExtendedResponse(resultCode=ldaperrors.LDAPInsufficientAccessRights.resultCode,
matchedDN='',
errorMessage='')],
)
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['foo', 'sambaAccount'],
},
complete=1)
d=o.setPassword(newPasswd='new')
def eb(fail):
fail.trap(ldapsyntax.PasswordSetAggregateError)
l=fail.value.errors
assert len(l)==2
assert len(l[0])==2
self.assertEquals(l[0][0], 'ExtendedOperation')
assert isinstance(l[0][1], failure.Failure)
l[0][1].trap(ldaperrors.LDAPInsufficientAccessRights)
assert len(l[1])==2
self.assertEquals(l[1][0], 'Samba')
assert isinstance(l[1][1], failure.Failure)
l[1][1].trap(ldapsyntax.PasswordSetAborted)
client.assertSent(pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=foo,dc=example,dc=com',
newPasswd='new'),
)
d.addCallbacks(testutil.mustRaise, eb)
return d
class LDAPSyntaxFetch(unittest.TestCase):
def testFetch_WithDirtyJournal(self):
"""Trying to fetch attributes with a dirty journal fails."""
client = LDAPClientTestDriver()
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
o['x']=['foo']
self.failUnlessRaises(
ldapsyntax.ObjectDirtyError,
o.fetch)
def testFetch_Empty(self):
"""Fetching attributes for a newly-created object works."""
client = LDAPClientTestDriver(
[ pureldap.LDAPSearchResultEntry(objectName='cn=foo,dc=example,dc=com',
attributes=(
('foo', ['a']),
('bar', ['b', 'c']),
)),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
d=o.fetch()
def cb(dummy):
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='cn=foo,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
))
has=o.keys()
has.sort()
want=['foo', 'bar']
want.sort()
self.assertEquals(has, want)
self.assertEquals(o['foo'], ['a'])
self.assertEquals(o['bar'], ['b', 'c'])
d.addCallback(cb)
return d
def testFetch_Prefilled(self):
"""Fetching attributes for a (partially) known object overwrites the old attributes."""
client = LDAPClientTestDriver(
[ pureldap.LDAPSearchResultEntry(objectName='cn=foo,dc=example,dc=com',
attributes=(
('foo', ['a']),
('bar', ['b', 'c']),
)),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'foo': ['x'],
'quux': ['baz', 'xyzzy']
})
d=o.fetch()
def cb(dummy):
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='cn=foo,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
))
has=o.keys()
has.sort()
want=['foo', 'bar']
want.sort()
self.assertEquals(has, want)
self.assertEquals(o['foo'], ['a'])
self.assertEquals(o['bar'], ['b', 'c'])
d.addCallback(cb)
return d
def testFetch_Partial(self):
"""Fetching only some of the attributes does not overwrite existing values of different attribute types."""
client = LDAPClientTestDriver(
[ pureldap.LDAPSearchResultEntry(objectName='cn=foo,dc=example,dc=com',
attributes=(
('foo', ['a']),
('bar', ['b', 'c']),
)),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'foo': ['x'],
'quux': ['baz', 'xyzzy']
})
d=o.fetch('foo', 'bar', 'thud')
def cb(dummy):
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='cn=foo,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
attributes=('foo', 'bar', 'thud'),
))
has=o.keys()
has.sort()
want=['foo', 'bar', 'quux']
want.sort()
self.assertEquals(has, want)
self.assertEquals(o['foo'], ['a'])
self.assertEquals(o['bar'], ['b', 'c'])
self.assertEquals(o['quux'], ['baz', 'xyzzy'])
d.addCallback(cb)
return d
def testCommitAndFetch(self):
"""Fetching after a commit works."""
client = LDAPClientTestDriver(
[ pureldap.LDAPModifyResponse(resultCode=0,
matchedDN='',
errorMessage='')
],
[ pureldap.LDAPSearchResultEntry('cn=foo,dc=example,dc=com',
[('aValue', ['foo', 'bar'])],
),
pureldap.LDAPSearchResultDone(resultCode=0),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
})
o['aValue']=['foo', 'bar']
d=o.commit()
d.addCallback(self.assertIdentical, o)
d.addCallback(lambda _: o.fetch('aValue'))
d.addCallback(self.assertIdentical, o)
def cb(dummy):
client.assertSent(delta.ModifyOp('cn=foo,dc=example,dc=com', [
delta.Replace('aValue', ['foo', 'bar']),
]).asLDAP(),
pureldap.LDAPSearchRequest(
baseObject='cn=foo,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
attributes=['aValue'],
))
d.addCallback(cb)
return d
class LDAPSyntaxRDNHandling(unittest.TestCase):
def testRemovingRDNFails(self):
"""Removing RDN fails with CannotRemoveRDNError."""
o=ldapsyntax.LDAPEntry(client=None, dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['someObjectClass'],
'cn': ['foo', 'bar', 'baz'],
'a': ['aValue'],
})
o['cn'].remove('bar')
del o['a']
self.assertRaises(ldapsyntax.CannotRemoveRDNError,
o['cn'].remove,
'foo')
def f():
del o['cn']
self.assertRaises(ldapsyntax.CannotRemoveRDNError,
f)
def f():
o['cn']=['thud']
self.assertRaises(ldapsyntax.CannotRemoveRDNError,
f)
# TODO maybe this should be ok, it preserves the RDN.
# For now, disallow it.
def f():
o['cn']=['foo']
self.assertRaises(ldapsyntax.CannotRemoveRDNError,
f)
class LDAPSyntaxMove(unittest.TestCase):
def test_move(self):
client = LDAPClientTestDriver(
[ pureldap.LDAPModifyDNResponse(resultCode=0,
matchedDN='',
errorMessage=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'cn': ['foo'],
'aValue': ['a'],
})
d = o.move('cn=bar,ou=somewhere,dc=example,dc=com')
def cb(dummy):
client.assertSent(pureldap.LDAPModifyDNRequest(
entry='cn=foo,dc=example,dc=com',
newrdn='cn=bar',
deleteoldrdn=1,
newSuperior='ou=somewhere,dc=example,dc=com',
))
self.assertEquals(o.dn, 'cn=bar,ou=somewhere,dc=example,dc=com')
d.addCallback(cb)
return d
class Bind(unittest.TestCase):
def test_ok(self):
client = LDAPClientTestDriver(
[ pureldap.LDAPBindResponse(resultCode=0,
matchedDN=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
d = defer.maybeDeferred(o.bind, 's3krit')
d.addCallback(self.assertIdentical, o)
def cb(dummy):
client.assertSent(pureldap.LDAPBindRequest(
dn='cn=foo,dc=example,dc=com',
auth='s3krit'))
d.addCallback(cb)
return d
def test_fail(self):
client = LDAPClientTestDriver(
[ pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPInvalidCredentials.resultCode,
matchedDN=''),
])
o=ldapsyntax.LDAPEntry(client=client,
dn='cn=foo,dc=example,dc=com')
d = defer.maybeDeferred(o.bind, 's3krit')
def eb(fail):
fail.trap(ldaperrors.LDAPInvalidCredentials)
d.addCallbacks(testutil.mustRaise, eb)
return d
ldaptor-0.0.43/ldaptor/test/mockweb.py 0000644 0001750 0001750 00000005251 10344407651 016001 0 ustar jan jan """I mock the web."""
from nevow import url
from twisted.internet import address
from twisted.web import client
from nevow import testutil
from ldaptor.test import util
class FakeChannel(testutil.FakeChannel):
def requestDone(self, request):
self.transport.loseConnection()
class MyHTTPPageGetter(client.HTTPPageGetter):
def handleStatus_301(self):
if not self.followRedirect:
client.HTTPPageGetter.handleStatus_301(self)
return
l = self.headers.get('location')
if not l:
self.handleStatusDefault()
url = l[0]
self.factory.setURL(url)
_getPage_connect(clientFactory=self.factory,
serverAddress=address.IPv4Address(
'TCP', self.factory.host, self.factory.port),
clientAddress=None)
self.quietLoss = 1
self.transport.loseConnection()
class HTTPClientFactory_noCookies(client.HTTPClientFactory):
def gotHeaders(self, headers):
client.HTTPClientFactory.gotHeaders(self, headers)
self.cookies.clear()
def _getPage_connect(clientFactory,
serverAddress,
clientAddress):
clientProto = clientFactory.buildProtocol(serverAddress)
serverProto = clientFactory.site.buildProtocol(clientAddress)
pump = util.returnConnected(serverProto, clientProto,
serverAddress=serverAddress,
clientAddress=clientAddress)
def getPage(site, u, extraInfo=False,
factoryClass=client.HTTPClientFactory,
*a, **kw):
u = url.URL.fromString(str(u))
clientFactory = factoryClass(str(u), *a, **kw)
clientFactory.protocol = MyHTTPPageGetter
clientFactory.site = site
if ':' in u.netloc:
host, port = u.netloc.split(':', 1)
else:
host, port = u.netloc, 80
serverAddress = address.IPv4Address('TCP', host, port)
clientAddress = address.IPv4Address('TCP', 'localhost', 1024)
_getPage_connect(clientFactory, serverAddress, clientAddress)
if extraInfo:
def _cb(page):
return {'status': clientFactory.status,
'version': clientFactory.version,
'message': clientFactory.message,
'headers': clientFactory.headers,
'page': page,
'url': url.URL.fromString(clientFactory.url),
}
clientFactory.deferred.addCallback(_cb)
return clientFactory.deferred
def getPage_noCookies(*a, **kw):
defaults = {
'factoryClass': HTTPClientFactory_noCookies,
}
defaults.update(kw)
return getPage(*a, **defaults)
ldaptor-0.0.43/ldaptor/test/test_autofill.py 0000644 0001750 0001750 00000003134 10345261504 017222 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.autofill module.
"""
from twisted.trial import unittest
from ldaptor.protocols.ldap import ldapsyntax
from ldaptor.testutil import LDAPClientTestDriver
class Autofill_sum: #TODO baseclass
def __init__(self, resultAttr, sumAttrs):
self.resultAttr = resultAttr
self.sumAttrs = sumAttrs
def start(self, ldapObject):
pass
def notify(self, ldapObject, attributeType):
if attributeType not in self.sumAttrs:
return
sum = 0
for sumAttr in self.sumAttrs:
if sumAttr not in ldapObject:
continue
for val in ldapObject[sumAttr]:
val = int(val)
sum += val
sum = str(sum)
ldapObject[self.resultAttr] = [sum]
class LDAPAutoFill_Simple(unittest.TestCase):
def testSimpleSum(self):
"""A simple autofiller that calculates sums of attributes should work.."""
client = LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['some', 'other'],
})
d = o.addAutofiller(Autofill_sum(resultAttr='sum',
sumAttrs=['a', 'b']))
def cb(dummy):
client.assertNothingSent()
o['a'] = ['1']
o['b'] = ['2', '3']
self.failUnless('sum' in o)
self.failUnlessEqual(o['sum'], ['6'])
d.addCallback(cb)
return d
ldaptor-0.0.43/ldaptor/test/test_ldapclient.py 0000644 0001750 0001750 00000002103 10345261504 017515 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.ldapsyntax module.
"""
from twisted.trial import unittest
from twisted.test import proto_helpers
from twisted.internet import defer
from ldaptor.protocols.ldap import ldapclient
from ldaptor import testutil
class SillyMessage(object):
needs_answer = True
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
class SillyError(Exception):
def __str__(self):
'Exception for test purposes.'
class ConnectionLost(unittest.TestCase):
def test_simple(self):
c = ldapclient.LDAPClient()
c.makeConnection(proto_helpers.StringTransport())
d1 = c.send(SillyMessage('foo'))
d2 = c.send(SillyMessage('bar'))
c.connectionLost(SillyError())
def eb(fail):
fail.trap(SillyError)
d1.addCallbacks(testutil.mustRaise, eb)
d2.addCallbacks(testutil.mustRaise, eb)
d = defer.DeferredList([d1, d2])
return defer.DeferredList([d1, d2],
fireOnOneErrback=True)
ldaptor-0.0.43/ldaptor/test/test_autofill_posix.py 0000644 0001750 0001750 00000016537 10345261504 020457 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.autofill.posixAccount module.
"""
from twisted.trial import unittest
from ldaptor.protocols.ldap import ldapsyntax, autofill
from ldaptor.protocols import pureldap
from ldaptor.protocols.ldap.autofill import posixAccount
from ldaptor.testutil import LDAPClientTestDriver
class LDAPAutoFill_Posix(unittest.TestCase):
def testMustHaveObjectClass(self):
"""Test that Autofill_posix fails unless object is a posixAccount."""
client = LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['something', 'other'],
})
autoFiller = posixAccount.Autofill_posix(baseDN='dc=example,dc=com')
d = o.addAutofiller(autoFiller)
def _cbMustRaise(_):
raise unittest.FailTest('Should have raised an exception')
def _eb(fail):
client.assertNothingSent()
fail.trap(autofill.ObjectMissingObjectClassException)
return None
d.addCallbacks(_cbMustRaise,
_eb)
return d
def testDefaultSetting(self):
"""Test that fields get their default values."""
client = LDAPClientTestDriver(
# uid==1000 -> free
[ pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1000 -> taken
[ pureldap.LDAPSearchResultEntry(objectName='',
attributes=[('objectClass',
('foo',
'posixAccount',
'bar'))]),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1500 -> free
[ pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1250 -> free
[ pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1125 -> free
[ pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1062 -> free
[ pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1031 -> free
[ pureldap.LDAPSearchResultEntry(objectName='',
attributes=[('objectClass',
('foo',
'posixAccount',
'bar'))]),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1046 -> free
[ pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1038 -> taken
[ pureldap.LDAPSearchResultEntry(objectName='',
attributes=[('objectClass',
('foo',
'posixAccount',
'bar'))]),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1042 -> free
[ pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1040 -> taken
[ pureldap.LDAPSearchResultEntry(objectName='',
attributes=[('objectClass',
('foo',
'posixAccount',
'bar'))]),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
# gid==1041 -> taken
[ pureldap.LDAPSearchResultEntry(objectName='',
attributes=[('objectClass',
('foo',
'posixAccount',
'bar'))]),
pureldap.LDAPSearchResultDone(resultCode=0,
matchedDN='',
errorMessage=''),],
)
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['posixAccount', 'other'],
})
d = o.addAutofiller(posixAccount.Autofill_posix(baseDN='dc=example,dc=com'))
d.addCallback(self._cb_testDefaultSetting, client, o)
return d
def _cb_testDefaultSetting(self, val, client, o):
client.assertSent(
*[
pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com', scope=2,
derefAliases=0, sizeLimit=1, timeLimit=0, typesOnly=0,
filter=pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription(value='uidNumber'),
assertionValue=pureldap.LDAPAssertionValue(value='1000')),
attributes=()),
] + [
pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com', scope=2,
derefAliases=0, sizeLimit=1, timeLimit=0, typesOnly=0,
filter=pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription(value='gidNumber'),
assertionValue=pureldap.LDAPAssertionValue(value=str(x))),
attributes=())
for x in (1000, 1500, 1250, 1125, 1062, 1031, 1046, 1038, 1042, 1040, 1041)])
self.failUnless('loginShell' in o)
self.failUnlessEqual(o['loginShell'], ['/bin/sh'])
self.failUnless('uidNumber' in o)
self.failUnlessEqual(o['uidNumber'], ['1000'])
self.failUnless('gidNumber' in o)
self.failUnlessEqual(o['gidNumber'], ['1042'])
ldaptor-0.0.43/ldaptor/test/test_ldifprotocol.py 0000644 0001750 0001750 00000033201 10344535643 020110 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.ldif module.
"""
from twisted.trial import unittest
import sets
from ldaptor.protocols.ldap import ldifprotocol, distinguishedname
class LDIFDriver(ldifprotocol.LDIF):
def __init__(self):
self.listOfCompleted = []
def gotEntry(self, obj):
self.listOfCompleted.append(obj)
class TestLDIFParsing(unittest.TestCase):
def testFromLDIF(self):
proto = LDIFDriver()
for line in (
"dn: cn=foo,dc=example,dc=com",
"objectClass: a",
"objectClass: b",
"aValue: a",
"aValue: b",
"bValue: c",
"",
"dn: cn=bar,dc=example,dc=com",
"objectClass: c",
"aValue:: IEZPTyE=",
"aValue: b",
"bValue: C",
"",
):
proto.lineReceived(line)
self.failUnlessEqual(len(proto.listOfCompleted), 2)
o = proto.listOfCompleted.pop(0)
self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
self.failUnlessEqual(o['objectClass'], ['a', 'b'])
self.failUnlessEqual(o['aValue'], ['a', 'b'])
self.failUnlessEqual(o['bValue'], ['c'])
o = proto.listOfCompleted.pop(0)
self.failUnlessEqual(str(o.dn), 'cn=bar,dc=example,dc=com')
self.failUnlessEqual(o['objectClass'], ['c'])
self.failUnlessEqual(o['aValue'], [' FOO!', 'b'])
self.failUnlessEqual(o['bValue'], ['C'])
self.failUnlessEqual(proto.listOfCompleted, [])
def testSplitLines(self):
proto = LDIFDriver()
for line in (
"dn: cn=foo,dc=ex",
" ample,dc=com",
"objectClass: a",
"ob",
" jectClass: b",
"",
):
proto.lineReceived(line)
self.failUnlessEqual(len(proto.listOfCompleted), 1)
o = proto.listOfCompleted.pop(0)
self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
self.failUnlessEqual(o['objectClass'], ['a', 'b'])
self.failUnlessEqual(proto.listOfCompleted, [])
def testCaseInsensitiveAttributeTypes(self):
proto = LDIFDriver()
proto.dataReceived("""\
dn: cn=foo,dc=example,dc=com
objectClass: a
obJeCtClass: b
cn: foo
avalue: a
aValUe: b
""")
self.failUnlessEqual(len(proto.listOfCompleted), 1)
o = proto.listOfCompleted.pop(0)
self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
self.failUnlessEqual(o['objectClass'], ['a', 'b'])
self.failUnlessEqual(o['CN'], ['foo'])
self.failUnlessEqual(o['aValue'], ['a', 'b'])
self.failUnlessEqual(proto.listOfCompleted, [])
def testVersion1(self):
proto = LDIFDriver()
proto.dataReceived("""\
version: 1
dn: cn=foo,dc=example,dc=com
objectClass: a
objectClass: b
aValue: a
aValue: b
bValue: c
""")
self.failUnlessEqual(len(proto.listOfCompleted), 1)
o = proto.listOfCompleted.pop(0)
self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
self.failUnlessEqual(o['objectClass'], ['a', 'b'])
self.failUnlessEqual(o['aValue'], ['a', 'b'])
self.failUnlessEqual(o['bValue'], ['c'])
def testVersionInvalid(self):
proto = LDIFDriver()
self.assertRaises(ldifprotocol.LDIFVersionNotANumberError,
proto.dataReceived,
"""\
version: junk
dn: cn=foo,dc=example,dc=com
objectClass: a
objectClass: b
aValue: a
aValue: b
bValue: c
""")
def testVersion2(self):
proto = LDIFDriver()
self.assertRaises(ldifprotocol.LDIFUnsupportedVersionError,
proto.dataReceived,
"""\
version: 2
dn: cn=foo,dc=example,dc=com
objectClass: a
objectClass: b
aValue: a
aValue: b
bValue: c
""")
def testNoSpaces(self):
proto = LDIFDriver()
proto.dataReceived("""\
dn:cn=foo,dc=example,dc=com
objectClass:a
obJeCtClass:b
cn:foo
avalue:a
aValUe:b
""")
self.failUnlessEqual(len(proto.listOfCompleted), 1)
o = proto.listOfCompleted.pop(0)
self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
self.failUnlessEqual(o['objectClass'], ['a', 'b'])
self.failUnlessEqual(o['CN'], ['foo'])
self.failUnlessEqual(o['aValue'], ['a', 'b'])
self.failUnlessEqual(proto.listOfCompleted, [])
def testTruncatedFailure(self):
proto = LDIFDriver()
proto.dataReceived("""\
version: 1
dn: cn=foo,dc=example,dc=com
objectClass: a
objectClass: b
aValue: a
aValue: b
bValue: c
""")
self.failUnlessEqual(len(proto.listOfCompleted), 0)
self.assertRaises(ldifprotocol.LDIFTruncatedError,
proto.connectionLost)
class RFC2849_Examples(unittest.TestCase):
examples = [
( """Example 1: An simple LDAP file with two entries""",
"""\
version: 1
dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Barbara Jensen
cn: Barbara J Jensen
cn: Babs Jensen
sn: Jensen
uid: bjensen
telephonenumber: +1 408 555 1212
description: A big sailing fan.
dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Bjorn Jensen
sn: Jensen
telephonenumber: +1 408 555 1212
""",
[ ( 'cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com',
{ 'objectClass': ['top', 'person', 'organizationalPerson'],
'cn': ['Barbara Jensen',
'Barbara J Jensen',
'Babs Jensen'],
'sn': ['Jensen'],
'uid': ['bjensen'],
'telephonenumber': ['+1 408 555 1212'],
'description': ['A big sailing fan.'],
}),
( 'cn=Bjorn Jensen,ou=Accounting,dc=airius,dc=com',
{ 'objectClass': ['top', 'person', 'organizationalPerson'],
'cn': ['Bjorn Jensen'],
'sn': ['Jensen'],
'telephonenumber': ['+1 408 555 1212'],
}),
]),
( """Example 2: A file containing an entry with a folded attribute value""",
"""\
version: 1
dn:cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass:top
objectclass:person
objectclass:organizationalPerson
cn:Barbara Jensen
cn:Barbara J Jensen
cn:Babs Jensen
sn:Jensen
uid:bjensen
telephonenumber:+1 408 555 1212
description:Babs is a big sailing fan, and travels extensively in sea
rch of perfect sailing conditions.
title:Product Manager, Rod and Reel Division
""",
[ ( 'cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com',
{ 'objectclass': ['top', 'person', 'organizationalPerson'],
'cn': ['Barbara Jensen', 'Barbara J Jensen', 'Babs Jensen'],
'sn': ['Jensen'],
'uid': ['bjensen'],
'telephonenumber': ['+1 408 555 1212'],
'description': ['Babs is a big sailing fan, and travels extensively in search of perfect sailing conditions.'],
'title': ['Product Manager, Rod and Reel Division'],
}),
]),
( """Example 3: A file containing a base-64-encoded value""",
"""\
version: 1
dn: cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Gern Jensen
cn: Gern O Jensen
sn: Jensen
uid: gernj
telephonenumber: +1 408 555 1212
description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVlIGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdGVyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQgb3V0IG1vcmUu
""",
[ ( 'cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com',
{ 'objectclass': ['top', 'person', 'organizationalPerson'],
'cn': ['Gern Jensen', 'Gern O Jensen'],
'sn': ['Jensen'],
'uid': ['gernj'],
'telephonenumber': ['+1 408 555 1212'],
'description': ['What a careful reader you are! This value is base-64-encoded because it has a control character in it (a CR).\r By the way, you should really get out more.'],
}),
]),
]
def testExamples(self):
for name, data, expected in self.examples:
proto = LDIFDriver()
proto.dataReceived(data)
self.failUnlessEqual(len(proto.listOfCompleted), len(expected))
for dn, attr in expected:
o = proto.listOfCompleted.pop(0)
self.failUnlessEqual(o.dn, distinguishedname.DistinguishedName(dn))
got = sets.Set([x.lower() for x in o.keys()])
want = sets.Set([x.lower() for x in attr.keys()])
self.failUnlessEqual(got, want)
for k, v in attr.items():
self.failUnlessEqual(o[k], v)
self.failUnlessEqual(proto.listOfCompleted, [])
"""
TODO more tests from RFC2849:
Example 4: A file containing an entries with UTF-8-encoded attribute
values, including language tags. Comments indicate the contents
of UTF-8-encoded attributes and distinguished names.
version: 1
dn:: b3U95Za25qWt6YOoLG89QWlyaXVz
# dn:: ou=,o=Airius
objectclass: top
objectclass: organizationalUnit
ou:: 5Za25qWt6YOo
# ou::
ou;lang-ja:: 5Za25qWt6YOo
# ou;lang-ja::
ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2
# ou;lang-ja::
ou;lang-en: Sales
description: Japanese office
dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
# dn:: uid=,ou=,o=Airius
userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: rogasawara
mail: rogasawara@airius.co.jp
givenname;lang-ja:: 44Ot44OJ44OL44O8
# givenname;lang-ja::
sn;lang-ja:: 5bCP56yg5Y6f
# sn;lang-ja::
cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
# cn;lang-ja::
title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
# title;lang-ja::
preferredlanguage: ja
givenname:: 44Ot44OJ44OL44O8
# givenname::
sn:: 5bCP56yg5Y6f
# sn::
cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
# cn::
title:: 5Za25qWt6YOoIOmDqOmVtw==
# title::
givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
# givenname;lang-ja;phonetic::
sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
# sn;lang-ja;phonetic::
cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
# cn;lang-ja;phonetic::
title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
# title;lang-ja;phonetic::
#
givenname;lang-en: Rodney
sn;lang-en: Ogasawara
cn;lang-en: Rodney Ogasawara
title;lang-en: Sales, Director
"""
"""
Example 5: A file containing a reference to an external file
version: 1
dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Horatio Jensen
cn: Horatio N Jensen
sn: Jensen
uid: hjensen
telephonenumber: +1 408 555 1212
jpegphoto:< file:///usr/local/directory/photos/hjensen.jpg
"""
"""
Example 6: A file containing a series of change records and comments
version: 1
# Add a new entry
dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
changetype: add
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Fiona Jensen
sn: Jensen
uid: fiona
telephonenumber: +1 408 555 1212
jpegphoto:< file:///usr/local/directory/photos/fiona.jpg
# Delete an existing entry
dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com
changetype: delete
# Modify an entry's relative distinguished name
dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
changetype: modrdn
newrdn: cn=Paula Jensen
deleteoldrdn: 1
# Rename an entry and move all of its children to a new location in
# the directory tree (only implemented by LDAPv3 servers).
dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
changetype: modrdn
newrdn: ou=Product Development Accountants
deleteoldrdn: 0
newsuperior: ou=Accounting, dc=airius, dc=com
# Modify an entry: add an additional value to the postaladdress
# attribute, completely delete the description attribute, replace
# the telephonenumber attribute with two values, and delete a specific
# value from the facsimiletelephonenumber attribute
dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com
changetype: modify
add: postaladdress
postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
-
delete: description
-
replace: telephonenumber
telephonenumber: +1 408 555 1234
telephonenumber: +1 408 555 5678
-
delete: facsimiletelephonenumber
facsimiletelephonenumber: +1 408 555 9876
-
# Modify an entry: replace the postaladdress attribute with an empty
# set of values (which will cause the attribute to be removed), and
# delete the entire description attribute. Note that the first will
# always succeed, while the second will only succeed if at least
# one value for the description attribute is present.
dn: cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com
changetype: modify
replace: postaladdress
-
delete: description
-
"""
"""
Example 7: An LDIF file containing a change record with a control
version: 1
# Delete an entry. The operation will attach the LDAPv3
# Tree Delete Control defined in [9]. The criticality
# field is "true" and the controlValue field is
# absent, as required by [9].
dn: ou=Product Development, dc=airius, dc=com
control: 1.2.840.113556.1.4.805 true
changetype: delete
"""
ldaptor-0.0.43/ldaptor/test/test_dns.py 0000644 0001750 0001750 00000005463 10160267335 016201 0 ustar jan jan """
Test cases for ldaptor.dns
"""
from twisted.trial import unittest
from ldaptor import dns
class NetmaskToNumbits(unittest.TestCase):
def test_classA(self):
self.assertEquals(dns.netmaskToNumbits('255.0.0.0'), 8)
def test_classB(self):
self.assertEquals(dns.netmaskToNumbits('255.255.0.0'), 16)
def test_classC(self):
self.assertEquals(dns.netmaskToNumbits('255.255.255.0'), 24)
def test_host(self):
self.assertEquals(dns.netmaskToNumbits('255.255.255.255'), 32)
def test_numbits(self):
for i in range(0, 33):
self.assertEquals(dns.netmaskToNumbits(str(i)), i)
def test_CIDR(self):
for i in range(0, 33):
mask = dns.ntoa(dns.aton(i))
self.assertEquals(dns.netmaskToNumbits(mask), i)
class PtrSoaName(unittest.TestCase):
def test_classA(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '255.0.0.0'),
'1.in-addr.arpa.')
self.assertEquals(dns.ptrSoaName('1.2.3.4', '8'),
'1.in-addr.arpa.')
def test_classB(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '255.255.0.0'),
'2.1.in-addr.arpa.')
self.assertEquals(dns.ptrSoaName('1.2.3.4', '16'),
'2.1.in-addr.arpa.')
def test_classC(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '255.255.255.0'),
'3.2.1.in-addr.arpa.')
self.assertEquals(dns.ptrSoaName('1.2.3.4', '24'),
'3.2.1.in-addr.arpa.')
def test_CIDR_9(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '9'),
'0/9.1.in-addr.arpa.')
self.assertEquals(dns.ptrSoaName('1.200.3.4', '9'),
'128/9.1.in-addr.arpa.')
def test_CIDR_12(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '12'),
'0/12.1.in-addr.arpa.')
self.assertEquals(dns.ptrSoaName('1.200.3.4', '12'),
'192/12.1.in-addr.arpa.')
def test_CIDR_13(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '13'),
'0/13.1.in-addr.arpa.')
self.assertEquals(dns.ptrSoaName('1.200.3.4', '13'),
'200/13.1.in-addr.arpa.')
def test_CIDR_15(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '15'),
'2/15.1.in-addr.arpa.')
self.assertEquals(dns.ptrSoaName('1.200.3.4', '15'),
'200/15.1.in-addr.arpa.')
def test_CIDR_29(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '29'),
'0/29.3.2.1.in-addr.arpa.')
def test_CIDR_30(self):
self.assertEquals(dns.ptrSoaName('1.2.3.4', '30'),
'4/30.3.2.1.in-addr.arpa.')
ldaptor-0.0.43/ldaptor/test/test_ldapfilter.py 0000644 0001750 0001750 00000053711 10344535643 017546 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.ldapfilter module.
"""
from twisted.trial import unittest
from ldaptor.protocols import pureldap
from ldaptor import ldapfilter
import types
def s(*l):
"""Join all members of list to a string. Integer members are chr()ed"""
r=''
for e in l:
if isinstance(e, types.IntType):
e=chr(e)
r=r+str(e)
return r
def l(s):
"""Split a string to ord's of chars."""
return map(lambda x: ord(x), s)
class RFC2254Examples(unittest.TestCase):
def test_cn(self):
text = '(cn=Babs Jensen)'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='Babs Jensen'))
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_not_cn(self):
text = '(!(cn=Tim Howes))'
filt = pureldap.LDAPFilter_not(
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='Tim Howes')))
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_and_or(self):
text = '(&(objectClass=Person)(|(sn=Jensen)(cn=Babs J*)))'
filt = pureldap.LDAPFilter_and(
[ pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='objectClass'),
assertionValue=pureldap.LDAPAssertionValue(value='Person')),
pureldap.LDAPFilter_or([ pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='sn'),
assertionValue=pureldap.LDAPAssertionValue(value='Jensen')),
pureldap.LDAPFilter_substrings(
type='cn',
substrings=[ pureldap.LDAPFilter_substrings_initial(value='Babs J')
])
]),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_substrings(self):
text = '(o=univ*of*mich*)'
filt = pureldap.LDAPFilter_substrings(
type='o',
substrings=[ pureldap.LDAPFilter_substrings_initial(value='univ'),
pureldap.LDAPFilter_substrings_any(value='of'),
pureldap.LDAPFilter_substrings_any(value='mich'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_extensible_1(self):
text = '(cn:1.2.3.4.5:=Fred Flintstone)'
self.assertEquals(ldapfilter.parseFilter(text),
pureldap.LDAPFilter_extensibleMatch(
type='cn',
dnAttributes=False,
matchingRule='1.2.3.4.5',
matchValue='Fred Flintstone',
))
def test_extensible_2(self):
text = '(sn:dn:2.4.6.8.10:=Barney Rubble)'
self.assertEquals(ldapfilter.parseFilter(text),
pureldap.LDAPFilter_extensibleMatch(
type='sn',
dnAttributes=True,
matchingRule='2.4.6.8.10',
matchValue='Barney Rubble',
))
def test_extensible_3(self):
text = '(o:dn:=Ace Industry)'
self.assertEquals(ldapfilter.parseFilter(text),
pureldap.LDAPFilter_extensibleMatch(
type='o',
dnAttributes=True,
matchingRule=None,
matchValue='Ace Industry',
))
def test_extensible_4(self):
text = '(:dn:2.4.6.8.10:=Dino)'
self.assertEquals(ldapfilter.parseFilter(text),
pureldap.LDAPFilter_extensibleMatch(
type=None,
dnAttributes=True,
matchingRule='2.4.6.8.10',
matchValue='Dino',
))
def test_escape_parens(self):
text = r'(o=Parens R Us \28for all your parenthetical needs\29)'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='o'),
assertionValue=pureldap.LDAPAssertionValue(value='Parens R Us (for all your parenthetical needs)'))
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_escape_asterisk(self):
text = r'(cn=*\2A*)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[ pureldap.LDAPFilter_substrings_any(value='*'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text.lower())
def test_escape_backslash(self):
text = r'(filename=C:\5cMyFile)'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='filename'),
assertionValue=pureldap.LDAPAssertionValue(value=r'C:\MyFile'))
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_escape_binary(self):
text = r'(bin=\00\00\00\04)'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='bin'),
assertionValue=pureldap.LDAPAssertionValue(value='\00\00\00\04'))
self.assertEquals(ldapfilter.parseFilter(text), filt)
def test_escape_utf8(self):
text = r'(sn=Lu\c4\8di\c4\87)'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='sn'),
assertionValue=pureldap.LDAPAssertionValue(value='Lu\xc4\x8di\xc4\x87'))
self.assertEquals(ldapfilter.parseFilter(text), filt)
#self.assertEquals(filt.asText(), text)
class TestValid(unittest.TestCase):
def test_item_present(self):
text = r'(cn=*)'
filt = pureldap.LDAPFilter_present(value='cn')
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_simple(self):
text = r'(cn=foo)'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo'))
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_init(self):
text = r'(cn=foo*)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_final(self):
text = r'(cn=*foo)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_final('foo'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_any(self):
text = r'(cn=*foo*)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_any('foo'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_aa(self):
text = r'(cn=*foo*bar*)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_any('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_ia(self):
text = r'(cn=foo*bar*)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_iaa(self):
text = r'(cn=foo*bar*baz*)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
pureldap.LDAPFilter_substrings_any('baz'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_if(self):
text = r'(cn=foo*bar)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_final('bar'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_iaf(self):
text = r'(cn=foo*bar*baz)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
pureldap.LDAPFilter_substrings_final('baz'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_iaaf(self):
text = r'(cn=foo*bar*baz*quux)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
pureldap.LDAPFilter_substrings_any('baz'),
pureldap.LDAPFilter_substrings_final('quux'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_af(self):
text = r'(cn=*foo*bar)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_any('foo'),
pureldap.LDAPFilter_substrings_final('bar'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_item_substring_aaf(self):
text = r'(cn=*foo*bar*baz)'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_any('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
pureldap.LDAPFilter_substrings_final('baz'),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_not_item(self):
text = r'(!(cn=foo))'
filt = pureldap.LDAPFilter_not(
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo')))
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_or_item(self):
text = r'(|(cn=foo)(cn=bar))'
filt = pureldap.LDAPFilter_or([
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo')),
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='bar')),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_and_item(self):
text = r'(&(cn=foo)(cn=bar))'
filt = pureldap.LDAPFilter_and([
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo')),
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='bar')),
])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_andornot(self):
text = r'(&(!(|(cn=foo)(cn=bar)))(sn=a*b*c*d))'
filt = pureldap.LDAPFilter_and([
pureldap.LDAPFilter_not(
pureldap.LDAPFilter_or([
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo')),
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='bar')),
])),
pureldap.LDAPFilter_substrings(
type='sn',
substrings=[pureldap.LDAPFilter_substrings_initial('a'),
pureldap.LDAPFilter_substrings_any('b'),
pureldap.LDAPFilter_substrings_any('c'),
pureldap.LDAPFilter_substrings_final('d'),
])])
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_whitespace_beforeCloseParen(self):
text = r'(cn=foo )'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo '))
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
def test_whitespace_afterEq(self):
text = r'(cn= foo)'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value=' foo'))
self.assertEquals(ldapfilter.parseFilter(text), filt)
self.assertEquals(filt.asText(), text)
class TestInvalid(unittest.TestCase):
def test_closeParen_1(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
'(&(|(mail=)@*)(uid=)))(mail=*))')
def test_closeParen_2(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
'(|(mail=)@*)(uid=)))')
def test_closeParen_3(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
'(mail=)@*)')
def test_closeParen_4(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
'(uid=))')
def test_openParen_1(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
'(&(|(mail=(@*)(uid=())(mail=*))')
def test_openParen_2(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
'(|(mail=(@*)(uid=())')
def test_openParen_3(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
'(mail=(@*)')
def test_openParen_4(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
'(uid=()')
def test_whitespace_leading(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
r' (cn=foo)')
def test_whitespace_trailing(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
r'(cn=foo) ')
def test_whitespace_afterOpenParen(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
r'( cn=foo)')
def test_whitespace_beforeEq(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
r'(cn =foo)')
class TestMaybeSubstring(unittest.TestCase):
def test_item_present(self):
text = r'*'
filt = pureldap.LDAPFilter_present(value='cn')
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_simple(self):
text = r'foo'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo'))
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_init(self):
text = r'foo*'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_final(self):
text = r'*foo'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_final('foo'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_any(self):
text = r'*foo*'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_any('foo'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_aa(self):
text = r'*foo*bar*'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_any('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_ia(self):
text = r'foo*bar*'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_iaa(self):
text = r'foo*bar*baz*'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
pureldap.LDAPFilter_substrings_any('baz'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_if(self):
text = r'foo*bar'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_final('bar'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_iaf(self):
text = r'foo*bar*baz'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
pureldap.LDAPFilter_substrings_final('baz'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_iaaf(self):
text = r'foo*bar*baz*quux'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
pureldap.LDAPFilter_substrings_any('baz'),
pureldap.LDAPFilter_substrings_final('quux'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_af(self):
text = r'*foo*bar'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_any('foo'),
pureldap.LDAPFilter_substrings_final('bar'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_item_substring_aaf(self):
text = r'*foo*bar*baz'
filt = pureldap.LDAPFilter_substrings(
type='cn',
substrings=[pureldap.LDAPFilter_substrings_any('foo'),
pureldap.LDAPFilter_substrings_any('bar'),
pureldap.LDAPFilter_substrings_final('baz'),
])
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
def test_escape_simple(self):
text = r'f\2aoo(bar'
filt = pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='f*oo(bar'))
self.assertEquals(ldapfilter.parseMaybeSubstring('cn', text), filt)
class TestWhitespace(unittest.TestCase):
def test_escape(self):
self.assertRaises(ldapfilter.InvalidLDAPFilter,
ldapfilter.parseFilter,
r'(cn=\ 61)')
ldaptor-0.0.43/ldaptor/test/test_entry_diff.py 0000644 0001750 0001750 00000014506 10344407651 017545 0 ustar jan jan """
Test cases for ldaptor.diff
"""
from twisted.trial import unittest
from ldaptor import delta, entry
class TestDiffEntry(unittest.TestCase):
def testEqual(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
})
result = a.diff(b)
self.assertEquals(result, None)
def testAdd_New_OneType_OneValue(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
'baz': ['quux'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('dc=foo',
[
delta.Add('baz', ['quux']),
]))
def testAdd_New_OneType_ManyValues(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
'baz': ['quux', 'thud', 'foo'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('dc=foo',
[
delta.Add('baz', ['quux', 'thud', 'foo']),
]))
def testAdd_New_ManyTypes(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
'baz': ['quux'],
'bang': ['thud'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('dc=foo',
[
delta.Add('bang', ['thud']),
delta.Add('baz', ['quux']),
]))
def testAdd_Existing_OneType_OneValue(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar', 'quux'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('dc=foo',
[
delta.Add('foo', ['quux']),
]))
def testAdd_Existing_OneType_ManyValues(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar', 'quux', 'thud', 'foo'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('dc=foo',
[
delta.Add('foo', ['quux', 'thud', 'foo']),
]))
def testAdd_NewAndExisting_ManyTypes(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
'baz': ['quux'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar', 'thud', 'bang'],
'baz': ['quux', 'bar', 'stump'],
'bang': ['thud', 'barble'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('dc=foo',
[
delta.Add('bang', ['thud', 'barble']),
delta.Add('baz', ['bar', 'stump']),
delta.Add('foo', ['thud', 'bang']),
]))
def testDelete_All_OneType(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
'baz': ['quux', 'thud'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('dc=foo',
[
delta.Delete('baz', ['quux', 'thud']),
]))
def testDelete_Some_OneType(self):
a = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
'baz': ['quux', 'thud'],
})
b = entry.BaseLDAPEntry(dn='dc=foo',
attributes={
'foo': ['bar'],
'baz': ['thud'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('dc=foo',
[
delta.Delete('baz', ['quux']),
]))
def testComplex(self):
a = entry.BaseLDAPEntry(dn='cn=Paula Jensen,ou=Product Development,dc=airius,dc=com',
attributes={
'description': ['Something'],
'telephonenumber': ['+123 456'],
'facsimiletelephonenumber': ['+1 408 555 9876'],
})
b = entry.BaseLDAPEntry(dn='cn=Paula Jensen,ou=Product Development,dc=airius,dc=com',
attributes={
'postalAddress': ['123 Anystreet $ Sunnyvale, CA $ 94086'],
'telephonenumber': ['+1 408 555 1234', '+1 408 555 5678'],
})
result = a.diff(b)
self.assertEquals(result,
delta.ModifyOp('cn=Paula Jensen,ou=Product Development,dc=airius,dc=com',
[
delta.Add('postalAddress', ['123 Anystreet $ Sunnyvale, CA $ 94086']),
delta.Delete('description', ['Something']),
delta.Delete('facsimiletelephonenumber', ['+1 408 555 9876']),
delta.Add('telephonenumber', ['+1 408 555 1234', '+1 408 555 5678']),
delta.Delete('telephonenumber', ['+123 456']),
]))
ldaptor-0.0.43/ldaptor/test/__init__.py 0000644 0001750 0001750 00000000036 07712743107 016111 0 ustar jan jan """Unit tests for Ldaptor."""
ldaptor-0.0.43/ldaptor/test/util.py 0000644 0001750 0001750 00000010517 10344535643 015333 0 ustar jan jan from twisted.python import failure
from twisted.internet import reactor, protocol, address, error
from twisted.test import testutils
from twisted.trial import unittest
from StringIO import StringIO
class FakeTransport(protocol.FileWrapper):
disconnecting = False
disconnect_done = False
def __init__(self, addr, peerAddr):
self.data = StringIO()
protocol.FileWrapper.__init__(self, self.data)
self.addr = addr
self.peerAddr = peerAddr
def getHost(self):
return self.addr
def getPeer(self):
return self.peerAddr
def loseConnection(self):
self.disconnecting = True
class FasterIOPump(testutils.IOPump):
def pump(self):
"""Move data back and forth.
Returns whether any data was moved.
"""
self.clientIO.seek(0)
self.serverIO.seek(0)
cData = self.clientIO.read()
sData = self.serverIO.read()
self.clientIO.seek(0)
self.serverIO.seek(0)
self.clientIO.truncate()
self.serverIO.truncate()
self.server.dataReceived(cData)
self.client.dataReceived(sData)
if cData or sData:
return 1
else:
return 0
class IOPump(FasterIOPump):
active = []
def __init__(self,
client, server,
clientTransport, serverTransport):
self.clientTransport = clientTransport
self.serverTransport = serverTransport
testutils.IOPump.__init__(self,
client=client,
server=server,
clientIO=clientTransport.data,
serverIO=serverTransport.data)
self.active.append(self)
def pump(self):
FasterIOPump.pump(self)
if (self.clientTransport.disconnecting
and not self.clientTransport.data.getvalue()
and not self.clientTransport.disconnect_done):
self.server.connectionLost(error.ConnectionDone)
self.clientTransport.disconnect_done = True
if (self.serverTransport.disconnecting
and not self.serverTransport.data.getvalue()
and not self.serverTransport.disconnect_done):
self.client.connectionLost(error.ConnectionDone)
self.serverTransport.disconnect_done = True
if (self.clientTransport.disconnect_done
and self.serverTransport.disconnect_done):
self.active.remove(self)
def __repr__(self):
return '<%s client=%r/%r server=%r/%r>' % (
self.__class__.__name__,
self.client,
self.clientIO.getvalue(),
self.server,
self.serverIO.getvalue(),
)
def returnConnected(server, client,
clientAddress=None,
serverAddress=None):
"""Take two Protocol instances and connect them.
"""
if serverAddress is None:
serverAddress = address.IPv4Address('TCP', 'localhost', 1)
if clientAddress is None:
clientAddress = address.IPv4Address('TCP', 'localhost', 2)
clientTransport = FakeTransport(clientAddress, serverAddress)
client.makeConnection(clientTransport)
serverTransport = FakeTransport(serverAddress, clientAddress)
server.makeConnection(serverTransport)
pump = IOPump(client, server,
clientTransport,
serverTransport)
# Challenge-response authentication:
pump.flush()
# Uh...
pump.flush()
return pump
def _append(result, lst):
lst.append(result)
def _getDeferredResult(d, timeout=None):
if timeout is not None:
d.setTimeout(timeout)
resultSet = []
d.addBoth(_append, resultSet)
while not resultSet:
for pump in IOPump.active:
pump.pump()
reactor.iterate()
return resultSet[0]
def pumpingDeferredResult(d, timeout=None):
result = _getDeferredResult(d, timeout)
if isinstance(result, failure.Failure):
if result.tb:
raise result.value.__class__, result.value, result.tb
raise result.value
else:
return result
def pumpingDeferredError(d, timeout=None):
result = _getDeferredResult(d, timeout)
if isinstance(result, failure.Failure):
return result
else:
raise unittest.FailTest, "Deferred did not fail: %r" % (result,)
ldaptor-0.0.43/ldaptor/test/test_svcbindproxy.py 0000644 0001750 0001750 00000062617 10344535643 020157 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.svcbindproxy module.
"""
from twisted.trial import unittest
from twisted.internet import reactor
from ldaptor.protocols.ldap import svcbindproxy, ldaperrors
from ldaptor.protocols import pureldap, pureber
from ldaptor import ldapfilter, testutil
class ServiceBindingProxy(unittest.TestCase):
berdecoder = pureldap.LDAPBERDecoderContext_TopLevel(
inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())))
def createServer(self, services, fallback=None, responses=[]):
server = testutil.createServer(lambda config: svcbindproxy.ServiceBindingProxy(
config=config,
services=services,
fallback=fallback,
),
baseDN='dc=example,dc=com',
*responses)
server.now = '20050213140302Z'
server.timestamp = lambda : server.now
return server
def test_bind_noMatchingServicesFound_noFallback(self):
server = self.createServer(
services=['svc1',
'svc2',
'svc3',
],
fallback=False,
responses=[
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
])
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com', auth='s3krit'), id=4)))
reactor.iterate() #TODO
client = server.client
client.assertSent(
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc1)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc2)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc3)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
)
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=ldaperrors.LDAPInvalidCredentials.resultCode), id=4)))
def test_bind_noMatchingServicesFound_fallback_success(self):
server = self.createServer(
services=['svc1',
'svc2',
'svc3',
],
fallback=True,
responses=[
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPBindResponse(resultCode=ldaperrors.Success.resultCode) ],
])
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com', auth='s3krit'), id=4)))
reactor.iterate() #TODO
client = server.client
client.assertSent(
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc1)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc2)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc3)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com', auth='s3krit'))
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=ldaperrors.Success.resultCode), id=4)))
def test_bind_noMatchingServicesFound_fallback_badAuth(self):
server = self.createServer(
services=['svc1',
'svc2',
'svc3',
],
fallback=True,
responses=[
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPBindResponse(resultCode=ldaperrors.LDAPInvalidCredentials.resultCode),
],
])
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com', auth='wrong-s3krit'), id=4)))
reactor.iterate() #TODO
client = server.client
client.assertSent(
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc1)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc2)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc3)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com', auth='wrong-s3krit'))
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=ldaperrors.LDAPInvalidCredentials.resultCode), id=4)))
def test_bind_match_success(self):
server = self.createServer(
services=['svc1',
'svc2',
'svc3',
],
fallback=True,
responses=[
# svc1
[ pureldap.LDAPSearchResultEntry(r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
attributes=[]),
pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPBindResponse(resultCode=ldaperrors.Success.resultCode) ],
])
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com', auth='secret'), id=4)))
reactor.iterate() #TODO
client = server.client
client.assertSent(
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc1)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPBindRequest(dn=r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com', auth='secret'),
)
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=ldaperrors.Success.resultCode,
matchedDN='cn=jack,dc=example,dc=com'), id=4)))
def test_bind_match_success_later(self):
server = self.createServer(
services=['svc1',
'svc2',
'svc3',
],
fallback=True,
responses=[
# svc1
[ pureldap.LDAPSearchResultEntry(r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
attributes=[]),
pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPBindResponse(resultCode=ldaperrors.LDAPInvalidCredentials.resultCode) ],
# svc2
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
# svc3
[ pureldap.LDAPSearchResultEntry(r'cn=svc3+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
attributes=[]),
pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPBindResponse(resultCode=ldaperrors.Success.resultCode) ],
])
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com', auth='secret'), id=4)))
reactor.iterate() #TODO
client = server.client
client.assertSent(
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc1)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPBindRequest(dn=r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com', auth='secret'),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc2)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc3)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPBindRequest(dn='cn=svc3+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com', auth='secret'),
)
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=ldaperrors.Success.resultCode,
matchedDN='cn=jack,dc=example,dc=com'), id=4)))
def test_bind_match_badAuth(self):
server = self.createServer(
services=['svc1',
'svc2',
'svc3',
],
fallback=True,
responses=[
# svc1
[ pureldap.LDAPSearchResultEntry(r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
attributes=[]),
pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPBindResponse(resultCode=ldaperrors.LDAPInvalidCredentials.resultCode) ],
# svc2
[ pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
# svc3
[ pureldap.LDAPSearchResultEntry(r'cn=svc3+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
attributes=[]),
pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode) ],
[ pureldap.LDAPBindResponse(resultCode=ldaperrors.LDAPInvalidCredentials.resultCode) ],
[ pureldap.LDAPBindResponse(resultCode=ldaperrors.LDAPInvalidCredentials.resultCode) ],
])
server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com', auth='wrong-s3krit'), id=4)))
reactor.iterate() #TODO
client = server.client
client.assertSent(
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc1)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPBindRequest(dn=r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com', auth='wrong-s3krit'),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc2)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPSearchRequest(baseObject='dc=example,dc=com',
derefAliases=0,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
filter=ldapfilter.parseFilter('(&'
+'(objectClass=serviceSecurityObject)'
+'(owner=cn=jack,dc=example,dc=com)'
+'(cn=svc3)'
+('(|(!(validFrom=*))(validFrom<=%s))' % server.now)
+('(|(!(validUntil=*))(validUntil>=%s))' % server.now)
+')'),
attributes=('1.1',)),
pureldap.LDAPBindRequest(dn='cn=svc3+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com', auth='wrong-s3krit'),
pureldap.LDAPBindRequest(version=3, dn='cn=jack,dc=example,dc=com', auth='wrong-s3krit'),
)
self.assertEquals(server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=ldaperrors.LDAPInvalidCredentials.resultCode), id=4)))
ldaptor-0.0.43/ldaptor/test/test_schema.py 0000644 0001750 0001750 00000053450 10104536552 016652 0 ustar jan jan """
Test cases for ldaptor.schema module.
"""
from twisted.trial import unittest
from ldaptor import schema
OBJECTCLASSES = {
'organization': """( 2.5.6.4 NAME 'organization'
DESC 'RFC2256: an organization'
SUP top STRUCTURAL
MUST o
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )""",
'organizationalUnit': """( 2.5.6.5 NAME 'organizationalUnit'
DESC 'RFC2256: an organizational unit'
SUP top STRUCTURAL
MUST ou
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )""",
'country': """( 2.5.6.2 NAME 'country'
DESC 'RFC2256: a country'
SUP top STRUCTURAL
MUST c
MAY ( searchGuide $ description ) )""",
}
class AttributeType_KnownValues(unittest.TestCase):
knownValues = [
("""( 2.5.4.4 NAME ( 'sn' 'surname' )
DESC 'RFC2256: last (family) name(s) for which the entity is known by'
SUP name )""",
{ 'oid': '2.5.4.4',
'name': ('sn', 'surname',),
'desc': 'RFC2256: last (family) name(s) for which the entity is known by',
'sup': 'name',
}),
("""( 2.5.4.2 NAME 'knowledgeInformation'
DESC 'RFC2256: knowledge information'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )""",
{ 'oid': '2.5.4.2',
'name': ('knowledgeInformation',),
'desc': 'RFC2256: knowledge information',
'equality': 'caseIgnoreMatch',
'syntax': '1.3.6.1.4.1.1466.115.121.1.15{32768}',
}),
("""( 2.5.4.5 NAME 'serialNumber'
DESC 'RFC2256: serial number of the entity'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )""",
{ 'oid': '2.5.4.5',
'name': ('serialNumber',),
'desc': 'RFC2256: serial number of the entity',
'equality': 'caseIgnoreMatch',
'substr': 'caseIgnoreSubstringsMatch',
'syntax': '1.3.6.1.4.1.1466.115.121.1.44{64}',
}),
("""( 2.5.4.6 NAME ( 'c' 'countryName' )
DESC 'RFC2256: ISO-3166 country 2-letter code'
SUP name SINGLE-VALUE )""",
{ 'oid': '2.5.4.6',
'name': ('c', 'countryName',),
'desc': 'RFC2256: ISO-3166 country 2-letter code',
'sup': 'name',
'single_value': 1,
}),
("""( 1.2.840.113549.1.9.1
NAME ( 'email' 'emailAddress' 'pkcs9email' )
DESC 'RFC2459: legacy attribute for email addresses in DNs'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )""",
{ 'oid': '1.2.840.113549.1.9.1',
'name': ('email', 'emailAddress', 'pkcs9email', ),
'desc': 'RFC2459: legacy attribute for email addresses in DNs',
'equality': 'caseIgnoreIA5Match',
'substr': 'caseIgnoreIA5SubstringsMatch',
'syntax': '1.3.6.1.4.1.1466.115.121.1.26{128}',
}),
]
def testParse(self):
defaults = {
'name': None,
'desc': None,
'obsolete': 0,
'sup': [],
'equality': None,
'ordering': None,
'substr': None,
'syntax': None,
'single_value': 0,
'collective': 0,
'no_user_modification': 0,
'usage': None,
}
for text, expected in self.knownValues:
a=schema.AttributeTypeDescription(text)
self.failIfEqual(a.oid, None)
for key, want in expected.items():
if key in defaults:
del defaults[key]
got = getattr(a, key)
self.assertEquals(got, want)
for key, want in defaults.items():
got = getattr(a, key)
self.assertEquals(got, want)
def testStringification(self):
for want, values in self.knownValues:
a=schema.AttributeTypeDescription(None)
for key, val in values.items():
setattr(a, key, val)
want = ' '.join(want.split(None))
got = ' '.join(str(a).split(None))
self.assertEquals(got, want)
class ObjectClass_KnownValues(unittest.TestCase):
knownValues = [
(OBJECTCLASSES['organization'],
{ 'oid': '2.5.6.4',
'name': ('organization',),
'desc': 'RFC2256: an organization',
'sup': ['top'],
'type': 'STRUCTURAL',
'must': ['o'],
'may': ['userPassword', 'searchGuide', 'seeAlso',
'businessCategory', 'x121Address', 'registeredAddress',
'destinationIndicator', 'preferredDeliveryMethod',
'telexNumber', 'teletexTerminalIdentifier',
'telephoneNumber', 'internationaliSDNNumber',
'facsimileTelephoneNumber', 'street', 'postOfficeBox',
'postalCode', 'postalAddress',
'physicalDeliveryOfficeName', 'st', 'l', 'description'],
}),
(OBJECTCLASSES['organizationalUnit'],
{ 'oid': '2.5.6.5',
'name': ('organizationalUnit',),
'desc': 'RFC2256: an organizational unit',
'sup': ['top'],
'type': 'STRUCTURAL',
'must': ['ou'],
'may': [ 'userPassword', 'searchGuide', 'seeAlso',
'businessCategory', 'x121Address', 'registeredAddress',
'destinationIndicator', 'preferredDeliveryMethod',
'telexNumber', 'teletexTerminalIdentifier',
'telephoneNumber', 'internationaliSDNNumber',
'facsimileTelephoneNumber', 'street', 'postOfficeBox',
'postalCode', 'postalAddress', 'physicalDeliveryOfficeName',
'st', 'l', 'description', ],
}),
]
def testParse(self):
defaults = {
'name': None,
'desc': None,
'obsolete': 0,
'sup': None,
'type': 'STRUCTURAL',
'must': [],
'may': [],
}
for text, expected in self.knownValues:
a=schema.ObjectClassDescription(text)
self.failIfEqual(a.oid, None)
for key, want in expected.items():
if key in defaults:
del defaults[key]
got = getattr(a, key)
self.assertEquals(got, want)
for key, want in defaults.items():
got = getattr(a, key)
self.assertEquals(got, want)
def testStringification(self):
for want, values in self.knownValues:
a=schema.ObjectClassDescription(None)
for key, val in values.items():
setattr(a, key, val)
want = ' '.join(want.split(None))
got = ' '.join(str(a).split(None))
self.assertEquals(got, want)
class TestComparison(unittest.TestCase):
ORDER = [
'country',
'organization',
'organizationalUnit',
]
def setUp(self):
data = {}
for oc,text in OBJECTCLASSES.items():
data[oc] = schema.ObjectClassDescription(text)
self.data = data
def test_eq(self):
for k1 in self.data:
for k2 in self.data:
if k1 == k2:
self.failUnless(self.data[k1] == self.data[k2])
else:
self.failIf(self.data[k1] == self.data[k2])
def test_ne(self):
for k1 in self.data:
for k2 in self.data:
if k1 == k2:
self.failIf(self.data[k1] != self.data[k2])
else:
self.failUnless(self.data[k1] != self.data[k2])
def test_order(self):
for i,base in enumerate(self.ORDER):
self.failUnless(self.data[base] <= self.data[base])
self.failUnless(self.data[base] >= self.data[base])
self.failIf(self.data[base] < self.data[base])
self.failIf(self.data[base] > self.data[base])
for lower in self.ORDER[:i]:
self.failUnless(self.data[lower] < self.data[base])
self.failUnless(self.data[lower] <= self.data[base])
self.failIf(self.data[base] < self.data[lower])
self.failIf(self.data[base] <= self.data[lower])
for higher in self.ORDER[i+1:]:
self.failUnless(self.data[higher] > self.data[base])
self.failUnless(self.data[higher] >= self.data[base])
self.failIf(self.data[base] > self.data[higher])
self.failIf(self.data[base] >= self.data[higher])
"""
attributetype ( 2.5.4.7 NAME ( 'l' 'localityName' )
DESC 'RFC2256: locality which this object resides in'
SUP name )
attributetype ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' )
DESC 'RFC2256: state or province which this object resides in'
SUP name )
attributetype ( 2.5.4.9 NAME ( 'street' 'streetAddress' )
DESC 'RFC2256: street address of this object'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 2.5.4.10 NAME ( 'o' 'organizationName' )
DESC 'RFC2256: organization this object belongs to'
SUP name )
attributetype ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' )
DESC 'RFC2256: organizational unit this object belongs to'
SUP name )
attributetype ( 2.5.4.12 NAME 'title'
DESC 'RFC2256: title associated with the entity'
SUP name )
attributetype ( 2.5.4.13 NAME 'description'
DESC 'RFC2256: descriptive information'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
attributetype ( 2.5.4.14 NAME 'searchGuide'
DESC 'RFC2256: search guide, obsoleted by enhancedSearchGuide'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )
attributetype ( 2.5.4.15 NAME 'businessCategory'
DESC 'RFC2256: business category'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 2.5.4.16 NAME 'postalAddress'
DESC 'RFC2256: postal address'
EQUALITY caseIgnoreListMatch
SUBSTR caseIgnoreListSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributetype ( 2.5.4.17 NAME 'postalCode'
DESC 'RFC2256: postal code'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
attributetype ( 2.5.4.18 NAME 'postOfficeBox'
DESC 'RFC2256: Post Office Box'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
attributetype ( 2.5.4.19 NAME 'physicalDeliveryOfficeName'
DESC 'RFC2256: Physical Delivery Office Name'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 2.5.4.20 NAME 'telephoneNumber'
DESC 'RFC2256: Telephone Number'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
attributetype ( 2.5.4.21 NAME 'telexNumber'
DESC 'RFC2256: Telex Number'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
attributetype ( 2.5.4.22 NAME 'teletexTerminalIdentifier'
DESC 'RFC2256: Teletex Terminal Identifier'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
attributetype ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
DESC 'RFC2256: Facsimile (Fax) Telephone Number'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
attributetype ( 2.5.4.24 NAME 'x121Address'
DESC 'RFC2256: X.121 Address'
EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{15} )
attributetype ( 2.5.4.25 NAME 'internationaliSDNNumber'
DESC 'RFC2256: international ISDN number'
EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
attributetype ( 2.5.4.26 NAME 'registeredAddress'
DESC 'RFC2256: registered postal address'
SUP postalAddress
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributetype ( 2.5.4.27 NAME 'destinationIndicator'
DESC 'RFC2256: destination indicator'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
attributetype ( 2.5.4.28 NAME 'preferredDeliveryMethod'
DESC 'RFC2256: preferred delivery method'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
SINGLE-VALUE )
attributetype ( 2.5.4.29 NAME 'presentationAddress'
DESC 'RFC2256: presentation address'
EQUALITY presentationAddressMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.43
SINGLE-VALUE )
attributetype ( 2.5.4.30 NAME 'supportedApplicationContext'
DESC 'RFC2256: supported application context'
EQUALITY objectIdentifierMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
attributetype ( 2.5.4.31 NAME 'member'
DESC 'RFC2256: member of a group'
SUP distinguishedName )
attributetype ( 2.5.4.32 NAME 'owner'
DESC 'RFC2256: owner (of the object)'
SUP distinguishedName )
attributetype ( 2.5.4.33 NAME 'roleOccupant'
DESC 'RFC2256: occupant of role'
SUP distinguishedName )
attributetype ( 2.5.4.34 NAME 'seeAlso'
DESC 'RFC2256: DN of related object'
SUP distinguishedName )
attributetype ( 2.5.4.36 NAME 'userCertificate'
DESC 'RFC2256: X.509 user certificate, use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
attributetype ( 2.5.4.37 NAME 'cACertificate'
DESC 'RFC2256: X.509 CA certificate, use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
attributetype ( 2.5.4.38 NAME 'authorityRevocationList'
DESC 'RFC2256: X.509 authority revocation list, use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
attributetype ( 2.5.4.39 NAME 'certificateRevocationList'
DESC 'RFC2256: X.509 certificate revocation list, use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
attributetype ( 2.5.4.40 NAME 'crossCertificatePair'
DESC 'RFC2256: X.509 cross certificate pair, use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )
attributetype ( 2.5.4.42 NAME ( 'givenName' 'gn' )
DESC 'RFC2256: first name(s) for which the entity is known by'
SUP name )
attributetype ( 2.5.4.43 NAME 'initials'
DESC 'RFC2256: initials of some or all of names, but not the surname(s).'
SUP name )
attributetype ( 2.5.4.44 NAME 'generationQualifier'
DESC 'RFC2256: name qualifier indicating a generation'
SUP name )
attributetype ( 2.5.4.45 NAME 'x500UniqueIdentifier'
DESC 'RFC2256: X.500 unique identifier'
EQUALITY bitStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )
attributetype ( 2.5.4.46 NAME 'dnQualifier'
DESC 'RFC2256: DN qualifier'
EQUALITY caseIgnoreMatch
ORDERING caseIgnoreOrderingMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
attributetype ( 2.5.4.47 NAME 'enhancedSearchGuide'
DESC 'RFC2256: enhanced search guide'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
attributetype ( 2.5.4.48 NAME 'protocolInformation'
DESC 'RFC2256: protocol information'
EQUALITY protocolInformationMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )
attributetype ( 2.5.4.50 NAME 'uniqueMember'
DESC 'RFC2256: unique member of a group'
EQUALITY uniqueMemberMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )
attributetype ( 2.5.4.51 NAME 'houseIdentifier'
DESC 'RFC2256: house identifier'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
attributetype ( 2.5.4.52 NAME 'supportedAlgorithms'
DESC 'RFC2256: supported algorithms'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
attributetype ( 2.5.4.53 NAME 'deltaRevocationList'
DESC 'RFC2256: delta revocation list; use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
attributetype ( 2.5.4.54 NAME 'dmdName'
DESC 'RFC2256: name of DMD'
SUP name )
objectclass ( 2.5.6.3 NAME 'locality'
DESC 'RFC2256: a locality'
SUP top STRUCTURAL
MAY ( street $ seeAlso $ searchGuide $ st $ l $ description ) )
objectclass ( 2.5.6.6 NAME 'person'
DESC 'RFC2256: a person'
SUP top STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
objectclass ( 2.5.6.7 NAME 'organizationalPerson'
DESC 'RFC2256: an organizational person'
SUP person STRUCTURAL
MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
objectclass ( 2.5.6.8 NAME 'organizationalRole'
DESC 'RFC2256: an organizational role'
SUP top STRUCTURAL
MUST cn
MAY ( x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
seeAlso $ roleOccupant $ preferredDeliveryMethod $ street $
postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ ou $ st $ l $ description ) )
objectclass ( 2.5.6.9 NAME 'groupOfNames'
DESC 'RFC2256: a group of names (DNs)'
SUP top STRUCTURAL
MUST ( member $ cn )
MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
objectclass ( 2.5.6.10 NAME 'residentialPerson'
DESC 'RFC2256: an residential person'
SUP person STRUCTURAL
MUST l
MAY ( businessCategory $ x121Address $ registeredAddress $
destinationIndicator $ preferredDeliveryMethod $ telexNumber $
teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ preferredDeliveryMethod $ street $
postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ st $ l ) )
objectclass ( 2.5.6.11 NAME 'applicationProcess'
DESC 'RFC2256: an application process'
SUP top STRUCTURAL
MUST cn
MAY ( seeAlso $ ou $ l $ description ) )
objectclass ( 2.5.6.12 NAME 'applicationEntity'
DESC 'RFC2256: an application entity'
SUP top STRUCTURAL
MUST ( presentationAddress $ cn )
MAY ( supportedApplicationContext $ seeAlso $ ou $ o $ l $
description ) )
objectclass ( 2.5.6.13 NAME 'dSA'
DESC 'RFC2256: a directory system agent (a server)'
SUP applicationEntity STRUCTURAL
MAY knowledgeInformation )
objectclass ( 2.5.6.14 NAME 'device'
DESC 'RFC2256: a device'
SUP top STRUCTURAL
MUST cn
MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) )
objectclass ( 2.5.6.15 NAME 'strongAuthenticationUser'
DESC 'RFC2256: a strong authentication user'
SUP top AUXILIARY
MUST userCertificate )
objectclass ( 2.5.6.16 NAME 'certificationAuthority'
DESC 'RFC2256: a certificate authority'
SUP top AUXILIARY
MUST ( authorityRevocationList $ certificateRevocationList $
cACertificate ) MAY crossCertificatePair )
objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames'
DESC 'RFC2256: a group of unique names (DN and Unique Identifier)'
SUP top STRUCTURAL
MUST ( uniqueMember $ cn )
MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
objectclass ( 2.5.6.18 NAME 'userSecurityInformation'
DESC 'RFC2256: a user security information'
SUP top AUXILIARY
MAY ( supportedAlgorithms ) )
objectclass ( 2.5.6.16.2 NAME 'certificationAuthority-V2'
SUP certificationAuthority
AUXILIARY MAY ( deltaRevocationList ) )
objectclass ( 2.5.6.19 NAME 'cRLDistributionPoint'
SUP top STRUCTURAL
MUST ( cn )
MAY ( certificateRevocationList $ authorityRevocationList $
deltaRevocationList ) )
objectclass ( 2.5.6.20 NAME 'dmd'
SUP top STRUCTURAL
MUST ( dmdName )
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
street $ postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ st $ l $ description ) )
objectclass ( 2.5.6.21 NAME 'pkiUser'
DESC 'RFC2587: a PKI user'
SUP top AUXILIARY
MAY userCertificate )
objectclass ( 2.5.6.22 NAME 'pkiCA'
DESC 'RFC2587: PKI certificate authority'
SUP top AUXILIARY
MAY ( authorityRevocationList $ certificateRevocationList $
cACertificate $ crossCertificatePair ) )
objectclass ( 2.5.6.23 NAME 'deltaCRL'
DESC 'RFC2587: PKI user'
SUP top AUXILIARY
MAY deltaRevocationList )
attributetype ( 1.3.6.1.4.1.250.1.57 NAME 'labeledURI'
DESC 'RFC2079: Uniform Resource Identifier with optional label'
EQUALITY caseExactMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
objectclass ( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject'
DESC 'RFC2079: object that contains the URI attribute type'
MAY ( labeledURI )
SUP top AUXILIARY )
attributetype ( 0.9.2342.19200300.100.1.1
NAME ( 'uid' 'userid' )
DESC 'RFC1274: user identifier'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributetype ( 0.9.2342.19200300.100.1.3
NAME ( 'mail' 'rfc822Mailbox' )
DESC 'RFC1274: RFC822 Mailbox'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
objectclass ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
DESC 'RFC1274: simple security object'
SUP top AUXILIARY
MUST userPassword )
attributetype ( 0.9.2342.19200300.100.1.25
NAME ( 'dc' 'domainComponent' )
DESC 'RFC1274/2247: domain component'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
objectclass ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
DESC 'RFC2247: domain component object'
SUP top AUXILIARY MUST dc )
objectclass ( 1.3.6.1.1.3.1 NAME 'uidObject'
DESC 'RFC2377: uid object'
SUP top AUXILIARY MUST uid )
attributetype ( 0.9.2342.19200300.100.1.37
NAME 'associatedDomain'
DESC 'RFC1274: domain associated with object'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
"""
ldaptor-0.0.43/ldaptor/test/web/ 0000755 0001750 0001750 00000000000 10403234277 014550 5 ustar jan jan ldaptor-0.0.43/ldaptor/test/web/edit-simple.twill 0000644 0001750 0001750 00000004575 10352514563 020056 0 ustar jan jan # textareas reshown on forms with error get spurious \n prefixes and
# suffixes with tidy
config do_run_tidy 0
formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
formvalue search search_Name jack
submit
code 200
title "Ldaptor Search Page"
find "
1 entries matched\.
"
follow /ou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom/edit/uid%3Djack%2Cou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom$
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Edit Page"
notfind Exception
notfind traceback
find '\sNo error for error key: edit\s'
find ''
formvalue edit edit_cn 'Jack R. Black'
submit
code 200
title "Ldaptor Edit Page"
notfind Exception
notfind traceback
find '\s*Edited uid=jack,ou=People,dc=example,dc=com successfully\. \[[^]]+\]
'
formvalue search search_Name 'Jack R. Black'
submit
code 200
title "Ldaptor Search Page"
find '
1 entries matched\.
'
follow edit
code 200
title "Ldaptor Edit Page"
# put it back like it used to be
formvalue edit edit_cn 'Jack Black'
submit
code 200
title "Ldaptor Edit Page"
notfind Exception
notfind traceback
find '\s*Edited uid=jack,ou=People,dc=example,dc=com successfully\. \[[^]]+\]
changing cn
remove \'Jack R\. Black\'
add \'Jack Black\'
\s*'
find '\sNo error for error key: edit\s'
find ''
ldaptor-0.0.43/ldaptor/test/web/frontpage.twill 0000644 0001750 0001750 00000000401 10403043506 017576 0 ustar jan jan title "Ldaptor Web Interface"
formvalue go baseDN dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
#TODO if possible, get rid of %3D and use just = instead
url '/dc%3Dexample%2Cdc%3Dcom/search/$'
find dc=example,dc=com
notfind LDAPNoSuchObject
ldaptor-0.0.43/ldaptor/test/web/search.twill 0000644 0001750 0001750 00000002077 10350214673 017077 0 ustar jan jan formvalue go baseDN dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
formvalue search searchfilter '(objectClass=dcObject)'
find ''
formvalue search scope 0
submit
code 200
find '
"
ldaptor-0.0.43/ldaptor/test/web/edit-missingMust.twill 0000644 0001750 0001750 00000003353 10352532370 021074 0 ustar jan jan # textareas reshown on forms with error get spurious \n prefixes and
# suffixes with tidy
config do_run_tidy 0
formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
formvalue search search_Name missing-must-fields
submit
code 200
title "Ldaptor Search Page"
find "
1 entries matched\.
"
follow /ou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom/edit/cn%3Dmissing-must-fields%2Cou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom$
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Edit Page"
notfind Exception
notfind traceback
find ''
notfind ''
formvalue edit edit dummy
submit
code 200
title "Ldaptor Edit Page"
notfind 'No changes!'
# no status message at all
find '\s*\s*'
# sn field gives error
find '
"
ldaptor-0.0.43/ldaptor/test/web/add-fail-missingRequiredFields.twill 0000644 0001750 0001750 00000001277 10350215020 023556 0 ustar jan jan formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
follow "add new entry"
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Add Page"
formvalue add structuralObjectClass account
formvalue add auxiliary_posixAccount True
submit
code 200
title "Ldaptor Add Page"
# required fields for posixAccount are enforced
formvalue add add_uid justfortest
submit
code 200
find '
Error:
'
find '
Please enter a string\.
'
ldaptor-0.0.43/ldaptor/test/web/delete-fail-nodn.twill 0000644 0001750 0001750 00000000405 10350243416 020727 0 ustar jan jan go dc=example,dc=com/delete
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title 'Ldaptor Delete Page'
find 'Missing DN to delete\.'
follow 'search page'
code 200
title 'Ldaptor Search Page'
ldaptor-0.0.43/ldaptor/test/web/frontpage-baddn.twill 0000644 0001750 0001750 00000001173 10350243416 020656 0 ustar jan jan title "Ldaptor Web Interface"
formvalue go baseDN junk
submit
code 200
title "Ldaptor Web Interface"
find '
\'junk\' is not a valid LDAP DN: Invalid relative distinguished name \'junk\'\.
'
go 'junk'
code 200
title "Ldaptor Web Interface"
find ''
find 'No error for error key: go'
find 'No error for error key: go\.baseDN'
url ^http://localhost:\d+/$
ldaptor-0.0.43/ldaptor/test/web/add-delete-lookingAtRemovedEntry.twill 0000644 0001750 0001750 00000002422 10352503422 024100 0 ustar jan jan formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
follow "add new entry"
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor.Add.Page"
formvalue add structuralObjectClass account
submit
code 200
title "Ldaptor Add Page"
formvalue add add_uid justfortest
submit
code 200
find 'Added uid=justfortest,ou=People,dc=example,dc=com successfully\.'
follow Search
code 200
title "Ldaptor Search Page"
formvalue search search_Name justfortest
submit
code 200
find "
1 entries matched\.
"
follow /uid%3Djustfortest%2Cou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom/search/$
code 200
title "Ldaptor Search Page"
follow /uid%3Djustfortest%2Cou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom/delete/uid%3Djustfortest%2Cou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom$
code 200
title "Ldaptor Delete Page"
find "
"
ldaptor-0.0.43/ldaptor/test/web/search-all.twill 0000644 0001750 0001750 00000000351 10370122041 017623 0 ustar jan jan formvalue go baseDN dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
formvalue search search dummy
submit
code 200
find '
5 entries matched\.
'
find '
Used filter \(objectClass=\*\)
'
ldaptor-0.0.43/ldaptor/test/web/delete-fail-ldaperror.twill 0000644 0001750 0001750 00000001031 10350256624 021764 0 ustar jan jan go dc=example,dc=com/delete/dc=example,dc=com
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
# Make sure the authentication worked
title "Ldaptor Delete Page"
find "
Remove dc=example,dc=com\?
"
go cn=does-not-exist,dc=example,dc=com
code 200
title "Ldaptor Delete Page"
find '
Remove cn=does-not-exist,dc=example,dc=com\?
'
find '
An error occurred: noSuchObject
'
notfind Exception
notfind traceback
ldaptor-0.0.43/ldaptor/test/web/add-fail-missingRequiredFields-retryWorks.twill 0000644 0001750 0001750 00000004550 10350243416 025756 0 ustar jan jan # textareas reshown on forms with error get spurious \n prefixes and
# suffixes with tidy
config do_run_tidy 0
formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
follow "add new entry"
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Add Page"
formvalue add structuralObjectClass account
formvalue add auxiliary_posixAccount True
submit
code 200
title "Ldaptor Add Page"
# required fields for posixAccount are enforced
formvalue add add_uid justfortest
submit
code 200
find '
Error:
'
find '
Please enter a string\.
'
find '
Please enter a string\.
'
find ''
find 'No error for error key: add\.add_uid'
# we purposefully do not re-set add_uid here, as
# letting it preserve the old form value triggers
# a bug where the value was prefixed and suffixed
# with a newline. still unclear whether the bug is
# in twill or in ldaptor
formvalue add add_cn 'Just For Test'
formvalue add add_homeDirectory /home/testusers/justfortest
submit
code 200
notfind '
"
ldaptor-0.0.43/ldaptor/test/web/delete-nonleaf.twill 0000644 0001750 0001750 00000001111 10350214673 020500 0 ustar jan jan formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
follow /ou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom/delete/ou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom$
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Delete Page"
find "
Remove ou=People,dc=example,dc=com\?
"
formvalue delete delete dummy
submit
code 200
# we do not want to get redirected away on error
title "Ldaptor Delete Page"
find '
Failed: notAllowedOnNonLeaf: Cannot remove entry with children: ou=People,dc=example,dc=com\.
'
ldaptor-0.0.43/ldaptor/test/web/password-simple.twill 0000644 0001750 0001750 00000001577 10365664731 021001 0 ustar jan jan # textareas reshown on forms with error get spurious \n prefixes and
# suffixes with tidy
config do_run_tidy 0
formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
formvalue search search_Name "jack"
submit
code 200
title "Ldaptor Search Page"
find "
1 entries matched\.
"
follow '/ou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom/change_password/uid%3Djack%2Cou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom$'
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Password Change Page"
find '
\s*About to set password for\s+uid=jack,ou=People,dc=example,dc=com.\s*
'
formvalue setPassword newPassword hushhush
formvalue setPassword again hushhush
submit
code 200
title "Ldaptor Password Change Page"
notfind 'Failed'
find '\s*Password set\.\s*'
ldaptor-0.0.43/ldaptor/test/web/edit-textarea-emptiness.twill 0000644 0001750 0001750 00000002336 10352530664 022400 0 ustar jan jan ### empty textareas don't suddenly get "" as their value
# textareas reshown on forms with error get spurious \n prefixes and
# suffixes with tidy
config do_run_tidy 0
formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
formvalue search search_Name 'John Smith'
submit
code 200
title "Ldaptor Search Page"
find "
1 entries matched\.
"
follow /ou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom/edit/cn%3DJohn%20Smith%2Cou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom$
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Edit Page"
notfind Exception
notfind traceback
formvalue edit edit dummy
submit
code 200
title "Ldaptor Edit Page"
notfind '\s*Edited cn=John Smith,ou=People,dc=example,dc=com successfully. \[[^]]+\]
\s*'
ldaptor-0.0.43/ldaptor/test/web/search-broken-filter.twill 0000644 0001750 0001750 00000000426 10350214673 021634 0 ustar jan jan formvalue go baseDN dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
formvalue search searchfilter broke
submit
code 200
notfind Exception
notfind InvalidLDAPFilter
find '
Invalid LDAP filter: Expected "\(" at point 0 in \'broke\'
'
ldaptor-0.0.43/ldaptor/test/web/password-simple-others.twill 0000644 0001750 0001750 00000001732 10370122117 022253 0 ustar jan jan # textareas reshown on forms with error get spurious \n prefixes and
# suffixes with tidy
config do_run_tidy 0
formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
title "Ldaptor Search Page"
formvalue search search_Name "John Smith"
submit
code 200
title "Ldaptor Search Page"
find "
1 entries matched\.
"
follow '/ou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom/change_password/cn%3DJohn%20Smith%2Cou%3DPeople%2Cdc%3Dexample%2Cdc%3Dcom$'
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Password Change Page"
find '
\s*About to set password for\s+cn=John Smith,ou=People,dc=example,dc=com.\s*
'
formvalue setPassword newPassword hushhush
formvalue setPassword again hushhush
submit
code 200
title "Ldaptor Password Change Page"
find 'Failed: Some of the password plugins failed: ExtendedOperation failed with insufficientAccessRights; Samba failed with Aborted.'
ldaptor-0.0.43/ldaptor/test/web/delete-fail-baddn.twill 0000644 0001750 0001750 00000000440 10350256624 021045 0 ustar jan jan go dc=example,dc=com/delete/dc=example,dc=com
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
# Make sure the authentication worked
title "Ldaptor Delete Page"
find "
Remove dc=example,dc=com\?
"
go invaliddn
code 404
ldaptor-0.0.43/ldaptor/test/web/add-posixaccount.twill 0000644 0001750 0001750 00000002701 10350243416 021066 0 ustar jan jan formvalue go baseDN ou=People,dc=example,dc=com
submit
code 200
follow "add new entry"
code 200
title "Login"
formvalue login name jack
formvalue login password secret
submit
code 200
title "Ldaptor Add Page"
formvalue add structuralObjectClass account
formvalue add auxiliary_posixAccount True
submit
code 200
title "Ldaptor Add Page"
formvalue add add_uid justfortest
formvalue add add_homeDirectory /home/testusers/justfortest
submit
code 200
find 'Added uid=justfortest,ou=People,dc=example,dc=com successfully\.'
follow Search
code 200
title "Ldaptor Search Page"
formvalue search search_Name justfortest
submit
code 200
find "
'
find 'cn=John Smith,ou=People,dc=example,dc=com\s'
ldaptor-0.0.43/ldaptor/test/test_pureldap.py 0000644 0001750 0001750 00000053100 10365653714 017227 0 ustar jan jan # Ldaptor -- TODO
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
Test cases for ldaptor.protocols.pureldap module.
"""
from twisted.trial import unittest
from ldaptor.protocols import pureldap, pureber
import types
def s(*l):
"""Join all members of list to a string. Integer members are chr()ed"""
r=''
for e in l:
if isinstance(e, types.IntType):
e=chr(e)
r=r+str(e)
return r
def l(s):
"""Split a string to ord's of chars."""
return map(lambda x: ord(x), s)
class KnownValues(unittest.TestCase):
knownValues=( # class, args, kwargs, expected_result
(pureldap.LDAPModifyRequest,
[],
{ "object": 'cn=foo, dc=example, dc=com',
"modification": [
pureber.BERSequence([
pureber.BEREnumerated(0),
pureber.BERSequence([
pureldap.LDAPAttributeDescription('bar'),
pureber.BERSet([
pureldap.LDAPString('a'),
pureldap.LDAPString('b'),
]),
]),
]),
],
},
None,
[0x66, 50]
+ ([0x04, 0x1a] + l("cn=foo, dc=example, dc=com")
+ [0x30, 20]
+ ([0x30, 18]
+ ([0x0a, 0x01, 0x00]
+ [0x30, 13]
+ ([0x04, len("bar")] + l("bar")
+ [0x31, 0x06]
+ ([0x04, len("a")] + l("a")
+ [0x04, len("b")] + l("b"))))))
),
(pureldap.LDAPModifyRequest,
[],
{ "object": 'cn=foo, dc=example, dc=com',
"modification": [
pureber.BERSequence([
pureber.BEREnumerated(1L),
pureber.BERSequence([
pureber.BEROctetString('bar'),
pureber.BERSet([]),
]),
]),
],
},
None,
[0x66, 0x2c]
+ ([0x04, 0x1a] + l("cn=foo, dc=example, dc=com")
+ [0x30, 0x0e]
+ ([0x30, 0x0c]
+ ([0x0a, 0x01, 0x01]
+ [0x30, 0x07]
+ ([0x04, 0x03] + l("bar")
+ [0x31, 0x00]))))
),
(pureldap.LDAPFilter_not,
[],
{ "value": pureldap.LDAPFilter_present("foo"),
},
pureldap.LDAPBERDecoderContext_Filter(fallback=pureber.BERDecoderContext()),
[0xa2, 0x05]
+ [0x87]
+ [len("foo")]
+ l("foo")),
(pureldap.LDAPFilter_or,
[],
{ "value": [pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo')),
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='uid'),
assertionValue=pureldap.LDAPAssertionValue(value='foo')),
]
},
pureldap.LDAPBERDecoderContext_Filter(fallback=pureber.BERDecoderContext()),
[0xa1, 23]
+ [0xa3, 9]
+ [0x04] + [len("cn")] + l("cn")
+ [0x04] + [len("foo")] + l("foo")
+ [0xa3, 10]
+ [0x04] + [len("uid")] + l("uid")
+ [0x04] + [len("foo")] + l("foo"),
),
(pureldap.LDAPFilter_and,
[],
{ "value": [pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
assertionValue=pureldap.LDAPAssertionValue(value='foo')),
pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value='uid'),
assertionValue=pureldap.LDAPAssertionValue(value='foo')),
]
},
pureldap.LDAPBERDecoderContext_Filter(fallback=pureber.BERDecoderContext()),
[0xa0, 23]
+ [0xa3, 9]
+ [0x04] + [len("cn")] + l("cn")
+ [0x04] + [len("foo")] + l("foo")
+ [0xa3, 10]
+ [0x04] + [len("uid")] + l("uid")
+ [0x04] + [len("foo")] + l("foo"),
),
(pureldap.LDAPModifyDNRequest,
[],
{'entry': 'cn=foo,dc=example,dc=com',
'newrdn': 'uid=bar',
'deleteoldrdn': 0,
},
None,
[0x6c, 0x26]
+ [0x04]
+ [len("cn=foo,dc=example,dc=com")]
+ l("cn=foo,dc=example,dc=com")
+ [0x04]
+ [len("uid=bar")]
+ l("uid=bar")
+ [0x01, 0x01, 0x00]),
(pureldap.LDAPModifyDNRequest,
[],
{'entry': 'cn=aoue,dc=example,dc=com',
'newrdn': 'uid=aoue',
'deleteoldrdn': 0,
'newSuperior': 'ou=People,dc=example,dc=com',
},
None,
[0x6c, 69]
+ [0x04]
+ [len("cn=aoue,dc=example,dc=com")]
+ l("cn=aoue,dc=example,dc=com")
+ [0x04]
+ [len("uid=aoue")]
+ l("uid=aoue")
+ [0x01, 0x01, 0x00]
+ [0x80]
+ [len("ou=People,dc=example,dc=com")]
+ l("ou=People,dc=example,dc=com")),
(pureldap.LDAPSearchRequest,
[],
{'baseObject': 'dc=yoja,dc=example,dc=com',
},
None,
[0x63, 57]
+ [0x04]
+ [len('dc=yoja,dc=example,dc=com')]
+ l('dc=yoja,dc=example,dc=com')
# scope
+ [0x0a, 1, 2]
# derefAliases
+ [0x0a, 1, 0]
# sizeLimit
+ [0x02, 1, 0]
# timeLimit
+ [0x02, 1, 0]
# typesOnly
+ [0x01, 1, 0]
# filter
+ [135, 11] + l('objectClass')
# attributes
+ [48, 0]
),
(pureldap.LDAPUnbindRequest,
[],
{},
None,
[0x42, 0x00]
),
(pureldap.LDAPSearchResultDone,
[],
{'resultCode': 0,
},
None,
[0x65, 0x07]
# resultCode
+ [0x0a, 0x01, 0x00]
# matchedDN
+ [0x04]
+ [len('')]
+ l('')
# errorMessage
+ [0x04]
+ [len('')]
+ l('')
# referral, TODO
+ []
),
(pureldap.LDAPSearchResultDone,
[],
{'resultCode': 0,
'matchedDN': 'dc=foo,dc=example,dc=com',
},
None,
[0x65, 31]
# resultCode
+ [0x0a, 0x01, 0x00]
# matchedDN
+ [0x04]
+ [len('dc=foo,dc=example,dc=com')]
+ l('dc=foo,dc=example,dc=com')
# errorMessage
+ [0x04]
+ [len('')]
+ l('')
# referral, TODO
+ []
),
(pureldap.LDAPSearchResultDone,
[],
{'resultCode': 0,
'matchedDN': 'dc=foo,dc=example,dc=com',
'errorMessage': 'the foobar was fubar',
},
None,
[0x65, 51]
# resultCode
+ [0x0a, 0x01, 0x00]
# matchedDN
+ [0x04]
+ [len('dc=foo,dc=example,dc=com')]
+ l('dc=foo,dc=example,dc=com')
# errorMessage
+ [0x04]
+ [len('the foobar was fubar')]
+ l('the foobar was fubar',)
# referral, TODO
+ []
),
(pureldap.LDAPSearchResultDone,
[],
{'resultCode': 0,
'errorMessage': 'the foobar was fubar',
},
None,
[0x65, 27]
# resultCode
+ [0x0a, 0x01, 0x00]
# matchedDN
+ [0x04]
+ [len('')]
+ l('')
# errorMessage
+ [0x04]
+ [len('the foobar was fubar')]
+ l('the foobar was fubar',)
# referral, TODO
+ []
),
(pureldap.LDAPMessage,
[],
{'id': 42,
'value': pureldap.LDAPBindRequest(),
},
pureldap.LDAPBERDecoderContext_TopLevel(
inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()))),
[0x30, 12]
# id
+ [0x02, 0x01, 42]
# value
+ l(str(pureldap.LDAPBindRequest()))
),
(pureldap.LDAPControl,
[],
{'controlType': '1.2.3.4',
},
None,
[0x30, 9]
# controlType
+ [0x04, 7]
+ l("1.2.3.4")
),
(pureldap.LDAPControl,
[],
{'controlType': '1.2.3.4',
'criticality': True,
},
None,
[0x30, 12]
# controlType
+ [0x04, 7]
+ l("1.2.3.4")
# criticality
+ [0x01, 1, 0xFF]
),
(pureldap.LDAPControl,
[],
{'controlType': '1.2.3.4',
'criticality': True,
'controlValue': 'silly',
},
None,
[0x30, 19]
# controlType
+ [0x04, 7]
+ l("1.2.3.4")
# criticality
+ [0x01, 1, 0xFF]
# controlValue
+ [0x04, len("silly")]
+ l("silly")
),
(pureldap.LDAPMessage,
[],
{'id': 42,
'value': pureldap.LDAPBindRequest(),
'controls': [ ('1.2.3.4', None, None),
('2.3.4.5', False),
('3.4.5.6', True, '\x00\x01\x02\xFF'),
],
},
pureldap.LDAPBERDecoderContext_TopLevel(
inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()))),
[0x30, 59]
# id
+ [0x02, 0x01, 42]
# value
+ l(str(pureldap.LDAPBindRequest()))
# controls
+ l(str(pureldap.LDAPControls(value=[
pureldap.LDAPControl(controlType='1.2.3.4'),
pureldap.LDAPControl(controlType='2.3.4.5',
criticality=False),
pureldap.LDAPControl(controlType='3.4.5.6',
criticality=True,
controlValue='\x00\x01\x02\xFF'),
]))),
),
(pureldap.LDAPFilter_equalityMatch,
[],
{'attributeDesc': pureldap.LDAPAttributeDescription('cn'),
'assertionValue': pureldap.LDAPAssertionValue('foo'),
},
pureldap.LDAPBERDecoderContext_Filter(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())),
[0xa3, 9]
+ ([0x04, 2] + l('cn')
+ [0x04, 3] + l('foo'))
),
(pureldap.LDAPFilter_or,
[[pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('cn'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('uid'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('mail'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_substrings(type='mail', substrings=[pureldap.LDAPFilter_substrings_initial('foo@')]),
]],
{},
pureldap.LDAPBERDecoderContext_Filter(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())),
[0xA1, 52]
+ ([0xa3, 9]
+ ([0x04, 2] + l('cn')
+ [0x04, 3] + l('foo'))
+ [0xa3, 10]
+ ([0x04, 3] + l('uid')
+ [0x04, 3] + l('foo'))
+ [0xa3, 11]
+ ([0x04, 4] + l('mail')
+ [0x04, 3] + l('foo'))
+ [0xa4, 14]
+ ([0x04, 4] + l('mail')
+ [0x30, 6]
+ ([0x80, 4] + l('foo@'))))
),
(pureldap.LDAPSearchRequest,
[],
{'baseObject': 'dc=example,dc=com',
'scope': pureldap.LDAP_SCOPE_wholeSubtree,
'derefAliases': pureldap.LDAP_DEREF_neverDerefAliases,
'sizeLimit': 1,
'timeLimit': 0,
'typesOnly': False,
'filter': pureldap.LDAPFilter_or([
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('cn'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('uid'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('mail'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_substrings(type='mail', substrings=[pureldap.LDAPFilter_substrings_initial('foo@')]),
]),
'attributes': [''],
},
pureldap.LDAPBERDecoderContext_LDAPMessage(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())),
[0x63, 92]
+ ([0x04, 17] + l('dc=example,dc=com')
+ [0x0a, 1, 0x02]
+ [0x0a, 1, 0x00]
+ [0x02, 1, 0x01]
+ [0x02, 1, 0x00]
+ [0x01, 1, 0x00]
+ [0xA1, 52]
+ ([0xa3, 9]
+ ([0x04, 2] + l('cn')
+ [0x04, 3] + l('foo'))
+ [0xa3, 10]
+ ([0x04, 3] + l('uid')
+ [0x04, 3] + l('foo'))
+ [0xa3, 11]
+ ([0x04, 4] + l('mail')
+ [0x04, 3] + l('foo'))
+ [0xa4, 14]
+ ([0x04, 4] + l('mail')
+ [0x30, 6]
+ ([0x80, 4] + l('foo@'))))
+ [0x30, 2]
+ ([0x04, 0])
)
),
(pureldap.LDAPMessage,
[],
{'id': 1L,
'value': pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_wholeSubtree,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=1,
timeLimit=0,
typesOnly=False,
filter=pureldap.LDAPFilter_or([
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('cn'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('uid'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('mail'),
assertionValue=pureldap.LDAPAssertionValue('foo')),
pureldap.LDAPFilter_substrings(type='mail', substrings=[pureldap.LDAPFilter_substrings_initial('foo@')]),
]),
attributes=[''],
),
},
pureldap.LDAPBERDecoderContext_TopLevel(
inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()))),
[0x30, 97]
# id
+ [0x02, 1, 1]
# value
+ [0x63, 92]
+ ([0x04, 17] + l('dc=example,dc=com')
+ [0x0a, 1, 0x02]
+ [0x0a, 1, 0x00]
+ [0x02, 1, 0x01]
+ [0x02, 1, 0x00]
+ [0x01, 1, 0x00]
+ [0xA1, 52]
+ ([0xa3, 9]
+ ([0x04, 2] + l('cn')
+ [0x04, 3] + l('foo'))
+ [0xa3, 10]
+ ([0x04, 3] + l('uid')
+ [0x04, 3] + l('foo'))
+ [0xa3, 11]
+ ([0x04, 4] + l('mail')
+ [0x04, 3] + l('foo'))
+ [0xa4, 14]
+ ([0x04, 4] + l('mail')
+ [0x30, 6]
+ ([0x80, 4] + l('foo@'))))
+ [0x30, 2]
+ ([0x04, 0])
)
),
(pureldap.LDAPExtendedRequest,
[],
{'requestName': '42.42.42',
'requestValue': 'foo',
},
None,
[0x40|0x20|23, 1+1+8+1+1+3]
+ ([0x80|0]
+ [len('42.42.42')]
+ l('42.42.42'))
+ ([0x80|1]
+ [len('foo')]
+ l('foo'))
),
)
def testToLDAP(self):
"""str(LDAPClass(...)) should give known result with known input"""
for klass, args, kwargs, decoder, encoded in self.knownValues:
result = klass(*args, **kwargs)
result = str(result)
result = map(ord, result)
if result!=encoded:
raise AssertionError, \
"Class %s(*%s, **%s) doesn't encode properly: " \
"%s != %s" % (klass.__name__,
repr(args), repr(kwargs),
repr(result), repr(encoded))
def testFromLDAP(self):
"""LDAPClass(encoded="...") should give known result with known input"""
for klass, args, kwargs, decoder, encoded in self.knownValues:
if decoder is None:
decoder = pureldap.LDAPBERDecoderContext(
fallback=pureber.BERDecoderContext())
m=s(*encoded)
result, bytes = pureber.berDecodeObject(decoder, m)
self.assertEquals(bytes, len(m))
shouldBe = klass(*args, **kwargs)
#TODO shouldn't use str below
assert str(result)==str(shouldBe), \
"Class %s(*%s, **%s) doesn't decode properly: " \
"%s != %s" % (klass.__name__,
repr(args), repr(kwargs),
repr(result), repr(shouldBe))
def testPartial(self):
"""LDAPClass(encoded="...") with too short input should throw BERExceptionInsufficientData"""
for klass, args, kwargs, decoder, encoded in self.knownValues:
if decoder is None:
decoder = pureldap.LDAPBERDecoderContext(
fallback=pureber.BERDecoderContext())
for i in xrange(1, len(encoded)):
m=s(*encoded)[:i]
self.assertRaises(pureber.BERExceptionInsufficientData,
pureber.berDecodeObject,
decoder, m)
self.assertEquals((None, 0), pureber.berDecodeObject(decoder, ''))
class TestEquality(unittest.TestCase):
valuesToTest=(
(pureldap.LDAPFilter_equalityMatch,
[ pureldap.LDAPAttributeDescription(value='cn'),
pureldap.LDAPAssertionValue(value='foo'),
]),
(pureldap.LDAPFilter_equalityMatch,
[ pureldap.LDAPAttributeDescription(value='cn'),
pureldap.LDAPAssertionValue(value='bar'),
]),
(pureber.BERInteger, [0]),
)
def testEquality(self):
"""LDAP objects equal LDAP objects with same type and content"""
for class_, args in self.valuesToTest:
x=class_(*args)
y=class_(*args)
self.assertEquals(x, x)
self.assertEquals(x, y)
def testInEquality(self):
"""LDAP objects do not equal LDAP objects with different type or content"""
for i in xrange(len(self.valuesToTest)):
for j in xrange(len(self.valuesToTest)):
if i!=j:
i_class, i_args = self.valuesToTest[i]
j_class, j_args = self.valuesToTest[j]
x=i_class(*i_args)
y=j_class(*j_args)
self.assertNotEquals(x, y)
class Substrings(unittest.TestCase):
def test_length(self):
"""LDAPFilter_substrings.substrings behaves like a proper list."""
decoder = pureldap.LDAPBERDecoderContext(
fallback=pureber.BERDecoderContext())
filt = pureldap.LDAPFilter_substrings.fromBER(
tag=pureldap.LDAPFilter_substrings.tag,
content=s(0x04, 4, 'mail',
0x30, 6,
0x80, 4, 'foo@'),
berdecoder=decoder)
# The confusion that used to occur here was because
# filt.substrings was left as a BERSequence, which under the
# current str()-to-wire-protocol system had len() > 1 even
# when empty, and that tripped e.g. entry.match()
self.assertEquals(len(filt.substrings), 1)
ldaptor-0.0.43/ldaptor/test/test_webui.py 0000644 0001750 0001750 00000043045 10402650176 016524 0 ustar jan jan from twisted.trial import unittest
import urllib, string
from twisted.internet import address, protocol, defer
from twisted.python import components
from twisted.web import microdom
from nevow import appserver, tags
from webut.skin import skin
from ldaptor import inmemory, interfaces, config
from ldaptor.protocols.ldap import ldapserver
from ldaptor.apps.webui import main, defskin
from ldaptor.test import mockweb, util
def getTextContents(node):
s=u''
for text in node.childNodes:
assert (isinstance(text, microdom.Text)
or isinstance(text, microdom.EntityReference))
if isinstance(text, microdom.Text):
s += text.toxml()
elif isinstance(text, microdom.EntityReference):
if text.eref.startswith('#x'):
n = int(text.eref[len('#x'):], 16)
s += unichr(n)
else:
s += text.toxml()
else:
raise RuntimeError, 'TODO'
return s
class MockLDAPConfig(config.LDAPConfig):
def _loadServiceLocationOverrides(self):
return {}
class SiteMixin:
def setUp(self):
db = inmemory.ReadOnlyInMemoryLDAPEntry('')
db.addChild('cn=schema',
{'objectClass': ['TODO'],
'cn': ['schema'],
'attributeTypes': [
"""( 0.9.2342.19200300.100.1.25
NAME ( 'dc' 'domainComponent' )
DESC 'RFC1274/2247: domain component'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )""",
"""( 2.5.4.0 NAME 'objectClass'
DESC 'RFC2256: object classes of the entity'
EQUALITY objectIdentifierMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )""",
"""( 2.5.4.4 NAME ( 'sn' 'surname' )
DESC 'RFC2256: last (family) name(s) for which the entity is known by'
SUP name )""",
"""( 2.5.4.3 NAME ( 'cn' 'commonName' )
DESC 'RFC2256: common name(s) for which the entity is known by'
SUP name )""",
"""( 2.5.4.35 NAME 'userPassword'
DESC 'RFC2256/2307: password of user'
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )""",
"""( 2.5.4.20 NAME 'telephoneNumber'
DESC 'RFC2256: Telephone Number'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )""",
"""( 2.5.4.34 NAME 'seeAlso'
DESC 'RFC2256: DN of related object'
SUP distinguishedName )""",
"""( 2.5.4.13 NAME 'description'
DESC 'RFC2256: descriptive information'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )""",
],
'objectClasses': [
"""( 2.5.6.0 NAME 'top'
DESC 'top of the superclass chain'
ABSTRACT
MUST objectClass )""",
"""( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
DESC 'RFC2247: domain component object'
SUP top AUXILIARY MUST dc )""",
"""( 2.5.6.6 NAME 'person'
DESC 'RFC2256: a person'
SUP top
STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )""",
],
})
self.com = db.addChild('dc=com', {})
self.example = self.com.addChild('dc=example',
{'objectClass': ['dcObject'],
'dc': ['example'],
'subschemaSubentry': ['cn=schema'],
})
self.foo = self.example.addChild('uid=foo',
{'objectClass': ['person'],
'uid': ['foo'],
'cn': ['Foo Bar'],
'sn': ['Bar'],
'userPassword': ['{SSHA}1feEJLgP7OB5mUKU/fYJzBoAGlOrze8='], # "foo"
'subschemaSubentry': ['cn=schema'],
})
class LDAPServerFactory(protocol.ServerFactory):
protocol = ldapserver.LDAPServer
def __init__(self, root):
self.root = root
components.registerAdapter(lambda x: x.root,
LDAPServerFactory,
interfaces.IConnectedLDAPEntry)
serverFactory = LDAPServerFactory(db)
def _doConnect(factory):
factory.doStart()
client = factory.buildProtocol(address.IPv4Address('TCP', 'localhost', '389'))
server = serverFactory.buildProtocol(address.IPv4Address('TCP', 'localhost', '1024'))
util.returnConnected(server, client)
cfg = MockLDAPConfig(baseDN='dc=example,dc=com',
serviceLocationOverrides={'': _doConnect},
identityBaseDN='dc=example,dc=com',)
class TestSkin(defskin.DefaultSkin):
def render_head(self, ctx, data):
d = defer.maybeDeferred(super(TestSkin, self).render_head, ctx, data)
def cb(stan):
return stan[tags.comment['kilroy was here']]
d.addCallback(cb)
return d
self.root = main.getResource(cfg, skinFactory=TestSkin)
self.site = appserver.NevowSite(self.root)
self.site.startFactory()
def tearDown(self):
assert isinstance(self.root, skin.Skinner)
for name, sess in self.root.resource.sessions.items():
sess.expire()
self.site.stopFactory()
def getPage(self, url, cookies, *a, **kw):
parse = kw.pop('parse', True)
if cookies:
getter = mockweb.getPage
else:
getter = mockweb.getPage_noCookies
kw['extraInfo'] = True
d = getter(self.site, url, *a, **kw)
data = util.pumpingDeferredResult(d)
if parse:
tree = microdom.parseString(data['page'], beExtremelyLenient=True)
assert 'tree' not in data
data['tree'] = tree
title = data['tree'].getElementsByTagName('title')[0]
assert 'title' not in data
data['title'] = getTextContents(title)
return data
class TestCSS(SiteMixin, unittest.TestCase):
urls = [
'http://localhost/',
'http://localhost/dc=example,dc=com/',
'http://localhost/dc=example,dc=com/search',
'http://localhost/dc=example,dc=com/search/',
'http://localhost/dc=example,dc=com/edit/', # to test login
]
def _checkResults(self, data, cookies):
# while we're here, make sure the skin system seems to work
self.assertIn('', data['page'])
self.assertNotIn('Title Goes Here', data['page'])
head = data['tree'].getElementsByTagName('head')
assert len(head) == 1, \
"Expected exactly one element, got %r" % head
links = head[0].getElementsByTagName('link')
for link in links:
if link.getAttribute('rel') == 'stylesheet':
href = link.getAttribute('href')
u = data['url'].clear().click(href)
self.assertEquals(u.scheme, 'http')
self.assertEquals(u.netloc, 'localhost')
self.assertEquals(u.queryList(), [])
l = u.pathList()
self.failUnless(l[-1].endswith('.css'),
"url %s has invalid CSS extension" % data['url'])
basename = l[-1][:-len('.css')]
self.failUnless(len(basename) >= 1)
for c in basename:
self.failUnless(c in string.ascii_lowercase, "url %s has invalid character %r in CSS reference %r" % (data['url'], c, l[-1]))
cssData = self.getPage(u, cookies,
followRedirect=False,
parse=False)
self.assertEquals(cssData['status'], '200',
"CSS files must not be without a guard session")
def checkPage(self, url, cookies):
data = self.getPage(url, cookies)
self._checkResults(data, cookies)
def test_form_css(self):
for u in self.urls:
self.checkPage(u, cookies=True)
def test_form_css_noCookies(self):
for u in self.urls:
self.checkPage(u, cookies=False)
class TestAuthenticatedCSS(TestCSS):
urls = [
'http://localhost/dc=example,dc=com/edit',
'http://localhost/dc=example,dc=com/edit/',
'http://localhost/dc=example,dc=com/edit/uid=foo,dc=example,dc=com',
'http://localhost/dc=example,dc=com/add',
'http://localhost/dc=example,dc=com/add/',
'http://localhost/dc=example,dc=com/add/manual/dcObject',
'http://localhost/dc=example,dc=com/change_password',
'http://localhost/dc=example,dc=com/change_password/',
'http://localhost/dc=example,dc=com/change_password/uid=foo,dc=example,dc=com',
'http://localhost/dc=example,dc=com/mass_change_password',
'http://localhost/dc=example,dc=com/mass_change_password/',
'http://localhost/dc=example,dc=com/mass_change_password/(uid=foo)',
'http://localhost/dc=example,dc=com/delete',
'http://localhost/dc=example,dc=com/delete/',
'http://localhost/dc=example,dc=com/delete/uid=foo,dc=example,dc=com',
'http://localhost/dc=example,dc=com/move',
'http://localhost/dc=example,dc=com/move/',
'http://localhost/dc=example,dc=com/move/uid=foo,dc=example,dc=com',
]
def checkPage(self, url, cookies):
data = self.getPage(url, cookies)
self.assertEquals(data['title'], 'Login')
# fill form, submit
forms = data['tree'].getElementsByTagName('form')
self.assertEquals(len(forms), 1)
form = forms[0]
self.assertEquals(form.getAttribute('enctype', 'application/x-www-form-urlencoded'),
'application/x-www-form-urlencoded')
data = self.getPage(data['url'].clear().click(form.getAttribute('action')),
cookies,
method=form.getAttribute('method', 'get').upper(),
headers={'Content-Type': 'application/x-www-form-urlencoded'},
postdata='&'.join(['%s=%s' % (urllib.quote('username'),
urllib.quote('foo')),
'%s=%s' % (urllib.quote('password'),
urllib.quote('foo')),
]),
)
self._checkResults(data, cookies)
class TestAuthentication(SiteMixin, unittest.TestCase):
def test_ensureBind(self):
self.failUnless(self.foo.bind('foo'))
def checkPage(self, url, cookies):
data = self.getPage(url, cookies)
self.assertEquals(data['title'], 'Login')
# fill form, submit
forms = data['tree'].getElementsByTagName('form')
self.assertEquals(len(forms), 1)
form = forms[0]
self.assertEquals(form.getAttribute('enctype', 'application/x-www-form-urlencoded'),
'application/x-www-form-urlencoded')
data = self.getPage(data['url'].clear().click(form.getAttribute('action')),
cookies,
method=form.getAttribute('method', 'get').upper(),
headers={'Content-Type': 'application/x-www-form-urlencoded'},
postdata='&'.join(['%s=%s' % (urllib.quote('username'),
urllib.quote('foo')),
'%s=%s' % (urllib.quote('password'),
urllib.quote('foo')),
]),
)
return data
def test_edit(self):
data = self.checkPage('http://localhost/dc=example,dc=com/edit/dc=example,dc=com', cookies=True)
self.assertEquals(data['title'], u'Ldaptor Edit Page')
def test_edit_noCookies(self):
data = self.checkPage('http://localhost/dc=example,dc=com/edit/dc=example,dc=com', cookies=False)
self.assertEquals(data['title'], u'Ldaptor Edit Page')
def test_move(self):
data = self.checkPage('http://localhost/dc=example,dc=com/move', cookies=True)
self.assertEquals(data['title'], u'Ldaptor Move Page')
def test_move_noCookies(self):
data = self.checkPage('http://localhost/dc=example,dc=com/move', cookies=False)
self.assertEquals(data['title'], u'Ldaptor Move Page')
def test_add(self):
data = self.checkPage('http://localhost/dc=example,dc=com/add', cookies=True)
self.assertEquals(data['title'], u'Ldaptor Add Page')
def test_add_noCookies(self):
data = self.checkPage('http://localhost/dc=example,dc=com/add', cookies=False)
self.assertEquals(data['title'], u'Ldaptor Add Page')
def test_delete(self):
data = self.checkPage('http://localhost/dc=example,dc=com/delete/dc=example,dc=com', cookies=True)
self.assertEquals(data['title'], u'Ldaptor Delete Page')
def test_delete_noCookies(self):
data = self.checkPage('http://localhost/dc=example,dc=com/delete/dc=example,dc=com', cookies=False)
self.assertEquals(data['title'], u'Ldaptor Delete Page')
def test_mass_change_password(self):
data = self.checkPage('http://localhost/dc=example,dc=com/mass_change_password', cookies=True)
self.assertEquals(data['title'], u'Ldaptor Mass Password Change Page')
def test_mass_change_password_noCookies(self):
data = self.checkPage('http://localhost/dc=example,dc=com/mass_change_password', cookies=False)
self.assertEquals(data['title'], u'Ldaptor Mass Password Change Page')
def test_change_password(self):
data = self.checkPage('http://localhost/dc=example,dc=com/change_password', cookies=True)
self.assertEquals(data['title'], u'Ldaptor Password Change Page')
def test_change_password_noCookies(self):
data = self.checkPage('http://localhost/dc=example,dc=com/change_password', cookies=False)
self.assertEquals(data['title'], u'Ldaptor Password Change Page')
class TestDelete(SiteMixin, unittest.TestCase):
def checkPage(self, url, cookies):
data = self.getPage(url, cookies)
self.assertEquals(data['title'], 'Login')
# fill form, submit
forms = data['tree'].getElementsByTagName('form')
self.assertEquals(len(forms), 1)
form = forms[0]
self.assertEquals(form.getAttribute('enctype', 'application/x-www-form-urlencoded'),
'application/x-www-form-urlencoded')
data = self.getPage(data['url'].clear().click(form.getAttribute('action')),
cookies,
method=form.getAttribute('method', 'get').upper(),
headers={'Content-Type': 'application/x-www-form-urlencoded'},
postdata='&'.join(['%s=%s' % (urllib.quote('username'),
urllib.quote('foo')),
'%s=%s' % (urllib.quote('password'),
urllib.quote('foo')),
]),
)
return data
def test_nonExisting(self):
data = self.checkPage('http://localhost/dc=example,dc=com/delete/uid=bar,dc=example,dc=com', cookies=True)
self.assertEquals(data['title'], u'Ldaptor Delete Page')
self.failUnless('An error occurred' in data['page'])
self.failUnless('noSuchObject' in data['page'])
def test_existing(self):
# TODO cookies don't work because there's nothing that would carry over their state
data = self.checkPage('http://localhost/dc=example,dc=com/delete/uid=foo,dc=example,dc=com', cookies=False)
self.assertEquals(data['title'], u'Ldaptor Delete Page')
self.failUnless('
Remove uid=foo,dc=example,dc=com?
' in data['page'])
# fill form, submit
forms = data['tree'].getElementsByTagName('form')
self.assertEquals(len(forms), 1)
form = forms[0]
# TODO support multipart/form-data, that's what the form tells us to use
## self.assertEquals(form.getAttribute('enctype', 'application/x-www-form-urlencoded'),
## 'application/x-www-form-urlencoded')
action = data['url'].clear().click(form.getAttribute('action'))
data = self.getPage(action,
cookies=False,
method=form.getAttribute('method', 'get').upper(),
headers={'Content-Type': 'application/x-www-form-urlencoded'},
)
self.assertEquals(data['title'], 'Ldaptor Search Page')
self.failUnless('Deleted uid=foo,dc=example,dc=com.' in data['page'])
d = self.example.children()
children = util.pumpingDeferredResult(d)
self.assertEquals(children, [])
ldaptor-0.0.43/ldaptor/test/test_fetchschema.py 0000644 0001750 0001750 00000005302 10345261504 017654 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.fetchschema module.
"""
from twisted.trial import unittest
from ldaptor.protocols.ldap import fetchschema
from ldaptor import schema
from ldaptor.protocols import pureldap
from ldaptor.testutil import LDAPClientTestDriver
class OnWire(unittest.TestCase):
cn = """( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by' SUP name )"""
dcObject = """( 1.3.6.1.4.1.1466.344 NAME 'dcObject' DESC 'RFC2247: domain component object' SUP top AUXILIARY MUST dc )"""
def testSimple(self):
client=LDAPClientTestDriver([
pureldap.LDAPSearchResultEntry(
objectName='',
attributes=(('subschemaSubentry', ['cn=Subschema']),
('bar', ['b', 'c']),
),
),
pureldap.LDAPSearchResultDone(
resultCode=0,
matchedDN='',
errorMessage='')
],
[
pureldap.LDAPSearchResultEntry(
objectName='cn=Subschema',
attributes=(('attributeTypes', [ self.cn ]),
('objectClasses', [ self.dcObject ]),
),
),
pureldap.LDAPSearchResultDone(
resultCode=0,
matchedDN='',
errorMessage='')
],
)
d=fetchschema.fetch(client, 'dc=example,dc=com')
d.addCallback(self._cb_testSimple, client)
return d
def _cb_testSimple(self, val, client):
client.assertSent(pureldap.LDAPSearchRequest(
baseObject='dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=1,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilter_present('objectClass'),
attributes=['subschemaSubentry']),
pureldap.LDAPSearchRequest(
baseObject='cn=Subschema',
scope=pureldap.LDAP_SCOPE_baseObject,
derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
sizeLimit=1,
timeLimit=0,
typesOnly=0,
filter=pureldap.LDAPFilter_present('objectClass'),
attributes=['attributeTypes', 'objectClasses']),
)
self.failUnlessEqual(len(val), 2)
self.failUnlessEqual([str(x) for x in val[0]],
[str(schema.AttributeTypeDescription(self.cn))])
self.failUnlessEqual([str(x) for x in val[1]],
[str(schema.ObjectClassDescription(self.dcObject))])
ldaptor-0.0.43/ldaptor/test/ldif/ 0000755 0001750 0001750 00000000000 10403234303 014677 5 ustar jan jan ldaptor-0.0.43/ldaptor/test/ldif/webtests/ 0000755 0001750 0001750 00000000000 10403234304 016540 5 ustar jan jan ldaptor-0.0.43/ldaptor/test/ldif/webtests/cn=Subschema.ldif 0000644 0001750 0001750 00000120224 10345773672 021756 0 ustar jan jan # TODO must only be found with
# ldapsearch -x -b cn=Subschema -s base '(objectClass=subschema)' attributeTypes
# TODO provide createTimestamp modifyTimestamp
dn: cn=Subschema
objectClass: top
objectClass: subschema
attributeTypes: ( 2.16.840.1.113730.3.1.216 NAME 'userPKCS12' DESC 'RFC2798: p
ersonal identity information, a PKCS #12 PFX' SYNTAX 1.3.6.1.4.1.1466.115.121
.1.5 )
attributeTypes: ( 2.16.840.1.113730.3.1.40 NAME 'userSMIMECertificate' DESC 'R
FC2798: PKCS#7 SignedData used to support S/MIME' SYNTAX 1.3.6.1.4.1.1466.115
.121.1.5 )
attributeTypes: ( 2.16.840.1.113730.3.1.39 NAME 'preferredLanguage' DESC 'RFC2
798: preferred written or spoken language for a person' EQUALITY caseIgnoreMa
tch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SIN
GLE-VALUE )
attributeTypes: ( 0.9.2342.19200300.100.1.60 NAME 'jpegPhoto' DESC 'RFC2798: a
JPEG image' SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )
attributeTypes: ( 2.16.840.1.113730.3.1.4 NAME 'employeeType' DESC 'RFC2798: t
ype of employment for a person' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSub
stringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
attributeTypes: ( 2.16.840.1.113730.3.1.3 NAME 'employeeNumber' DESC 'RFC2798:
numerically identifies an employee within an organization' EQUALITY caseIgno
reMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
attributeTypes: ( 2.16.840.1.113730.3.1.241 NAME 'displayName' DESC 'RFC2798:
preferred name to be used when displaying entries' EQUALITY caseIgnoreMatch S
UBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-V
ALUE )
attributeTypes: ( 2.16.840.1.113730.3.1.2 NAME 'departmentNumber' DESC 'RFC279
8: identifies a department within an organization' EQUALITY caseIgnoreMatch S
UBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
attributeTypes: ( 2.16.840.1.113730.3.1.1 NAME 'carLicense' DESC 'RFC2798: veh
icle license or registration plate' EQUALITY caseIgnoreMatch SUBSTR caseIgnor
eSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
attributeTypes: ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry' EQUALITY caseExactIA5Mat
ch SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{10
24} SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.26 NAME 'nisMapName' SUP name )
attributeTypes: ( 1.3.6.1.1.1.1.24 NAME 'bootFile' DESC 'Boot image name' EQUA
LITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 1.3.6.1.1.1.1.23 NAME 'bootParameter' DESC 'rpc.bootparamd p
arameter' SYNTAX 1.3.6.1.1.1.0.1 )
attributeTypes: ( 1.3.6.1.1.1.1.22 NAME 'macAddress' DESC 'MAC address' EQUALI
TY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
attributeTypes: ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber' DESC 'IP netmask' EQ
UALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VA
LUE )
attributeTypes: ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber' DESC 'IP network' EQ
UALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VA
LUE )
attributeTypes: ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber' DESC 'IP address' EQUAL
ITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
attributeTypes: ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber' EQUALITY integerMatch S
YNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber' EQUALITY integerMat
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol' SUP name )
attributeTypes: ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort' EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple' DESC 'Netgroup tri
ple' SYNTAX 1.3.6.1.1.1.0.0 )
attributeTypes: ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup' EQUALITY caseExact
IA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
.26 )
attributeTypes: ( 1.3.6.1.1.1.1.12 NAME 'memberUid' EQUALITY caseExactIA5Match
SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag' EQUALITY integerMatch SYN
TAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire' EQUALITY integerMatch S
YNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive' EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning' EQUALITY integerMatch S
YNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.7 NAME 'shadowMax' EQUALITY integerMatch SYNTA
X 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.6 NAME 'shadowMin' EQUALITY integerMatch SYNTA
X 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange' EQUALITY integerMatc
h SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.4 NAME 'loginShell' DESC 'The path to the logi
n shell' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SING
LE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory' DESC 'The absolute path
to the home directory' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.11
5.121.1.26 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.2 NAME 'gecos' DESC 'The GECOS field; the comm
on name' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNT
AX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.1 NAME 'gidNumber' DESC 'An integer uniquely i
dentifying a group in an administrative domain' EQUALITY integerMatch SYNTAX
1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.1.1.1.0 NAME 'uidNumber' DESC 'An integer uniquely i
dentifying a user in an administrative domain' EQUALITY integerMatch SYNTAX 1
.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributeTypes: ( 0.9.2342.19200300.100.1.56 NAME 'documentPublisher' DESC 'RF
C1274: publisher of document' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubst
ringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
attributeTypes: ( 0.9.2342.19200300.100.1.55 NAME 'audio' DESC 'RFC1274: audio
(u-law)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.4{25000} )
attributeTypes: ( 0.9.2342.19200300.100.1.54 NAME 'dITRedirect' DESC 'RFC1274:
DIT Redirect' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.12
1.1.12 )
attributeTypes: ( 0.9.2342.19200300.100.1.53 NAME 'personalSignature' DESC 'RF
C1274: Personal Signature (G3 fax)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.23 )
attributeTypes: ( 0.9.2342.19200300.100.1.52 NAME 'subtreeMaximumQuality' DESC
'RFC1274: Subtree Maximun Quality' SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SING
LE-VALUE )
attributeTypes: ( 0.9.2342.19200300.100.1.51 NAME 'subtreeMinimumQuality' DESC
'RFC1274: Subtree Mininum Quality' SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SING
LE-VALUE )
attributeTypes: ( 0.9.2342.19200300.100.1.50 NAME 'singleLevelQuality' DESC 'R
FC1274: Single Level Quality' SYNTAX 1.3.6.1.4.1.1466.115.121.1.13 SINGLE-VAL
UE )
attributeTypes: ( 0.9.2342.19200300.100.1.49 NAME 'dSAQuality' DESC 'RFC1274:
DSA Quality' SYNTAX 1.3.6.1.4.1.1466.115.121.1.19 SINGLE-VALUE )
attributeTypes: ( 0.9.2342.19200300.100.1.48 NAME 'buildingName' DESC 'RFC1274
: name of building' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.47 NAME 'mailPreferenceOption' DESC
'RFC1274: mail preference option' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
attributeTypes: ( 0.9.2342.19200300.100.1.46 NAME 'janetMailbox' DESC 'RFC1274
: Janet mailbox' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMa
tch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.45 NAME 'organizationalStatus' DESC
'RFC1274: organizational status' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSu
bstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.44 NAME 'uniqueIdentifier' DESC 'RFC
1274: unique identifer' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.
121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.43 NAME ( 'co' 'friendlyCountryName'
) DESC 'RFC1274: friendly country name' EQUALITY caseIgnoreMatch SUBSTR case
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
attributeTypes: ( 0.9.2342.19200300.100.1.42 NAME ( 'pager' 'pagerTelephoneNum
ber' ) DESC 'RFC1274: pager telephone number' EQUALITY telephoneNumberMatch S
UBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributeTypes: ( 0.9.2342.19200300.100.1.41 NAME ( 'mobile' 'mobileTelephoneN
umber' ) DESC 'RFC1274: mobile telephone number' EQUALITY telephoneNumberMatc
h SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.50
)
attributeTypes: ( 0.9.2342.19200300.100.1.40 NAME 'personalTitle' DESC 'RFC127
4: personal title' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.39 NAME 'homePostalAddress' DESC 'RF
C1274: home postal address' EQUALITY caseIgnoreListMatch SUBSTR caseIgnoreLis
tSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributeTypes: ( 0.9.2342.19200300.100.1.38 NAME 'associatedName' DESC 'RFC12
74: DN of entry associated with domain' EQUALITY distinguishedNameMatch SYNTA
X 1.3.6.1.4.1.1466.115.121.1.12 )
attributeTypes: ( 0.9.2342.19200300.100.1.31 NAME 'cNAMERecord' EQUALITY caseI
gnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 0.9.2342.19200300.100.1.30 NAME 'sOARecord' EQUALITY caseIgn
oreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 0.9.2342.19200300.100.1.29 NAME 'nSRecord' EQUALITY caseIgno
reIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 0.9.2342.19200300.100.1.28 NAME 'mXRecord' EQUALITY caseIgno
reIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 0.9.2342.19200300.100.1.27 NAME 'mDRecord' EQUALITY caseIgno
reIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 0.9.2342.19200300.100.1.26 NAME 'aRecord' EQUALITY caseIgnor
eIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 0.9.2342.19200300.100.1.22 NAME 'otherMailbox' SYNTAX 1.3.6.
1.4.1.1466.115.121.1.39 )
attributeTypes: ( 0.9.2342.19200300.100.1.21 NAME 'secretary' DESC 'RFC1274: D
N of secretary' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.1
21.1.12 )
attributeTypes: ( 0.9.2342.19200300.100.1.20 NAME ( 'homePhone' 'homeTelephone
Number' ) DESC 'RFC1274: home telephone number' EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
attributeTypes: ( 0.9.2342.19200300.100.1.15 NAME 'documentLocation' DESC 'RFC
1274: location of document original' EQUALITY caseIgnoreMatch SUBSTR caseIgno
reSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.14 NAME 'documentAuthor' DESC 'RFC12
74: DN of author of document' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.
4.1.1466.115.121.1.12 )
attributeTypes: ( 0.9.2342.19200300.100.1.13 NAME 'documentVersion' DESC 'RFC1
274: version of document' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstring
sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.12 NAME 'documentTitle' DESC 'RFC127
4: title of document' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.11 NAME 'documentIdentifier' DESC 'R
FC1274: unique identifier of document' EQUALITY caseIgnoreMatch SUBSTR caseIg
noreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.10 NAME 'manager' DESC 'RFC1274: DN
of manager' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
.12 )
attributeTypes: ( 0.9.2342.19200300.100.1.9 NAME 'host' DESC 'RFC1274: host co
mputer' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.
6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.8 NAME 'userClass' DESC 'RFC1274: ca
tegory of user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYN
TAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.7 NAME 'photo' DESC 'RFC1274: photo
(G3 fax)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.23{25000} )
attributeTypes: ( 0.9.2342.19200300.100.1.6 NAME 'roomNumber' DESC 'RFC1274: r
oom number' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.5 NAME ( 'drink' 'favouriteDrink' )
DESC 'RFC1274: favorite drink' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubs
tringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.4 NAME 'info' DESC 'RFC1274: general
information' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTA
X 1.3.6.1.4.1.1466.115.121.1.15{2048} )
attributeTypes: ( 0.9.2342.19200300.100.1.2 NAME 'textEncodedORAddress' EQUALI
TY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.1
15.121.1.15{256} )
attributeTypes: ( 1.2.840.113549.1.9.1 NAME ( 'email' 'emailAddress' 'pkcs9ema
il' ) DESC 'RFC2459: legacy attribute for email addresses in DNs' EQUALITY ca
seIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.
115.121.1.26{128} )
attributeTypes: ( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain' DESC 'RFC
1274: domain associated with object' EQUALITY caseIgnoreIA5Match SUBSTR caseI
gnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domainComponent' ) D
ESC 'RFC1274/2247: domain component' EQUALITY caseIgnoreIA5Match SUBSTR caseI
gnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
attributeTypes: ( 0.9.2342.19200300.100.1.3 NAME ( 'mail' 'rfc822Mailbox' ) DE
SC 'RFC1274: RFC822 Mailbox' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5
SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
attributeTypes: ( 0.9.2342.19200300.100.1.1 NAME ( 'uid' 'userid' ) DESC 'RFC1
274: user identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributeTypes: ( 2.5.4.54 NAME 'dmdName' DESC 'RFC2256: name of DMD' SUP name
)
attributeTypes: ( 2.5.4.53 NAME 'deltaRevocationList' DESC 'RFC2256: delta rev
ocation list; use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
attributeTypes: ( 2.5.4.52 NAME 'supportedAlgorithms' DESC 'RFC2256: supported
algorithms' SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
attributeTypes: ( 2.5.4.51 NAME 'houseIdentifier' DESC 'RFC2256: house identif
ier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1
.4.1.1466.115.121.1.15{32768} )
attributeTypes: ( 2.5.4.50 NAME 'uniqueMember' DESC 'RFC2256: unique member of
a group' EQUALITY uniqueMemberMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )
attributeTypes: ( 2.5.4.48 NAME 'protocolInformation' DESC 'RFC2256: protocol
information' EQUALITY protocolInformationMatch SYNTAX 1.3.6.1.4.1.1466.115.12
1.1.42 )
attributeTypes: ( 2.5.4.47 NAME 'enhancedSearchGuide' DESC 'RFC2256: enhanced
search guide' SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
attributeTypes: ( 2.5.4.46 NAME 'dnQualifier' DESC 'RFC2256: DN qualifier' EQU
ALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubst
ringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
attributeTypes: ( 2.5.4.45 NAME 'x500UniqueIdentifier' DESC 'RFC2256: X.500 un
ique identifier' EQUALITY bitStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.6
)
attributeTypes: ( 2.5.4.44 NAME 'generationQualifier' DESC 'RFC2256: name qual
ifier indicating a generation' SUP name )
attributeTypes: ( 2.5.4.43 NAME 'initials' DESC 'RFC2256: initials of some or
all of names, but not the surname(s).' SUP name )
attributeTypes: ( 2.5.4.42 NAME ( 'givenName' 'gn' ) DESC 'RFC2256: first name
(s) for which the entity is known by' SUP name )
attributeTypes: ( 2.5.4.40 NAME 'crossCertificatePair' DESC 'RFC2256: X.509 cr
oss certificate pair, use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )
attributeTypes: ( 2.5.4.39 NAME 'certificateRevocationList' DESC 'RFC2256: X.5
09 certificate revocation list, use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121.
1.9 )
attributeTypes: ( 2.5.4.38 NAME 'authorityRevocationList' DESC 'RFC2256: X.509
authority revocation list, use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121.1.9
)
attributeTypes: ( 2.5.4.37 NAME 'cACertificate' DESC 'RFC2256: X.509 CA certif
icate, use ;binary' EQUALITY certificateExactMatch SYNTAX 1.3.6.1.4.1.1466.11
5.121.1.8 )
attributeTypes: ( 2.5.4.36 NAME 'userCertificate' DESC 'RFC2256: X.509 user ce
rtificate, use ;binary' EQUALITY certificateExactMatch SYNTAX 1.3.6.1.4.1.146
6.115.121.1.8 )
attributeTypes: ( 2.5.4.34 NAME 'seeAlso' DESC 'RFC2256: DN of related object'
SUP distinguishedName )
attributeTypes: ( 2.5.4.33 NAME 'roleOccupant' DESC 'RFC2256: occupant of role
' SUP distinguishedName )
attributeTypes: ( 2.5.4.32 NAME 'owner' DESC 'RFC2256: owner (of the object)'
SUP distinguishedName )
attributeTypes: ( 2.5.4.31 NAME 'member' DESC 'RFC2256: member of a group' SUP
distinguishedName )
attributeTypes: ( 2.5.4.30 NAME 'supportedApplicationContext' DESC 'RFC2256: s
upported application context' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4
.1.1466.115.121.1.38 )
attributeTypes: ( 2.5.4.29 NAME 'presentationAddress' DESC 'RFC2256: presentat
ion address' EQUALITY presentationAddressMatch SYNTAX 1.3.6.1.4.1.1466.115.12
1.1.43 SINGLE-VALUE )
attributeTypes: ( 2.5.4.28 NAME 'preferredDeliveryMethod' DESC 'RFC2256: prefe
rred delivery method' SYNTAX 1.3.6.1.4.1.1466.115.121.1.14 SINGLE-VALUE )
attributeTypes: ( 2.5.4.27 NAME 'destinationIndicator' DESC 'RFC2256: destinat
ion indicator' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNT
AX 1.3.6.1.4.1.1466.115.121.1.44{128} )
attributeTypes: ( 2.5.4.26 NAME 'registeredAddress' DESC 'RFC2256: registered
postal address' SUP postalAddress SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributeTypes: ( 2.5.4.25 NAME 'internationaliSDNNumber' DESC 'RFC2256: inter
national ISDN number' EQUALITY numericStringMatch SUBSTR numericStringSubstri
ngsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
attributeTypes: ( 2.5.4.24 NAME 'x121Address' DESC 'RFC2256: X.121 Address' EQ
UALITY numericStringMatch SUBSTR numericStringSubstringsMatch SYNTAX 1.3.6.1.
4.1.1466.115.121.1.36{15} )
attributeTypes: ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' ) DESC 'RFC
2256: Facsimile (Fax) Telephone Number' SYNTAX 1.3.6.1.4.1.1466.115.121.1.22
)
attributeTypes: ( 2.5.4.22 NAME 'teletexTerminalIdentifier' DESC 'RFC2256: Tel
etex Terminal Identifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
attributeTypes: ( 2.5.4.21 NAME 'telexNumber' DESC 'RFC2256: Telex Number' SYN
TAX 1.3.6.1.4.1.1466.115.121.1.52 )
attributeTypes: ( 2.5.4.20 NAME 'telephoneNumber' DESC 'RFC2256: Telephone Num
ber' EQUALITY telephoneNumberMatch SUBSTR telephoneNumberSubstringsMatch SYNT
AX 1.3.6.1.4.1.1466.115.121.1.50{32} )
attributeTypes: ( 2.5.4.19 NAME 'physicalDeliveryOfficeName' DESC 'RFC2256: Ph
ysical Delivery Office Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstr
ingsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributeTypes: ( 2.5.4.18 NAME 'postOfficeBox' DESC 'RFC2256: Post Office Box
' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.
1.1466.115.121.1.15{40} )
attributeTypes: ( 2.5.4.17 NAME 'postalCode' DESC 'RFC2256: postal code' EQUAL
ITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.
115.121.1.15{40} )
attributeTypes: ( 2.5.4.16 NAME 'postalAddress' DESC 'RFC2256: postal address'
EQUALITY caseIgnoreListMatch SUBSTR caseIgnoreListSubstringsMatch SYNTAX 1.3
.6.1.4.1.1466.115.121.1.41 )
attributeTypes: ( 2.5.4.15 NAME 'businessCategory' DESC 'RFC2256: business cat
egory' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6
.1.4.1.1466.115.121.1.15{128} )
attributeTypes: ( 2.5.4.14 NAME 'searchGuide' DESC 'RFC2256: search guide, obs
oleted by enhancedSearchGuide' SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )
attributeTypes: ( 2.5.4.13 NAME 'description' DESC 'RFC2256: descriptive infor
mation' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.
6.1.4.1.1466.115.121.1.15{1024} )
attributeTypes: ( 2.5.4.12 NAME 'title' DESC 'RFC2256: title associated with t
he entity' SUP name )
attributeTypes: ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' ) DESC 'RFC225
6: organizational unit this object belongs to' SUP name )
attributeTypes: ( 2.5.4.10 NAME ( 'o' 'organizationName' ) DESC 'RFC2256: orga
nization this object belongs to' SUP name )
attributeTypes: ( 2.5.4.9 NAME ( 'street' 'streetAddress' ) DESC 'RFC2256: str
eet address of this object' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstri
ngsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributeTypes: ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' ) DESC 'RFC2256: s
tate or province which this object resides in' SUP name )
attributeTypes: ( 2.5.4.7 NAME ( 'l' 'localityName' ) DESC 'RFC2256: locality
which this object resides in' SUP name )
attributeTypes: ( 2.5.4.6 NAME ( 'c' 'countryName' ) DESC 'RFC2256: ISO-3166 c
ountry 2-letter code' SUP name SINGLE-VALUE )
attributeTypes: ( 2.5.4.5 NAME 'serialNumber' DESC 'RFC2256: serial number of
the entity' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
1.3.6.1.4.1.1466.115.121.1.44{64} )
attributeTypes: ( 2.5.4.4 NAME ( 'sn' 'surname' ) DESC 'RFC2256: last (family)
name(s) for which the entity is known by' SUP name )
attributeTypes: ( 2.5.4.2 NAME 'knowledgeInformation' DESC 'RFC2256: knowledge
information' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{3
2768} )
attributeTypes: ( 1.3.6.1.4.1.250.1.57 NAME 'labeledURI' DESC 'RFC2079: Unifor
m Resource Identifier with optional label' EQUALITY caseExactMatch SYNTAX 1.3
.6.1.4.1.1466.115.121.1.15 )
attributeTypes: ( 2.5.4.35 NAME 'userPassword' DESC 'RFC2256/2307: password of
user' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
attributeTypes: ( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common nam
e(s) for which the entity is known by' SUP name )
attributeTypes: ( 2.5.4.41 NAME 'name' DESC 'RFC2256: common supertype of name
attributes' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
1.3.6.1.4.1.1466.115.121.1.15{32768} )
attributeTypes: ( 2.5.4.49 NAME 'distinguishedName' DESC 'RFC2256: common supe
rtype of DN attributes' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.14
66.115.121.1.12 )
attributeTypes: ( 2.16.840.1.113730.3.1.34 NAME 'ref' DESC 'namedref: subordin
ate referral URL' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.1
5 USAGE distributedOperation )
attributeTypes: ( 2.5.4.1 NAME ( 'aliasedObjectName' 'aliasedEntryName' ) DESC
'RFC2256: name of aliased object' EQUALITY distinguishedNameMatch SYNTAX 1.3
.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes' DESC 'RFC225
2: LDAP syntaxes' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1
.4.1.1466.115.121.1.54 USAGE directoryOperation )
attributeTypes: ( 2.5.21.8 NAME 'matchingRuleUse' DESC 'RFC2252: matching rule
uses' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.1
15.121.1.31 USAGE directoryOperation )
attributeTypes: ( 2.5.21.6 NAME 'objectClasses' DESC 'RFC2252: object classes'
EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121
.1.37 USAGE directoryOperation )
attributeTypes: ( 2.5.21.5 NAME 'attributeTypes' DESC 'RFC2252: attribute type
s' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.1
21.1.3 USAGE directoryOperation )
attributeTypes: ( 2.5.21.4 NAME 'matchingRules' DESC 'RFC2252: matching rules'
EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121
.1.30 USAGE directoryOperation )
attributeTypes: ( 1.3.6.1.1.5 NAME 'vendorVersion' DESC 'RFC3045: version of i
mplementation' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 S
INGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )
attributeTypes: ( 1.3.6.1.1.4 NAME 'vendorName' DESC 'RFC3045: name of impleme
ntation vendor' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )
attributeTypes: ( 1.3.6.1.4.1.4203.1.3.5 NAME 'supportedFeatures' DESC 'featur
es supported by the server' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1
.1466.115.121.1.38 USAGE dSAOperation )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.14 NAME 'supportedSASLMechanisms' D
ESC 'RFC2252: supported SASL mechanisms' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
USAGE dSAOperation )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion' DESC
'RFC2252: supported LDAP versions' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAG
E dSAOperation )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.7 NAME 'supportedExtension' DESC 'R
FC2252: supported extended operations' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 U
SAGE dSAOperation )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.13 NAME 'supportedControl' DESC 'RF
C2252: supported controls' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOper
ation )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts' DESC 'RFC22
52: naming contexts' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation
)
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer' DESC 'RFC2252: a
lternative servers' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE dSAOperation )
attributeTypes: ( 2.5.18.10 NAME 'subschemaSubentry' DESC 'RFC2252: name of co
ntrolling subschema entry' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1
.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation
)
attributeTypes: ( 2.5.18.9 NAME 'hasSubordinates' DESC 'X.501: entry has child
ren' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE N
O-USER-MODIFICATION USAGE directoryOperation )
attributeTypes: ( 2.5.18.4 NAME 'modifiersName' DESC 'RFC2252: name of last mo
difier' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
attributeTypes: ( 2.5.18.3 NAME 'creatorsName' DESC 'RFC2252: name of creator'
EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-
VALUE NO-USER-MODIFICATION USAGE directoryOperation )
attributeTypes: ( 2.5.18.2 NAME 'modifyTimestamp' DESC 'RFC2252: time which ob
ject was last modified' EQUALITY generalizedTimeMatch ORDERING generalizedTim
eOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODI
FICATION USAGE directoryOperation )
attributeTypes: ( 2.5.18.1 NAME 'createTimestamp' DESC 'RFC2252: time which ob
ject was created' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrder
ingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATI
ON USAGE directoryOperation )
attributeTypes: ( 2.5.21.9 NAME 'structuralObjectClass' DESC 'X.500(93): struc
tural object class of entry' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.
1.1466.115.121.1.38 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperatio
n )
attributeTypes: ( 2.5.4.0 NAME 'objectClass' DESC 'RFC2256: object classes of
the entity' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.
38 )
objectClasses: ( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RFC2798: I
nternet Organizational Person' SUP organizationalPerson STRUCTURAL MAY ( audi
o $ businessCategory $ carLicense $ departmentNumber $ displayName $ employee
Number $ employeeType $ givenName $ homePhone $ homePostalAddress $ initials
$ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ o $ pager $ photo $ room
Number $ secretary $ uid $ userCertificate $ x500uniqueIdentifier $ preferred
Language $ userSMIMECertificate $ userPKCS12 ) )
objectClasses: ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' DESC 'A device with bo
ot parameters' SUP top AUXILIARY MAY ( bootFile $ bootParameter ) )
objectClasses: ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' DESC 'A device with a M
AC address' SUP top AUXILIARY MAY macAddress )
objectClasses: ( 1.3.6.1.1.1.2.10 NAME 'nisObject' DESC 'An entry in a NIS map
' SUP top STRUCTURAL MUST ( cn $ nisMapEntry $ nisMapName ) MAY description )
objectClasses: ( 1.3.6.1.1.1.2.9 NAME 'nisMap' DESC 'A generic abstraction of
a NIS map' SUP top STRUCTURAL MUST nisMapName MAY description )
objectClasses: ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' DESC 'Abstraction of a net
group' SUP top STRUCTURAL MUST cn MAY ( nisNetgroupTriple $ memberNisNetgroup
$ description ) )
objectClasses: ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' DESC 'Abstraction of an IP n
etwork' SUP top STRUCTURAL MUST ( cn $ ipNetworkNumber ) MAY ( ipNetmaskNumbe
r $ l $ description $ manager ) )
objectClasses: ( 1.3.6.1.1.1.2.6 NAME 'ipHost' DESC 'Abstraction of a host, an
IP device' SUP top AUXILIARY MUST ( cn $ ipHostNumber ) MAY ( l $ descriptio
n $ manager ) )
objectClasses: ( 1.3.6.1.1.1.2.5 NAME 'oncRpc' DESC 'Abstraction of an ONC/RPC
binding' SUP top STRUCTURAL MUST ( cn $ oncRpcNumber $ description ) MAY des
cription )
objectClasses: ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' DESC 'Abstraction of an IP
protocol' SUP top STRUCTURAL MUST ( cn $ ipProtocolNumber $ description ) MAY
description )
objectClasses: ( 1.3.6.1.1.1.2.3 NAME 'ipService' DESC 'Abstraction an Interne
t Protocol service' SUP top STRUCTURAL MUST ( cn $ ipServicePort $ ipServiceP
rotocol ) MAY description )
objectClasses: ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction of a grou
p of accounts' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( userPassword
$ memberUid $ description ) )
objectClasses: ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' DESC 'Additional attribu
tes for shadow passwords' SUP top AUXILIARY MUST uid MAY ( userPassword $ sha
dowLastChange $ shadowMin $ shadowMax $ shadowWarning $ shadowInactive $ shad
owExpire $ shadowFlag $ description ) )
objectClasses: ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction of an a
ccount with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ uidNumber $
gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ descri
ption ) )
objectClasses: ( 0.9.2342.19200300.100.4.22 NAME 'qualityLabelledData' SUP top
AUXILIARY MUST dsaQuality MAY ( subtreeMinimumQuality $ subtreeMaximumQualit
y ) )
objectClasses: ( 0.9.2342.19200300.100.4.21 NAME 'pilotDSA' SUP dsa STRUCTURAL
MAY dSAQuality )
objectClasses: ( 0.9.2342.19200300.100.4.20 NAME 'pilotOrganization' SUP ( org
anization $ organizationalUnit ) STRUCTURAL MAY buildingName )
objectClasses: ( 0.9.2342.19200300.100.4.18 NAME 'friendlyCountry' SUP country
STRUCTURAL MUST friendlyCountryName )
objectClasses: ( 0.9.2342.19200300.100.4.17 NAME 'domainRelatedObject' DESC 'R
FC1274: an object related to an domain' SUP top AUXILIARY MUST associatedDoma
in )
objectClasses: ( 0.9.2342.19200300.100.4.15 NAME 'dNSDomain' SUP domain STRUCT
URAL MAY ( ARecord $ MDRecord $ MXRecord $ NSRecord $ SOARecord $ CNAMERecord
) )
objectClasses: ( 0.9.2342.19200300.100.4.14 NAME 'RFC822localPart' SUP domain
STRUCTURAL MAY ( commonName $ surname $ description $ seeAlso $ telephoneNumb
er $ physicalDeliveryOfficeName $ postalAddress $ postalCode $ postOfficeBox
$ streetAddress $ facsimileTelephoneNumber $ internationalISDNNumber $ teleph
oneNumber $ teletexTerminalIdentifier $ telexNumber $ preferredDeliveryMethod
$ destinationIndicator $ registeredAddress $ x121Address ) )
objectClasses: ( 0.9.2342.19200300.100.4.13 NAME 'domain' SUP top STRUCTURAL M
UST domainComponent MAY ( associatedName $ organizationName $ description $ b
usinessCategory $ seeAlso $ searchGuide $ userPassword $ localityName $ state
OrProvinceName $ streetAddress $ physicalDeliveryOfficeName $ postalAddress $
postalCode $ postOfficeBox $ streetAddress $ facsimileTelephoneNumber $ inte
rnationalISDNNumber $ telephoneNumber $ teletexTerminalIdentifier $ telexNumb
er $ preferredDeliveryMethod $ destinationIndicator $ registeredAddress $ x12
1Address ) )
objectClasses: ( 0.9.2342.19200300.100.4.9 NAME 'documentSeries' SUP top STRUC
TURAL MUST commonName MAY ( description $ seeAlso $ telephonenumber $ localit
yName $ organizationName $ organizationalUnitName ) )
objectClasses: ( 0.9.2342.19200300.100.4.7 NAME 'room' SUP top STRUCTURAL MUST
commonName MAY ( roomNumber $ description $ seeAlso $ telephoneNumber ) )
objectClasses: ( 0.9.2342.19200300.100.4.6 NAME 'document' SUP top STRUCTURAL
MUST documentIdentifier MAY ( commonName $ description $ seeAlso $ localityNa
me $ organizationName $ organizationalUnitName $ documentTitle $ documentVers
ion $ documentAuthor $ documentLocation $ documentPublisher ) )
objectClasses: ( 0.9.2342.19200300.100.4.5 NAME 'account' SUP top STRUCTURAL M
UST userid MAY ( description $ seeAlso $ localityName $ organizationName $ or
ganizationalUnitName $ host ) )
objectClasses: ( 0.9.2342.19200300.100.4.4 NAME ( 'pilotPerson' 'newPilotPerso
n' ) SUP person STRUCTURAL MAY ( userid $ textEncodedORAddress $ rfc822Mailbo
x $ favouriteDrink $ roomNumber $ userClass $ homeTelephoneNumber $ homePosta
lAddress $ secretary $ personalTitle $ preferredDeliveryMethod $ businessCate
gory $ janetMailbox $ otherMailbox $ mobileTelephoneNumber $ pagerTelephoneNu
mber $ organizationalStatus $ mailPreferenceOption $ personalSignature ) )
objectClasses: ( 1.3.6.1.1.3.1 NAME 'uidObject' DESC 'RFC2377: uid object' SUP
top AUXILIARY MUST uid )
objectClasses: ( 1.3.6.1.4.1.1466.344 NAME 'dcObject' DESC 'RFC2247: domain co
mponent object' SUP top AUXILIARY MUST dc )
objectClasses: ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject' DESC '
RFC1274: simple security object' SUP top AUXILIARY MUST userPassword )
objectClasses: ( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject' DESC 'RFC2079: o
bject that contains the URI attribute type' SUP top AUXILIARY MAY labeledURI
)
objectClasses: ( 2.5.6.23 NAME 'deltaCRL' DESC 'RFC2587: PKI user' SUP top AUX
ILIARY MAY deltaRevocationList )
objectClasses: ( 2.5.6.22 NAME 'pkiCA' DESC 'RFC2587: PKI certificate authorit
y' SUP top AUXILIARY MAY ( authorityRevocationList $ certificateRevocationLis
t $ cACertificate $ crossCertificatePair ) )
objectClasses: ( 2.5.6.21 NAME 'pkiUser' DESC 'RFC2587: a PKI user' SUP top AU
XILIARY MAY userCertificate )
objectClasses: ( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL MUST dmdName MAY ( use
rPassword $ searchGuide $ seeAlso $ businessCategory $ x121Address $ register
edAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNumber $ te
letexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $ facsimi
leTelephoneNumber $ street $ postOfficeBox $ postalCode $ postalAddress $ phy
sicalDeliveryOfficeName $ st $ l $ description ) )
objectClasses: ( 2.5.6.19 NAME 'cRLDistributionPoint' SUP top STRUCTURAL MUST
cn MAY ( certificateRevocationList $ authorityRevocationList $ deltaRevocatio
nList ) )
objectClasses: ( 2.5.6.16.2 NAME 'certificationAuthority-V2' SUP certification
Authority AUXILIARY MAY deltaRevocationList )
objectClasses: ( 2.5.6.18 NAME 'userSecurityInformation' DESC 'RFC2256: a user
security information' SUP top AUXILIARY MAY supportedAlgorithms )
objectClasses: ( 2.5.6.17 NAME 'groupOfUniqueNames' DESC 'RFC2256: a group of
unique names (DN and Unique Identifier)' SUP top STRUCTURAL MUST ( uniqueMemb
er $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
objectClasses: ( 2.5.6.16 NAME 'certificationAuthority' DESC 'RFC2256: a certi
ficate authority' SUP top AUXILIARY MUST ( authorityRevocationList $ certific
ateRevocationList $ cACertificate ) MAY crossCertificatePair )
objectClasses: ( 2.5.6.15 NAME 'strongAuthenticationUser' DESC 'RFC2256: a str
ong authentication user' SUP top AUXILIARY MUST userCertificate )
objectClasses: ( 2.5.6.14 NAME 'device' DESC 'RFC2256: a device' SUP top STRUC
TURAL MUST cn MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description
) )
objectClasses: ( 2.5.6.13 NAME 'dSA' DESC 'RFC2256: a directory system agent (
a server)' SUP applicationEntity STRUCTURAL MAY knowledgeInformation )
objectClasses: ( 2.5.6.12 NAME 'applicationEntity' DESC 'RFC2256: an applicati
on entity' SUP top STRUCTURAL MUST ( presentationAddress $ cn ) MAY ( support
edApplicationContext $ seeAlso $ ou $ o $ l $ description ) )
objectClasses: ( 2.5.6.11 NAME 'applicationProcess' DESC 'RFC2256: an applicat
ion process' SUP top STRUCTURAL MUST cn MAY ( seeAlso $ ou $ l $ description
) )
objectClasses: ( 2.5.6.10 NAME 'residentialPerson' DESC 'RFC2256: an residenti
al person' SUP person STRUCTURAL MUST l MAY ( businessCategory $ x121Address
$ registeredAddress $ destinationIndicator $ preferredDeliveryMethod $ telexN
umber $ teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber
$ facsimileTelephoneNumber $ preferredDeliveryMethod $ street $ postOfficeBo
x $ postalCode $ postalAddress $ physicalDeliveryOfficeName $ st $ l ) )
objectClasses: ( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of names (
DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $ seeAls
o $ owner $ ou $ o $ description ) )
objectClasses: ( 2.5.6.8 NAME 'organizationalRole' DESC 'RFC2256: an organizat
ional role' SUP top STRUCTURAL MUST cn MAY ( x121Address $ registeredAddress
$ destinationIndicator $ preferredDeliveryMethod $ telexNumber $ teletexTermi
nalIdentifier $ telephoneNumber $ internationaliSDNNumber $ facsimileTelephon
eNumber $ seeAlso $ roleOccupant $ preferredDeliveryMethod $ street $ postOff
iceBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName $ ou $ st $
l $ description ) )
objectClasses: ( 2.5.6.7 NAME 'organizationalPerson' DESC 'RFC2256: an organiz
ational person' SUP person STRUCTURAL MAY ( title $ x121Address $ registeredA
ddress $ destinationIndicator $ preferredDeliveryMethod $ telexNumber $ telet
exTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $ facsimileT
elephoneNumber $ street $ postOfficeBox $ postalCode $ postalAddress $ physic
alDeliveryOfficeName $ ou $ st $ l ) )
objectClasses: ( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCT
URAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ descri
ption ) )
objectClasses: ( 2.5.6.5 NAME 'organizationalUnit' DESC 'RFC2256: an organizat
ional unit' SUP top STRUCTURAL MUST ou MAY ( userPassword $ searchGuide $ see
Also $ businessCategory $ x121Address $ registeredAddress $ destinationIndica
tor $ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $ tel
ephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $ street $
postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName $ st
$ l $ description ) )
objectClasses: ( 2.5.6.4 NAME 'organization' DESC 'RFC2256: an organization' S
UP top STRUCTURAL MUST o MAY ( userPassword $ searchGuide $ seeAlso $ busines
sCategory $ x121Address $ registeredAddress $ destinationIndicator $ preferre
dDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $ telephoneNumber $
internationaliSDNNumber $ facsimileTelephoneNumber $ street $ postOfficeBox
$ postalCode $ postalAddress $ physicalDeliveryOfficeName $ st $ l $ descript
ion ) )
objectClasses: ( 2.5.6.3 NAME 'locality' DESC 'RFC2256: a locality' SUP top ST
RUCTURAL MAY ( street $ seeAlso $ searchGuide $ st $ l $ description ) )
objectClasses: ( 2.5.6.2 NAME 'country' DESC 'RFC2256: a country' SUP top STRU
CTURAL MUST c MAY ( searchGuide $ description ) )
objectClasses: ( 2.5.20.1 NAME 'subschema' DESC 'RFC2252: controlling subschem
a (sub)entry' AUXILIARY MAY ( dITStructureRules $ nameForms $ ditContentRules
$ objectClasses $ attributeTypes $ matchingRules $ matchingRuleUse ) )
objectClasses: ( 2.5.17.0 NAME 'subentry' SUP top STRUCTURAL MUST ( cn $ subtr
eeSpecification ) )
objectClasses: ( 1.3.6.1.4.1.4203.1.4.1 NAME ( 'OpenLDAProotDSE' 'LDAProotDSE'
) DESC 'OpenLDAP Root DSE object' SUP top STRUCTURAL MAY cn )
objectClasses: ( 2.16.840.1.113730.3.2.6 NAME 'referral' DESC 'namedref: named
subordinate referral' SUP top STRUCTURAL MUST ref )
objectClasses: ( 2.5.6.1 NAME 'alias' DESC 'RFC2256: an alias' SUP top STRUCTU
RAL MUST aliasedObjectName )
objectClasses: ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject' DESC 'RF
C2252: extensible object' SUP top AUXILIARY )
objectClasses: ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRAC
T MUST objectClass )
ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/ 0000755 0001750 0001750 00000000000 10403234304 020477 5 ustar jan jan ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.dir/ 0000755 0001750 0001750 00000000000 10403234304 023313 5 ustar jan jan ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.dir/ou=People.dir/ 0000755 0001750 0001750 00000000000 10403234304 025755 5 ustar jan jan ././@LongLink 0000000 0000000 0000000 00000000145 00000000000 011565 L ustar root root ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.dir/ou=People.dir/cn=John Smith.ldif ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.dir/ou=People.dir/cn=John Smith.ldif0000644 0001750 0001750 00000000174 10352525725 031215 0 ustar jan jan dn: cn=John Smith,ou=People,dc=example,dc=com
cn: John Smith
sn: Smith
objectClass: person
subschemaSubentry: cn=Subschema
ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.dir/ou=People.dir/uid=jack.ldif 0000644 0001750 0001750 00000000367 10352506123 030336 0 ustar jan jan dn: uid=jack,ou=People,dc=example,dc=com
objectClass: posixAccount
uid: jack
cn: Jack Black
uidNumber: 1234
gidNumber: 1234
homeDirectory: /home/jack
# "secret"
userPassword: {SSHA}yVLLj62rFf3kDAbzwEU0zYAVvbWrze8=
subschemaSubentry: cn=Subschema
././@LongLink 0000000 0000000 0000000 00000000156 00000000000 011567 L ustar root root ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.dir/ou=People.dir/cn=missing-must-fields.ldif ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.dir/ou=People.dir/cn=missing-must-fi0000644 0001750 0001750 00000000204 10352532370 031354 0 ustar jan jan dn: cn=missing-must-fields,ou=People,dc=example,dc=com
cn: missing-must-fields
objectClass: person
subschemaSubentry: cn=Subschema
ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.dir/ou=People.ldif 0000644 0001750 0001750 00000000154 10345773672 026065 0 ustar jan jan dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People
subschemaSubentry: cn=Subschema
ldaptor-0.0.43/ldaptor/test/ldif/webtests/dc=com.dir/dc=example.ldif 0000644 0001750 0001750 00000000071 10345024433 023401 0 ustar jan jan dn: dc=example,dc=com
objectClass: dcObject
dc: example
ldaptor-0.0.43/ldaptor/test/test_distinguishedname.py 0000644 0001750 0001750 00000027232 10344535643 021123 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.distinguishedname module.
"""
from twisted.trial import unittest
from ldaptor.protocols.ldap import distinguishedname as dn
class TestCaseWithKnownValues(unittest.TestCase):
knownValues = ()
def testKnownValues(self):
for s, l in self.knownValues:
fromString = dn.DistinguishedName(s)
listOfRDNs = []
for av in l:
listOfAttributeTypesAndValues = []
for a,v in av:
listOfAttributeTypesAndValues.append(dn.LDAPAttributeTypeAndValue(attributeType=a, value=v))
r=dn.RelativeDistinguishedName(listOfAttributeTypesAndValues)
listOfRDNs.append(r)
fromList = dn.DistinguishedName(listOfRDNs)
self.assertEquals(fromString, fromList)
fromStringToString = str(fromString)
fromListToString = str(fromList)
assert fromStringToString == fromListToString
canon = fromStringToString
# DNs equal their string representation. Note this does
# not mean they equal all the possible string
# representations -- just the canonical one.
self.assertEquals(fromString, canon)
self.assertEquals(fromList, canon)
self.assertEquals(canon, fromString)
self.assertEquals(canon, fromList)
# DNs can be used interchangeably with their canonical
# string representation as hash keys.
self.assertEquals(hash(fromString), hash(canon))
self.assertEquals(hash(fromList), hash(canon))
self.assertEquals(hash(canon), hash(fromString))
self.assertEquals(hash(canon), hash(fromList))
class LDAPDistinguishedName_Escaping(TestCaseWithKnownValues):
knownValues = (
('', []),
('cn=foo', [[('cn', 'foo')]]),
(r'cn=\,bar', [[('cn', r',bar')]]),
(r'cn=foo\,bar', [[('cn', r'foo,bar')]]),
(r'cn=foo\,', [[('cn', r'foo,')]]),
(r'cn=\+bar', [[('cn', r'+bar')]]),
(r'cn=foo\+bar', [[('cn', r'foo+bar')]]),
(r'cn=foo\+', [[('cn', r'foo+')]]),
(r'cn=\"bar', [[('cn', r'"bar')]]),
(r'cn=foo\"bar', [[('cn', r'foo"bar')]]),
(r'cn=foo\"', [[('cn', r'foo"')]]),
(r'cn=\\bar', [[('cn', r'\bar')]]),
(r'cn=foo\\bar', [[('cn', r'foo\bar')]]),
(r'cn=foo\\', [[('cn', 'foo\\')]]),
(r'cn=\bar', [[('cn', r'>bar')]]),
(r'cn=foo\>bar', [[('cn', r'foo>bar')]]),
(r'cn=foo\>', [[('cn', r'foo>')]]),
(r'cn=\;bar', [[('cn', r';bar')]]),
(r'cn=foo\;bar', [[('cn', r'foo;bar')]]),
(r'cn=foo\;', [[('cn', r'foo;')]]),
(r'cn=\#bar', [[('cn', r'#bar')]]),
(r'cn=\ bar', [[('cn', r' bar')]]),
(r'cn=bar\ ', [[('cn', r'bar ')]]),
(r'cn=test+owner=uid\=foo\,ou\=depar'
+r'tment\,dc\=example\,dc\=com,dc=ex'
+r'ample,dc=com', [[('cn', r'test'),
('owner', r'uid=foo,ou=depart'
+r'ment,dc=example,dc=com'),
],
[('dc', r'example')],
[('dc', r'com')]]),
(r'cn=bar,dc=example,dc=com', [[('cn', 'bar')],
[('dc', 'example')],
[('dc', 'com')]]),
(r'cn=bar, dc=example, dc=com', [[('cn', 'bar')],
[('dc', 'example')],
[('dc', 'com')]]),
(r'cn=bar, dc=example,dc=com', [[('cn', 'bar')],
[('dc', 'example')],
[('dc', 'com')]]),
)
def testOpenLDAPEqualsEscape(self):
"""Slapd wants = to be escaped in RDN attributeValues."""
got = dn.DistinguishedName(listOfRDNs=[
dn.RelativeDistinguishedName(
attributeTypesAndValues=[
dn.LDAPAttributeTypeAndValue(attributeType='cn', value=r'test'),
dn.LDAPAttributeTypeAndValue(attributeType='owner', value=r'uid=foo,ou=depart'
+r'ment,dc=example,dc=com'),
]),
dn.RelativeDistinguishedName('dc=example'),
dn.RelativeDistinguishedName('dc=com'),
])
got = str(got)
self.assertEquals(got,
r'cn=test+owner=uid\=foo\,ou\=depar'
+r'tment\,dc\=example\,dc\=com,dc=ex'
+r'ample,dc=com')
class LDAPDistinguishedName_RFC2253_Examples(TestCaseWithKnownValues):
knownValues = (
('CN=Steve Kille,O=Isode Limited,C=GB',
[[('CN', 'Steve Kille')],
[('O', 'Isode Limited')],
[('C', 'GB')]]),
('OU=Sales+CN=J. Smith,O=Widget Inc.,C=US',
[[('OU', 'Sales'),
('CN', 'J. Smith')],
[('O', 'Widget Inc.')],
[('C', 'US')]]),
(r'CN=L. Eagle,O=Sue\, Grabbit and Runn,C=GB',
[[('CN', 'L. Eagle')],
[('O', 'Sue, Grabbit and Runn')],
[('C', 'GB')]]),
(r'CN=Before\0DAfter,O=Test,C=GB',
[[('CN', 'Before\x0dAfter')],
[('O', 'Test')],
[('C', 'GB')]]),
(r'1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB',
[[('1.3.6.1.4.1.1466.0', '#04024869')],
[('O', 'Test')],
[('C', 'GB')]]),
(u'SN=Lu\u010di\u0107'.encode('utf-8'),
[[('SN', u'Lu\u010di\u0107'.encode('utf-8'))]])
)
class LDAPDistinguishedName_InitialSpaces(TestCaseWithKnownValues):
knownValues = (
('cn=foo, ou=bar, dc=quux, \ attributeThatStartsWithSpace=Value',
[[('cn', 'foo')],
[('ou', 'bar')],
[('dc', 'quux')],
[(' attributeThatStartsWithSpace', 'Value')]]),
)
class LDAPDistinguishedName_DomainName(unittest.TestCase):
def testNonDc(self):
d=dn.DistinguishedName('cn=foo,o=bar,c=us')
assert d.getDomainName() is None
def testNonTrailingDc(self):
d=dn.DistinguishedName('cn=foo,o=bar,dc=foo,c=us')
assert d.getDomainName() is None
def testSimple_ExampleCom(self):
d=dn.DistinguishedName('dc=example,dc=com')
assert d.getDomainName() == 'example.com'
def testSimple_SubExampleCom(self):
d=dn.DistinguishedName('dc=sub,dc=example,dc=com')
assert d.getDomainName() == 'sub.example.com'
def testSimple_HostSubExampleCom(self):
d=dn.DistinguishedName('cn=host,dc=sub,dc=example,dc=com')
assert d.getDomainName() == 'sub.example.com'
def testInterleaved_SubHostSubExampleCom(self):
d=dn.DistinguishedName('dc=sub2,cn=host,dc=sub,dc=example,dc=com')
assert d.getDomainName() == 'sub.example.com'
class LDAPDistinguishedName_contains(unittest.TestCase):
shsec=dn.DistinguishedName('dc=sub2,cn=host,dc=sub,dc=example,dc=com')
hsec=dn.DistinguishedName('cn=host,dc=sub,dc=example,dc=com')
sec=dn.DistinguishedName('dc=sub,dc=example,dc=com')
ec=dn.DistinguishedName('dc=example,dc=com')
c=dn.DistinguishedName('dc=com')
soc=dn.DistinguishedName('dc=sub,dc=other,dc=com')
oc=dn.DistinguishedName('dc=other,dc=com')
other=dn.DistinguishedName('o=foo,c=US')
root=dn.DistinguishedName('')
def test_selfContainment(self):
assert self.c.contains(self.c)
assert self.ec.contains(self.ec)
assert self.sec.contains(self.sec)
assert self.hsec.contains(self.hsec)
assert self.shsec.contains(self.shsec)
assert self.soc.contains(self.soc)
assert self.oc.contains(self.oc)
assert self.root.contains(self.root)
assert self.other.contains(self.other)
def test_realContainment(self):
assert self.c.contains(self.ec)
assert self.c.contains(self.sec)
assert self.c.contains(self.hsec)
assert self.c.contains(self.shsec)
assert self.ec.contains(self.sec)
assert self.ec.contains(self.hsec)
assert self.ec.contains(self.shsec)
assert self.sec.contains(self.hsec)
assert self.sec.contains(self.shsec)
assert self.hsec.contains(self.shsec)
assert self.c.contains(self.oc)
assert self.c.contains(self.soc)
assert self.oc.contains(self.soc)
for x in (self.shsec, self.hsec, self.sec, self.ec, self.c,
self.soc, self.oc, self.other):
assert self.root.contains(x)
def test_nonContainment_parents(self):
assert not self.shsec.contains(self.hsec)
assert not self.shsec.contains(self.sec)
assert not self.shsec.contains(self.ec)
assert not self.shsec.contains(self.c)
assert not self.hsec.contains(self.sec)
assert not self.hsec.contains(self.ec)
assert not self.hsec.contains(self.c)
assert not self.sec.contains(self.ec)
assert not self.sec.contains(self.c)
assert not self.ec.contains(self.c)
assert not self.soc.contains(self.oc)
for x in (self.shsec, self.hsec, self.sec, self.ec, self.c,
self.soc, self.oc, self.other):
assert not x.contains(self.root)
def test_nonContainment_nonParents(self):
groups=([self.shsec, self.hsec, self.sec, self.ec],
[self.soc, self.oc],
[self.other])
for g1 in groups:
for g2 in groups:
if g1!=g2:
for i1 in g1:
for i2 in g2:
assert not i1.contains(i2)
assert not self.c.contains(self.other)
assert not self.other.contains(self.c)
class LDAPDistinguishedName_Malformed(unittest.TestCase):
def testMalformed(self):
self.assertRaises(dn.InvalidRelativeDistinguishedName,
dn.DistinguishedName,
'foo')
self.assertRaises(dn.InvalidRelativeDistinguishedName,
dn.DistinguishedName,
'foo,dc=com')
self.assertRaises(dn.InvalidRelativeDistinguishedName,
dn.DistinguishedName,
'ou=something,foo')
self.assertRaises(dn.InvalidRelativeDistinguishedName,
dn.DistinguishedName,
'foo,foo')
class LDAPDistinguishedName_Prettify(unittest.TestCase):
def testPrettifySpaces(self):
"""str(DistinguishedName(...)) prettifies the DN by removing extra whitespace."""
d=dn.DistinguishedName('cn=foo, o=bar, c=us')
assert str(d) == 'cn=foo,o=bar,c=us'
class DistinguishedName_Init(unittest.TestCase):
def testString(self):
d=dn.DistinguishedName('dc=example,dc=com')
self.assertEquals(str(d), 'dc=example,dc=com')
def testDN(self):
proto=dn.DistinguishedName('dc=example,dc=com')
d=dn.DistinguishedName(proto)
self.assertEquals(str(d), 'dc=example,dc=com')
class RelativeDistinguishedName_Init(unittest.TestCase):
def testString(self):
rdn=dn.RelativeDistinguishedName('dc=example')
self.assertEquals(str(rdn), 'dc=example')
def testRDN(self):
proto=dn.RelativeDistinguishedName('dc=example')
rdn=dn.RelativeDistinguishedName(proto)
self.assertEquals(str(rdn), 'dc=example')
class DistinguishedName_Comparison(unittest.TestCase):
# TODO test more carefully
def testGT(self):
dn1=dn.DistinguishedName('dc=example,dc=com')
dn2=dn.DistinguishedName('dc=bar,dc=example,dc=com')
self.failUnless(dn1 > dn2)
ldaptor-0.0.43/ldaptor/test/test_attributeset.py 0000644 0001750 0001750 00000007035 10052211034 020112 0 ustar jan jan """
Test cases for ldaptor.attributeset
"""
from twisted.trial import unittest
import sets
from ldaptor import attributeset
class TestComparison(unittest.TestCase):
def testEquality_True_Set(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
self.assertEquals(a, b)
def testEquality_True_Set_Ordering(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('k', ['b', 'd', 'c'])
self.assertEquals(a, b)
def testEquality_True_List(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = ['b', 'c', 'd']
self.assertEquals(a, b)
def testEquality_True_List_Ordering(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = ['b', 'd', 'c']
self.assertEquals(a, b)
def testEquality_False_Value(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('k', ['b', 'c', 'e'])
self.assertNotEqual(a, b)
def testEquality_False_Key(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('l', ['b', 'c', 'd'])
self.assertNotEqual(a, b)
class TestSetOperations(unittest.TestCase):
def testDifference(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('k', ['b', 'c', 'e'])
self.assertEquals(a - b, sets.Set(['d']))
def testUnion(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('k', ['b', 'c', 'e'])
self.assertEquals(a | b, sets.Set(['b', 'c', 'd', 'e']))
def testIntersection(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('k', ['b', 'c', 'e'])
self.assertEquals(a & b, sets.Set(['b', 'c']))
def testSymmetricDifference(self):
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('k', ['b', 'c', 'e'])
self.assertEquals(a ^ b, sets.Set(['d', 'e']))
def testCopy(self):
class Magic:
pass
m1 = Magic()
a = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd', m1])
b = a.__copy__()
self.assertEquals(a, b)
self.assertNotIdentical(a, b)
magicFromA = [val for val in a if isinstance(val, Magic)][0]
magicFromB = [val for val in b if isinstance(val, Magic)][0]
self.assertEquals(magicFromA, magicFromB)
self.assertIdentical(magicFromA, magicFromB)
a.update('x')
self.assertEquals(a, sets.Set(['b', 'c', 'd', m1, 'x']))
self.assertEquals(b, sets.Set(['b', 'c', 'd', m1]))
def testDeepCopy(self):
class Magic:
def __eq__(self, other):
return isinstance(other, self.__class__)
def __hash__(self):
return 42
m1 = Magic()
a = attributeset.LDAPAttributeSet('k', ['a', m1])
b = a.__deepcopy__({})
self.assertEquals(a, b)
self.assertNotIdentical(a, b)
magicFromA = [val for val in a if isinstance(val, Magic)][0]
magicFromB = [val for val in b if isinstance(val, Magic)][0]
self.assertEquals(magicFromA, magicFromB)
self.assertNotIdentical(magicFromA, magicFromB)
a.update('x')
self.assertEquals(a, sets.Set(['a', m1, 'x']))
self.assertEquals(b, sets.Set(['a', m1]))
ldaptor-0.0.43/ldaptor/test/test_autofill_samba.py 0000644 0001750 0001750 00000033474 10345261504 020377 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.autofill.sambaAccount module.
"""
import sets
from twisted.trial import unittest
from ldaptor.protocols.ldap import ldapsyntax
from ldaptor.protocols.ldap.autofill import sambaAccount, sambaSamAccount
from ldaptor import testutil
class LDAPAutoFill_sambaAccount(unittest.TestCase):
def testMustHaveObjectClass(self):
"""Test that Autofill_samba fails unless object is a sambaAccount."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['something', 'other'],
})
autoFiller = sambaAccount.Autofill_samba()
d = o.addAutofiller(autoFiller)
def eb(val):
client.assertNothingSent()
val.trap(sambaAccount.ObjectMissingObjectClassException)
d.addCallbacks(testutil.mustRaise, eb)
return d
def testDefaultSetting(self):
"""Test that fields get their default values."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaAccount', 'other'],
})
d = o.addAutofiller(sambaAccount.Autofill_samba())
def cb(dummy):
client.assertNothingSent()
self.failUnless('acctFlags' in o)
self.failUnlessEqual(o['acctFlags'], ['[UX ]'])
self.failUnless('pwdLastSet' in o)
self.failUnlessEqual(o['pwdLastSet'], ['0'])
self.failUnless('logonTime' in o)
self.failUnlessEqual(o['logonTime'], ['0'])
self.failUnless('logoffTime' in o)
self.failUnlessEqual(o['logoffTime'], ['0'])
self.failUnless('pwdCanChange' in o)
self.failUnlessEqual(o['pwdCanChange'], ['0'])
self.failUnless('pwdMustChange' in o)
self.failUnlessEqual(o['pwdMustChange'], ['0'])
d.addCallback(cb)
return d
def testRid(self):
"""Test that rid field is updated based on uidNumber."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaAccount', 'other'],
})
d = o.addAutofiller(sambaAccount.Autofill_samba())
def cb(dummy):
client.assertNothingSent()
o['uidNumber'] = ['1000']
self.failUnless('rid' in o)
self.failUnlessEqual(o['rid'], [str(2*1000+1000)])
o['uidNumber'] = ['1001']
self.failUnlessEqual(o['rid'], [str(2*1001+1000)])
o['uidNumber'] = ['1002']
self.failUnlessEqual(o['rid'], [str(2*1002+1000)])
o['uidNumber'] = ['2000']
self.failUnlessEqual(o['rid'], [str(2*2000+1000)])
o['uidNumber'] = ['3000']
self.failUnlessEqual(o['rid'], [str(2*3000+1000)])
o['uidNumber'] = ['0']
self.failUnlessEqual(o['rid'], [str(2*0+1000)])
o['uidNumber'] = ['16000']
self.failUnlessEqual(o['rid'], [str(2*16000+1000)])
d.addCallback(cb)
return d
def testPrimaryGroupId(self):
"""Test that primaryGroupID field is updated based on gidNumber."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaAccount', 'other'],
})
d = o.addAutofiller(sambaAccount.Autofill_samba())
def cb(dummy):
client.assertNothingSent()
o['gidNumber'] = ['1000']
self.failUnless('primaryGroupID' in o)
self.failUnlessEqual(o['primaryGroupID'], [str(2*1000+1001)])
o['gidNumber'] = ['1001']
self.failUnlessEqual(o['primaryGroupID'], [str(2*1001+1001)])
o['gidNumber'] = ['1002']
self.failUnlessEqual(o['primaryGroupID'], [str(2*1002+1001)])
o['gidNumber'] = ['2000']
self.failUnlessEqual(o['primaryGroupID'], [str(2*2000+1001)])
o['gidNumber'] = ['3000']
self.failUnlessEqual(o['primaryGroupID'], [str(2*3000+1001)])
o['gidNumber'] = ['0']
self.failUnlessEqual(o['primaryGroupID'], [str(2*0+1001)])
o['gidNumber'] = ['16000']
self.failUnlessEqual(o['primaryGroupID'], [str(2*16000+1001)])
d.addCallback(cb)
return d
class LDAPAutoFill_sambaSamAccount(unittest.TestCase):
def testMustHaveObjectClass(self):
"""Test that Autofill_samba fails unless object is a sambaSamAccount."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['something', 'other'],
})
autoFiller = sambaSamAccount.Autofill_samba(domainSID='foo')
d = o.addAutofiller(autoFiller)
def eb(val):
client.assertNothingSent()
val.trap(sambaSamAccount.ObjectMissingObjectClassException)
d.addCallbacks(testutil.mustRaise, eb)
return d
def testDefaultSetting(self):
"""Test that fields get their default values."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaSamAccount', 'other'],
})
d = o.addAutofiller(sambaSamAccount.Autofill_samba(domainSID='foo'))
def cb(dummy):
client.assertNothingSent()
self.failUnlessEqual(sets.Set(o.keys()), sets.Set([
'objectClass',
'sambaAcctFlags',
'sambaLogoffTime',
'sambaLogonTime',
'sambaPwdCanChange',
'sambaPwdLastSet',
'sambaPwdMustChange',
]))
self.failUnlessEqual(o['sambaAcctFlags'], ['[UX ]'])
self.failUnlessEqual(o['sambaPwdLastSet'], ['0'])
self.failUnlessEqual(o['sambaLogonTime'], ['0'])
self.failUnlessEqual(o['sambaLogoffTime'], ['0'])
self.failUnlessEqual(o['sambaPwdCanChange'], ['0'])
self.failUnlessEqual(o['sambaPwdMustChange'], ['0'])
d.addCallback(cb)
return d
def testDefaultSetting_fixedPrimaryGroupSID(self):
"""Test that fields get their default values."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaSamAccount', 'other'],
})
d = o.addAutofiller(sambaSamAccount.Autofill_samba(domainSID='foo',
fixedPrimaryGroupSID=4131312))
def cb(dummy):
client.assertNothingSent()
self.failUnlessEqual(sets.Set(o.keys()), sets.Set([
'objectClass',
'sambaAcctFlags',
'sambaLogoffTime',
'sambaLogonTime',
'sambaPwdCanChange',
'sambaPwdLastSet',
'sambaPwdMustChange',
'sambaPrimaryGroupSID',
]))
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-4131312'])
self.failUnlessEqual(o['sambaAcctFlags'], ['[UX ]'])
self.failUnlessEqual(o['sambaPwdLastSet'], ['0'])
self.failUnlessEqual(o['sambaLogonTime'], ['0'])
self.failUnlessEqual(o['sambaLogoffTime'], ['0'])
self.failUnlessEqual(o['sambaPwdCanChange'], ['0'])
self.failUnlessEqual(o['sambaPwdMustChange'], ['0'])
d.addCallback(cb)
return d
def testSambaSID(self):
"""Test that sambaSID field is updated based on uidNumber."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaSamAccount', 'other'],
})
d = o.addAutofiller(sambaSamAccount.Autofill_samba(domainSID='foo'))
def cb(dummy):
client.assertNothingSent()
o['uidNumber'] = ['1000']
self.failUnless('sambaSID' in o)
self.failUnlessEqual(o['sambaSID'], ['foo-%s' % (2*1000+1000)])
o['uidNumber'] = ['1001']
self.failUnlessEqual(o['sambaSID'], ['foo-%s' % (2*1001+1000)])
o['uidNumber'] = ['1002']
self.failUnlessEqual(o['sambaSID'], ['foo-%s' % (2*1002+1000)])
o['uidNumber'] = ['2000']
self.failUnlessEqual(o['sambaSID'], ['foo-%s' % (2*2000+1000)])
o['uidNumber'] = ['3000']
self.failUnlessEqual(o['sambaSID'], ['foo-%s' % (2*3000+1000)])
o['uidNumber'] = ['0']
self.failUnlessEqual(o['sambaSID'], ['foo-%s' % (2*0+1000)])
o['uidNumber'] = ['16000']
self.failUnlessEqual(o['sambaSID'], ['foo-%s' % (2*16000+1000)])
d.addCallback(cb)
return d
def testSambaSID_preExisting(self):
"""Test that sambaSID field is updated based on uidNumber."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaSamAccount', 'other'],
'uidNumber': ['1000'],
})
d = o.addAutofiller(sambaSamAccount.Autofill_samba(domainSID='foo'))
def cb(dummy):
client.assertNothingSent()
self.failUnless('sambaSID' in o)
self.failUnlessEqual(o['sambaSID'], ['foo-%s' % (2*1000+1000)])
d.addCallback(cb)
return d
def testSambaPrimaryGroupSID(self):
"""Test that sambaPrimaryGroupSID field is updated based on gidNumber."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaSamAccount', 'other'],
})
d = o.addAutofiller(sambaSamAccount.Autofill_samba(domainSID='foo'))
def cb(dummy):
client.assertNothingSent()
o['gidNumber'] = ['1000']
self.failUnless('sambaPrimaryGroupSID' in o)
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-%s' % (2*1000+1001)])
o['gidNumber'] = ['1001']
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-%s' % (2*1001+1001)])
o['gidNumber'] = ['1002']
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-%s' % (2*1002+1001)])
o['gidNumber'] = ['2000']
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-%s' % (2*2000+1001)])
o['gidNumber'] = ['3000']
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-%s' % (2*3000+1001)])
o['gidNumber'] = ['0']
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-%s' % (2*0+1001)])
o['gidNumber'] = ['16000']
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-%s' % (2*16000+1001)])
d.addCallback(cb)
return d
def testSambaPrimaryGroupSID_preExisting(self):
"""Test that sambaPrimaryGroupSID field is updated based on gidNumber."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaSamAccount', 'other'],
'gidNumber': ['1000'],
})
d = o.addAutofiller(sambaSamAccount.Autofill_samba(domainSID='foo'))
def cb(dummy):
client.assertNothingSent()
self.failUnless('sambaPrimaryGroupSID' in o)
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-%s' % (2*1000+1001)])
d.addCallback(cb)
return d
def testSambaPrimaryGroupSID_notUpdatedWhenFixed(self):
"""Test that sambaPrimaryGroupSID field is updated based on gidNumber."""
client = testutil.LDAPClientTestDriver()
o=ldapsyntax.LDAPEntryWithAutoFill(client=client,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['sambaSamAccount', 'other'],
})
d = o.addAutofiller(sambaSamAccount.Autofill_samba(domainSID='foo',
fixedPrimaryGroupSID=4242))
def cb(dummy):
client.assertNothingSent()
self.failUnless('sambaPrimaryGroupSID' in o)
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-4242'])
o['gidNumber'] = ['1000']
self.failUnless('sambaPrimaryGroupSID' in o)
self.failUnlessEqual(o['sambaPrimaryGroupSID'], ['foo-4242'])
d.addCallback(cb)
return d
ldaptor-0.0.43/ldaptor/test/test_server.py 0000644 0001750 0001750 00000060045 10365661425 016725 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.ldapserver module.
"""
from twisted.trial import unittest
import sets, base64
from twisted.internet import protocol, address
from twisted.python import components
from ldaptor import inmemory, interfaces, schema, delta, entry
from ldaptor.protocols.ldap import ldapserver, ldapclient, ldaperrors, fetchschema
from ldaptor.protocols import pureldap, pureber
from twisted.test import proto_helpers
from ldaptor.test import util, test_schema
class LDAPServerTest(unittest.TestCase):
def setUp(self):
self.root = inmemory.ReadOnlyInMemoryLDAPEntry(
dn='dc=example,dc=com',
attributes={ 'dc': 'example',
})
self.stuff = self.root.addChild(
rdn='ou=stuff',
attributes={
'objectClass': ['a', 'b'],
'ou': ['stuff'],
})
self.thingie = self.stuff.addChild(
rdn='cn=thingie',
attributes={
'objectClass': ['a', 'b'],
'cn': ['thingie'],
})
self.another = self.stuff.addChild(
rdn='cn=another',
attributes={
'objectClass': ['a', 'b'],
'cn': ['another'],
})
server = ldapserver.LDAPServer()
server.factory = self.root
server.transport = proto_helpers.StringTransport()
server.connectionMade()
self.server = server
def test_bind(self):
self.server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(), id=4)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(pureldap.LDAPBindResponse(resultCode=0), id=4)))
def test_bind_success(self):
self.thingie['userPassword'] = ['{SSHA}yVLLj62rFf3kDAbzwEU0zYAVvbWrze8='] # "secret"
self.server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(
dn='cn=thingie,ou=stuff,dc=example,dc=com',
auth='secret'), id=4)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(resultCode=0,
matchedDN='cn=thingie,ou=stuff,dc=example,dc=com'),
id=4)))
def test_bind_invalidCredentials_badPassword(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(dn='cn=thingie,ou=stuff,dc=example,dc=com',
auth='invalid'),
id=734)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPInvalidCredentials.resultCode),
id=734)))
def test_bind_invalidCredentials_nonExisting(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(dn='cn=non-existing,dc=example,dc=com',
auth='invalid'),
id=78)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPInvalidCredentials.resultCode),
id=78)))
def test_bind_badVersion_1_anonymous(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(version=1),
id=32)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPProtocolError.resultCode,
errorMessage='Version 1 not supported'),
id=32)))
def test_bind_badVersion_2_anonymous(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(version=2),
id=32)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPProtocolError.resultCode,
errorMessage='Version 2 not supported'),
id=32)))
def test_bind_badVersion_4_anonymous(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(version=4),
id=32)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPProtocolError.resultCode,
errorMessage='Version 4 not supported'),
id=32)))
def test_bind_badVersion_4_nonExisting(self):
# TODO make a test just like this one that would pass authentication
# if version was correct, to ensure we don't leak that info either.
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(version=4,
dn='cn=non-existing,dc=example,dc=com',
auth='invalid'),
id=11)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPProtocolError.resultCode,
errorMessage='Version 4 not supported'),
id=11)))
def test_unbind(self):
self.server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPUnbindRequest(), id=7)))
self.assertEquals(self.server.transport.value(),
'')
def test_search_outOfTree(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPSearchRequest(
baseObject='dc=invalid',
), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(resultCode=ldaperrors.LDAPNoSuchObject.resultCode),
id=2)),
)
def test_search_matchAll_oneResult(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPSearchRequest(
baseObject='cn=thingie,ou=stuff,dc=example,dc=com',
), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='cn=thingie,ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('cn', ['thingie']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(resultCode=0),
id=2)),
)
def test_search_matchAll_manyResults(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPSearchRequest(
baseObject='ou=stuff,dc=example,dc=com',
), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('ou', ['stuff']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='cn=another,ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('cn', ['another']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='cn=thingie,ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('cn', ['thingie']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(resultCode=0),
id=2)),
)
def test_search_scope_oneLevel(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPSearchRequest(
baseObject='ou=stuff,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_singleLevel,
), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='cn=thingie,ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('cn', ['thingie']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='cn=another,ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('cn', ['another']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(resultCode=0),
id=2)),
)
def test_search_scope_wholeSubtree(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPSearchRequest(
baseObject='ou=stuff,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_wholeSubtree,
), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('ou', ['stuff']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='cn=another,ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('cn', ['another']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='cn=thingie,ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('cn', ['thingie']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(resultCode=0),
id=2)),
)
def test_search_scope_baseObject(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPSearchRequest(
baseObject='ou=stuff,dc=example,dc=com',
scope=pureldap.LDAP_SCOPE_baseObject,
), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='ou=stuff,dc=example,dc=com',
attributes=[ ('objectClass', ['a', 'b']),
('ou', ['stuff']),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(resultCode=0),
id=2)),
)
def test_rootDSE(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPSearchRequest(
baseObject='',
scope=pureldap.LDAP_SCOPE_baseObject,
filter=pureldap.LDAPFilter_present('objectClass'),
), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry(
objectName='',
attributes=[ ('supportedLDAPVersion', ['3']),
('namingContexts', ['dc=example,dc=com']),
('supportedExtension', [
pureldap.LDAPPasswordModifyRequest.oid,
]),
]),
id=2))
+ str(pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(resultCode=ldaperrors.Success.resultCode),
id=2)),
)
def test_delete(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPDelRequest(str(self.thingie.dn)), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPDelResponse(resultCode=0),
id=2)),
)
d = self.stuff.children()
d.addCallback(self.assertEquals, [self.another])
return d
def test_add_success(self):
dn = 'cn=new,ou=stuff,dc=example,dc=com'
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPAddRequest(entry=dn,
attributes=[
(pureldap.LDAPAttributeDescription("objectClass"),
pureber.BERSet(value=[
pureldap.LDAPAttributeValue('something'),
])),
]), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPAddResponse(
resultCode=ldaperrors.Success.resultCode),
id=2)),
)
# tree changed
d = self.stuff.children()
d.addCallback(self.assertEquals, [
self.thingie,
self.another,
inmemory.ReadOnlyInMemoryLDAPEntry(
'cn=new,ou=stuff,dc=example,dc=com',
{'objectClass': ['something']}),
])
return d
def test_add_fail_existsAlready(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPAddRequest(entry=str(self.thingie.dn),
attributes=[
(pureldap.LDAPAttributeDescription("objectClass"),
pureber.BERSet(value=[
pureldap.LDAPAttributeValue('something'),
])),
]), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPAddResponse(
resultCode=ldaperrors.LDAPEntryAlreadyExists.resultCode,
errorMessage=str(self.thingie.dn)),
id=2)),
)
# tree did not change
d = self.stuff.children()
d.addCallback(self.assertEquals, [self.thingie, self.another])
return d
def test_modifyDN_rdnOnly_deleteOldRDN_success(self):
newrdn = 'cn=thingamagic'
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPModifyDNRequest(entry=self.thingie.dn,
newrdn=newrdn,
deleteoldrdn=True),
id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPModifyDNResponse(
resultCode=ldaperrors.Success.resultCode),
id=2)),
)
# tree changed
d = self.stuff.children()
d.addCallback(self.assertEquals, [
inmemory.ReadOnlyInMemoryLDAPEntry(
'%s,ou=stuff,dc=example,dc=com' % newrdn,
{'objectClass': ['a', 'b'],
'cn': ['thingamagic']}),
self.another,
])
return d
def test_modifyDN_rdnOnly_noDeleteOldRDN_success(self):
newrdn = 'cn=thingamagic'
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPModifyDNRequest(entry=self.thingie.dn,
newrdn=newrdn,
deleteoldrdn=False),
id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPModifyDNResponse(
resultCode=ldaperrors.Success.resultCode),
id=2)),
)
# tree changed
d = self.stuff.children()
d.addCallback(self.assertEquals, sets.Set([
self.another,
inmemory.ReadOnlyInMemoryLDAPEntry(
'%s,ou=stuff,dc=example,dc=com' % newrdn,
{'objectClass': ['a', 'b'],
'cn': ['thingamagic', 'thingie']}),
]))
return d
test_modifyDN_rdnOnly_noDeleteOldRDN_success.todo = 'Not supported yet.'
def test_modify(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPModifyRequest(self.stuff.dn,
modification=[
delta.Add('foo', ['bar']).asLDAP(),
],
),
id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPModifyResponse(
resultCode=ldaperrors.Success.resultCode),
id=2)),
)
# tree changed
self.assertEquals(
self.stuff,
inmemory.ReadOnlyInMemoryLDAPEntry(
'ou=stuff,dc=example,dc=com',
{'objectClass': ['a', 'b'],
'ou': ['stuff'],
'foo': ['bar']}))
def test_extendedRequest_unknown(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPExtendedRequest(requestName='42.42.42',
requestValue='foo'),
id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPExtendedResponse(
resultCode=ldaperrors.LDAPProtocolError.resultCode,
errorMessage='Unknown extended request: 42.42.42'),
id=2)),
)
def test_passwordModify_notBound(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=thingie,ou=stuff,dc=example,dc=com',
newPasswd='hushhush'),
id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPExtendedResponse(
resultCode=ldaperrors.LDAPStrongAuthRequired.resultCode,
responseName=pureldap.LDAPPasswordModifyRequest.oid),
id=2)),
)
def test_passwordModify_simple(self):
# first bind to some entry
self.thingie['userPassword'] = ['{SSHA}yVLLj62rFf3kDAbzwEU0zYAVvbWrze8='] # "secret"
self.server.dataReceived(str(pureldap.LDAPMessage(pureldap.LDAPBindRequest(
dn='cn=thingie,ou=stuff,dc=example,dc=com',
auth='secret'), id=4)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(resultCode=0,
matchedDN='cn=thingie,ou=stuff,dc=example,dc=com'),
id=4)))
self.server.transport.clear()
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPPasswordModifyRequest(
userIdentity='cn=thingie,ou=stuff,dc=example,dc=com',
newPasswd='hushhush'),
id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPExtendedResponse(
resultCode=ldaperrors.Success.resultCode,
responseName=pureldap.LDAPPasswordModifyRequest.oid),
id=2)),
)
# tree changed
secrets = self.thingie.get('userPassword', [])
self.assertEquals(len(secrets), 1)
for secret in secrets:
self.assertEquals(secret[:len('{SSHA}')], '{SSHA}')
raw = base64.decodestring(secret[len('{SSHA}'):])
salt = raw[20:]
self.assertEquals(entry.sshaDigest('hushhush', salt),
secret)
def test_unknownRequest(self):
# make server miss one of the handle_* attributes
# without having to modify the LDAPServer class
class MockServer(ldapserver.LDAPServer):
handle_LDAPBindRequest = property()
self.server.__class__ = MockServer
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(), id=2)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPExtendedResponse(resultCode=ldaperrors.LDAPProtocolError.resultCode,
responseName='1.3.6.1.4.1.1466.20036',
errorMessage='Unknown request'), id=2)))
def test_control_unknown_critical(self):
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(), id=2,
controls=[('42.42.42.42', True, None),
])))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPUnavailableCriticalExtension.resultCode,
errorMessage='Unknown control 42.42.42.42'), id=2)))
def test_control_unknown_nonCritical(self):
self.thingie['userPassword'] = ['{SSHA}yVLLj62rFf3kDAbzwEU0zYAVvbWrze8='] # "secret"
self.server.dataReceived(str(pureldap.LDAPMessage(
pureldap.LDAPBindRequest(dn='cn=thingie,ou=stuff,dc=example,dc=com',
auth='secret'),
controls=[('42.42.42.42', False, None)],
id=4)))
self.assertEquals(self.server.transport.value(),
str(pureldap.LDAPMessage(
pureldap.LDAPBindResponse(resultCode=0,
matchedDN='cn=thingie,ou=stuff,dc=example,dc=com'),
id=4)))
class TestSchema(unittest.TestCase):
def setUp(self):
db = inmemory.ReadOnlyInMemoryLDAPEntry('', {})
com = db.addChild('dc=com',
{'objectClass': ['dcObject'],
'dc': ['com'],
})
com.addChild('dc=example',
{'objectClass': ['dcObject'],
'dc': ['example'],
'subschemaSubentry': ['cn=schema'],
})
db.addChild('cn=schema',
{'objectClass': ['TODO'],
'cn': ['schema'],
'attributeTypes': [test_schema.AttributeType_KnownValues.knownValues[0][0]],
'objectClasses': [test_schema.OBJECTCLASSES['organization'],
test_schema.OBJECTCLASSES['organizationalUnit'],
],
})
class LDAPServerFactory(protocol.ServerFactory):
protocol = ldapserver.LDAPServer
def __init__(self, root):
self.root = root
components.registerAdapter(lambda x: x.root,
LDAPServerFactory,
interfaces.IConnectedLDAPEntry)
serverFactory = LDAPServerFactory(db)
self.client = ldapclient.LDAPClient()
server = serverFactory.buildProtocol(address.IPv4Address('TCP', 'localhost', '1024'))
util.returnConnected(server, self.client)
def testSimple(self):
d = fetchschema.fetch(self.client, 'dc=example,dc=com')
(attributeTypes, objectClasses) = util.pumpingDeferredResult(d)
self.failUnlessEqual([str(x) for x in attributeTypes],
[str(schema.AttributeTypeDescription(x)) for x in [
test_schema.AttributeType_KnownValues.knownValues[0][0],
]])
self.failUnlessEqual([str(x) for x in objectClasses],
[str(schema.ObjectClassDescription(x)) for x in [
test_schema.OBJECTCLASSES['organization'],
test_schema.OBJECTCLASSES['organizationalUnit'],
]])
ldaptor-0.0.43/ldaptor/test/test_pureber.py 0000644 0001750 0001750 00000040151 10345573607 017061 0 ustar jan jan # Ldaptor -- TODO
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
Test cases for ldaptor.protocols.pureber module.
"""
from twisted.trial import unittest
from ldaptor.protocols import pureber
import types
def s(*l):
"""Join all members of list to a string. Integer members are chr()ed"""
r=''
for e in l:
if isinstance(e, types.IntType):
e=chr(e)
r=r+str(e)
return r
def l(s):
"""Split a string to ord's of chars."""
return map(lambda x: ord(x), s)
class BerLengths(unittest.TestCase):
knownValues=(
(0, [0]),
(1, [1]),
(100, [100]),
(126, [126]),
(127, [127]),
(128, [0x80|1, 128]),
(129, [0x80|1, 129]),
(255, [0x80|1, 255]),
(256, [0x80|2, 1, 0]),
(257, [0x80|2, 1, 1]),
(65535, [0x80|2, 0xFF, 0xFF]),
(65536, [0x80|3, 0x01, 0x00, 0x00]),
(256**127-1, [0x80|127]+127*[0xFF]),
)
def testToBER(self):
for integer, encoded in self.knownValues:
got = pureber.int2berlen(integer)
got = str(got)
got = map(ord, got)
self.assertEquals(got, encoded)
def testFromBER(self):
for integer, encoded in self.knownValues:
m=s(*encoded)
got, bytes = pureber.berDecodeLength(m)
self.assertEquals(bytes, len(m))
self.assertEquals(got, integer)
def testPartialBER(self):
m=str(pureber.int2berlen(3*256))
assert len(m)==3
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeLength, m[:2])
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeLength, m[:1])
m=str(pureber.int2berlen(256**100-1))
assert len(m)==101
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeLength, m[:100])
class BERBaseEquality(unittest.TestCase):
valuesToTest=(
(pureber.BERInteger, [0]),
(pureber.BERInteger, [1]),
(pureber.BERInteger, [4000]),
(pureber.BERSequence, [[pureber.BERInteger(1000), pureber.BERInteger(2000)]]),
(pureber.BERSequence, [[pureber.BERInteger(2000), pureber.BERInteger(1000)]]),
(pureber.BEROctetString, ["foo"]),
(pureber.BEROctetString, ["b"+chr(0xe4)+chr(0xe4)]),
)
def testBERBaseEquality(self):
"""BER objects equal BER objects with same type and content"""
for class_, args in self.valuesToTest:
x=class_(*args)
y=class_(*args)
assert x==x
assert x==y
def testBERBaseInEquality(self):
"""BER objects do not equal BER objects with different type or content"""
for i in xrange(len(self.valuesToTest)):
for j in xrange(len(self.valuesToTest)):
if i!=j:
i_class, i_args = self.valuesToTest[i]
j_class, j_args = self.valuesToTest[j]
x=i_class(*i_args)
y=j_class(*j_args)
assert x!=y
class BERIntegerKnownValues(unittest.TestCase):
knownValues=(
(0, [0x02, 0x01, 0]),
(1, [0x02, 0x01, 1]),
(2, [0x02, 0x01, 2]),
(125, [0x02, 0x01, 125]),
(126, [0x02, 0x01, 126]),
(127, [0x02, 0x01, 127]),
(-1, [0x02, 0x01, 256-1]),
(-2, [0x02, 0x01, 256-2]),
(-3, [0x02, 0x01, 256-3]),
(-126, [0x02, 0x01, 256-126]),
(-127, [0x02, 0x01, 256-127]),
(-128, [0x02, 0x01, 256-128]),
(-129, [0x02, 0x02, 256-1, 256-129]),
(128, [0x02, 0x02, 0, 128]),
(256, [0x02, 0x02, 1, 0]),
)
def testToBERIntegerKnownValues(self):
"""str(BERInteger(n)) should give known result with known input"""
for integer, encoded in self.knownValues:
result = pureber.BERInteger(integer)
result = str(result)
result = map(ord, result)
assert encoded==result
def testFromBERIntegerKnownValues(self):
"""BERInteger(encoded="...") should give known result with known input"""
for integer, encoded in self.knownValues:
m=s(*encoded)
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), m)
self.assertEquals(bytes, len(m))
assert isinstance(result, pureber.BERInteger)
result = result.value
assert integer==result
def testPartialBERIntegerEncodings(self):
"""BERInteger(encoded="...") with too short input should throw BERExceptionInsufficientData"""
m=str(pureber.BERInteger(42))
assert len(m)==3
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:2])
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:1])
self.assertEquals((None, 0), pureber.berDecodeObject(pureber.BERDecoderContext(), ''))
class BERIntegerSanityCheck(unittest.TestCase):
def testSanity(self):
"""BERInteger(encoded=BERInteger(n)).value==n for -1000..1000"""
for n in range(-1000, 1001, 10):
encoded = str(pureber.BERInteger(n))
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), encoded)
self.assertEquals(bytes, len(encoded))
assert isinstance(result, pureber.BERInteger)
result = result.value
assert n==result
class ObjectThatCanStringify(object):
def __str__(self):
return "bar"
class BEROctetStringKnownValues(unittest.TestCase):
knownValues=(
("", [0x04, 0]),
("foo", [0x04, 3]+l("foo")),
(100*"x", [0x04, 100]+l(100*"x")),
(ObjectThatCanStringify(), [0x04, 3]+l("bar")),
)
def testToBEROctetStringKnownValues(self):
"""str(BEROctetString(n)) should give known result with known input"""
for st, encoded in self.knownValues:
result = pureber.BEROctetString(st)
result = str(result)
result = map(ord, result)
assert encoded==result
def testFromBEROctetStringKnownValues(self):
"""BEROctetString(encoded="...") should give known result with known input"""
for st, encoded in self.knownValues:
m=s(*encoded)
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), m)
self.assertEquals(bytes, len(m))
assert isinstance(result, pureber.BEROctetString)
result = str(result)
result = map(ord, result)
assert encoded==result
def testPartialBEROctetStringEncodings(self):
"""BEROctetString(encoded="...") with too short input should throw BERExceptionInsufficientData"""
m=str(pureber.BEROctetString("x"))
assert len(m)==3
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:2])
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:1])
self.assertEquals((None, 0), pureber.berDecodeObject(pureber.BERDecoderContext(), ''))
class BEROctetStringSanityCheck(unittest.TestCase):
def testSanity(self):
"""BEROctetString(encoded=BEROctetString(n*'x')).value==n*'x' for some values of n"""
for n in 0,1,2,3,4,5,6,100,126,127,128,129,1000,2000:
encoded = str(pureber.BEROctetString(n*'x'))
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), encoded)
self.assertEquals(bytes, len(encoded))
assert isinstance(result, pureber.BEROctetString)
result = result.value
assert n*'x'==result
class BERNullKnownValues(unittest.TestCase):
def testToBERNullKnownValues(self):
"""str(BERNull()) should give known result"""
result = pureber.BERNull()
result = str(result)
result = map(ord, result)
assert [0x05, 0x00]==result
def testFromBERNullKnownValues(self):
"""BERNull(encoded="...") should give known result with known input"""
encoded=[0x05, 0x00]
m=s(*encoded)
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), m)
self.assertEquals(bytes, len(m))
assert isinstance(result, pureber.BERNull)
assert 0x05==result.tag
def testPartialBERNullEncodings(self):
"""BERNull(encoded="...") with too short input should throw BERExceptionInsufficientData"""
m=str(pureber.BERNull())
assert len(m)==2
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:1])
self.assertEquals((None, 0), pureber.berDecodeObject(pureber.BERDecoderContext(), ''))
class BERBooleanKnownValues(unittest.TestCase):
knownValues=(
(0, [0x01, 0x01, 0], 0),
(1, [0x01, 0x01, 0xFF], 0xFF),
(2, [0x01, 0x01, 0xFF], 0xFF),
(125, [0x01, 0x01, 0xFF], 0xFF),
(126, [0x01, 0x01, 0xFF], 0xFF),
(127, [0x01, 0x01, 0xFF], 0xFF),
(-1, [0x01, 0x01, 0xFF], 0xFF),
(-2, [0x01, 0x01, 0xFF], 0xFF),
(-3, [0x01, 0x01, 0xFF], 0xFF),
(-126, [0x01, 0x01, 0xFF], 0xFF),
(-127, [0x01, 0x01, 0xFF], 0xFF),
(-128, [0x01, 0x01, 0xFF], 0xFF),
(-129, [0x01, 0x01, 0xFF], 0xFF),
(-9999, [0x01, 0x01, 0xFF], 0xFF),
(128, [0x01, 0x01, 0xFF], 0xFF),
(255, [0x01, 0x01, 0xFF], 0xFF),
(256, [0x01, 0x01, 0xFF], 0xFF),
(9999, [0x01, 0x01, 0xFF], 0xFF),
)
def testToBERBooleanKnownValues(self):
"""str(BERBoolean(n)) should give known result with known input"""
for integer, encoded, dummy in self.knownValues:
result = pureber.BERBoolean(integer)
result = str(result)
result = map(ord, result)
assert encoded==result
def testFromBERBooleanKnownValues(self):
"""BERBoolean(encoded="...") should give known result with known input"""
for integer, encoded, canon in self.knownValues:
m=s(*encoded)
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), m)
self.assertEquals(bytes, len(m))
assert isinstance(result, pureber.BERBoolean)
result = result.value
assert result==canon
def testPartialBERBooleanEncodings(self):
"""BERBoolean(encoded="...") with too short input should throw BERExceptionInsufficientData"""
m=str(pureber.BERBoolean(42))
assert len(m)==3
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:2])
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:1])
self.assertEquals((None, 0), pureber.berDecodeObject(pureber.BERDecoderContext(), ''))
class BEREnumeratedKnownValues(unittest.TestCase):
knownValues=(
(0, [0x0a, 0x01, 0]),
(1, [0x0a, 0x01, 1]),
(2, [0x0a, 0x01, 2]),
(125, [0x0a, 0x01, 125]),
(126, [0x0a, 0x01, 126]),
(127, [0x0a, 0x01, 127]),
(-1, [0x0a, 0x01, 256-1]),
(-2, [0x0a, 0x01, 256-2]),
(-3, [0x0a, 0x01, 256-3]),
(-126, [0x0a, 0x01, 256-126]),
(-127, [0x0a, 0x01, 256-127]),
(-128, [0x0a, 0x01, 256-128]),
(-129, [0x0a, 0x02, 256-1, 256-129]),
(128, [0x0a, 0x02, 0, 128]),
(256, [0x0a, 0x02, 1, 0]),
)
def testToBEREnumeratedKnownValues(self):
"""str(BEREnumerated(n)) should give known result with known input"""
for integer, encoded in self.knownValues:
result = pureber.BEREnumerated(integer)
result = str(result)
result = map(ord, result)
assert encoded==result
def testFromBEREnumeratedKnownValues(self):
"""BEREnumerated(encoded="...") should give known result with known input"""
for integer, encoded in self.knownValues:
m=s(*encoded)
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), m)
self.assertEquals(bytes, len(m))
assert isinstance(result, pureber.BEREnumerated)
result = result.value
assert integer==result
def testPartialBEREnumeratedEncodings(self):
"""BEREnumerated(encoded="...") with too short input should throw BERExceptionInsufficientData"""
m=str(pureber.BEREnumerated(42))
assert len(m)==3
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:2])
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:1])
self.assertEquals((None, 0), pureber.berDecodeObject(pureber.BERDecoderContext(), ''))
class BEREnumeratedSanityCheck(unittest.TestCase):
def testSanity(self):
"""BEREnumerated(encoded=BEREnumerated(n)).value==n for -1000..1000"""
for n in range(-1000, 1001, 10):
encoded = str(pureber.BEREnumerated(n))
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), encoded)
self.assertEquals(bytes, len(encoded))
assert isinstance(result, pureber.BEREnumerated)
result = result.value
assert n==result
class BERSequenceKnownValues(unittest.TestCase):
knownValues=(
([], [0x30, 0x00]),
([pureber.BERInteger(2)], [0x30, 0x03, 0x02, 0x01, 2]),
([pureber.BERInteger(3)], [0x30, 0x03, 0x02, 0x01, 3]),
([pureber.BERInteger(128)], [0x30, 0x04, 0x02, 0x02, 0, 128]),
([pureber.BERInteger(2), pureber.BERInteger(3), pureber.BERInteger(128)],
[0x30, 0x0a]+[0x02, 0x01, 2]+[0x02, 0x01, 3]+[0x02, 0x02, 0, 128]),
)
def testToBERSequenceKnownValues(self):
"""str(BERSequence(x)) should give known result with known input"""
for content, encoded in self.knownValues:
result = pureber.BERSequence(content)
result = str(result)
result = map(ord, result)
assert encoded==result
def testFromBERSequenceKnownValues(self):
"""BERSequence(encoded="...") should give known result with known input"""
for content, encoded in self.knownValues:
m=s(*encoded)
result, bytes = pureber.berDecodeObject(pureber.BERDecoderContext(), m)
self.assertEquals(bytes, len(m))
assert isinstance(result, pureber.BERSequence)
result = result.data
assert len(content)==len(result)
for i in xrange(len(content)):
assert content[i]==result[i]
assert content==result
def testPartialBERSequenceEncodings(self):
"""BERSequence(encoded="...") with too short input should throw BERExceptionInsufficientData"""
m=str(pureber.BERSequence([pureber.BERInteger(2)]))
assert len(m)==5
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:4])
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:3])
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:2])
self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:1])
self.assertEquals((None, 0), pureber.berDecodeObject(pureber.BERDecoderContext(), ''))
# TODO BERSequenceOf
# TODO BERSet
ldaptor-0.0.43/ldaptor/test/test_connector.py 0000644 0001750 0001750 00000003607 10345261504 017402 0 ustar jan jan from twisted.trial import unittest
from twisted.internet import reactor, protocol, address
from ldaptor.protocols.ldap import ldapconnector, distinguishedname
class FakeProto(protocol.Protocol):
pass
class TestCallableOverride(unittest.TestCase):
"""
Callable values in serviceLocationOverride get to override the
whole connecting process.
"""
def testSimple(self):
dn = distinguishedname.DistinguishedName('dc=example,dc=com')
c = ldapconnector.LDAPClientCreator(reactor, FakeProto)
def _doConnect(factory):
factory.doStart()
factory.startedConnecting(c)
proto = factory.buildProtocol(address.IPv4Address('TCP', 'localhost', '1'))
d = c.connect(dn, overrides={ dn: _doConnect, })
def cb(r):
self.failUnless(isinstance(r, FakeProto))
d.addCallback(cb)
return d
def testFindOverride_plainString(self):
"""Plain strings work as override keys."""
c=ldapconnector.LDAPConnector(reactor=None,
dn='dc=example,dc=com',
factory=None)
o=c._findOverRide(dn=distinguishedname.DistinguishedName('cn=foo,dc=example,dc=com'),
overrides={
'dc=example,dc=com': ('server.example.com', 1389),
})
self.assertEquals(o, ('server.example.com', 1389))
def testFindOverride_root(self):
"""Empty dn can be used as override."""
c=ldapconnector.LDAPConnector(reactor=None,
dn='dc=example,dc=com',
factory=None)
o=c._findOverRide(dn=distinguishedname.DistinguishedName('cn=foo,dc=example,dc=com'),
overrides={
'': ('server.example.com', 1389),
})
self.assertEquals(o, ('server.example.com', 1389))
ldaptor-0.0.43/ldaptor/test/test_ldifdelta.py 0000644 0001750 0001750 00000014741 10344407651 017345 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.ldifdelta
"""
from twisted.trial import unittest
from ldaptor.protocols.ldap import ldifdelta
from ldaptor import delta, entry
class LDIFDeltaDriver(ldifdelta.LDIFDelta):
def __init__(self):
self.listOfCompleted = []
def gotEntry(self, obj):
self.listOfCompleted.append(obj)
"""
changerecord = "changetype:" FILL
(change-add / change-delete /
change-modify / change-moddn)
change-add = "add" SEP 1*attrval-spec
change-delete = "delete" SEP
change-moddn = ("modrdn" / "moddn") SEP
"newrdn:" ( FILL rdn /
":" FILL base64-rdn) SEP
"deleteoldrdn:" FILL ("0" / "1") SEP
0*1("newsuperior:"
( FILL distinguishedName /
":" FILL base64-distinguishedName) SEP)
change-modify = "modify" SEP *mod-spec
mod-spec = ("add:" / "delete:" / "replace:")
FILL AttributeDescription SEP
*attrval-spec
"-" SEP
"""
"""
version: 1
dn: cn=foo,dc=example,dc=com
changetype: delete
"""
"""
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modrdn #OR moddn
newrdn: rdn
deleteoldrdn: 0 #OR 1
#0..1 newsuperior: distinguishedName
"""
class TestLDIFDeltaParsing(unittest.TestCase):
def testModification_empty(self):
proto = LDIFDeltaDriver()
proto.dataReceived("""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modify
""")
proto.connectionLost()
self.assertEqual(proto.listOfCompleted,
[
delta.ModifyOp(dn='cn=foo,dc=example,dc=com'),
])
def testModification_oneAdd(self):
proto = LDIFDeltaDriver()
proto.dataReceived("""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modify
add: foo
foo: bar
-
""")
proto.connectionLost()
self.assertEqual(
proto.listOfCompleted,
[delta.ModifyOp(dn='cn=foo,dc=example,dc=com',
modifications=[delta.Add('foo', ['bar']),
]),
])
def testModification_twoAdds(self):
proto = LDIFDeltaDriver()
proto.dataReceived("""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modify
add: foo
foo: bar
-
add: thud
thud: quux
thud: baz
-
""")
proto.connectionLost()
self.assertEqual(
proto.listOfCompleted,
[delta.ModifyOp(dn='cn=foo,dc=example,dc=com',
modifications=[delta.Add('foo', ['bar']),
delta.Add('thud', ['quux', 'baz']),
]),
])
def testModification_complex(self):
proto = LDIFDeltaDriver()
proto.dataReceived("""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modify
delete: foo
foo: bar
-
delete: garply
-
add: thud
thud: quux
thud: baz
-
replace: waldo
-
add: foo
foo: baz
-
replace: thud
thud: xyzzy
-
add: silly
-
""")
proto.connectionLost()
self.assertEqual(
proto.listOfCompleted,
[delta.ModifyOp(dn='cn=foo,dc=example,dc=com',
modifications=[delta.Delete('foo', ['bar']),
delta.Delete('garply'),
delta.Add('thud', ['quux', 'baz']),
delta.Replace('waldo'),
delta.Add('foo', ['baz']),
delta.Replace('thud', ['xyzzy']),
delta.Add('silly'),
]),
])
def testModification_fail_noDash_1(self):
proto = LDIFDeltaDriver()
self.assertRaises(ldifdelta.LDIFDeltaModificationMissingEndDashError,
proto.dataReceived,
"""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modify
add: foo
foo: bar
""")
def testModification_fail_noDash_2(self):
proto = LDIFDeltaDriver()
self.assertRaises(ldifdelta.LDIFDeltaModificationMissingEndDashError,
proto.dataReceived,
"""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modify
add: foo
""")
def testModification_fail_differentKey(self):
proto = LDIFDeltaDriver()
self.assertRaises(ldifdelta.LDIFDeltaModificationDifferentAttributeTypeError,
proto.dataReceived,
"""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modify
add: foo
bar: quux
-
""")
def testModification_fail_unknownModSpec(self):
proto = LDIFDeltaDriver()
self.assertRaises(ldifdelta.LDIFDeltaUnknownModificationError,
proto.dataReceived,
"""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: modify
fiddle: foo
foo: bar
-
""")
def testNoChangeType(self):
proto = LDIFDeltaDriver()
self.assertRaises(ldifdelta.LDIFDeltaMissingChangeTypeError,
proto.dataReceived,
"""\
version: 1
dn: cn=foo,dc=example,dc=com
add: foo
foo: bar
-
""")
def testAdd(self):
proto = LDIFDeltaDriver()
proto.dataReceived("""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: add
foo: bar
thud: quux
thud: baz
""")
proto.connectionLost()
self.assertEqual(proto.listOfCompleted,
[delta.AddOp(entry.BaseLDAPEntry(
dn='cn=foo,dc=example,dc=com',
attributes={
'foo': ['bar'],
'thud': ['quux', 'baz'],
}))])
def testAdd_fail_noAttrvals(self):
proto = LDIFDeltaDriver()
self.assertRaises(ldifdelta.LDIFDeltaAddMissingAttributesError,
proto.dataReceived, """\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: add
""")
def testDelete(self):
proto = LDIFDeltaDriver()
proto.dataReceived("""\
version: 1
dn: cn=foo,dc=example,dc=com
changetype: delete
""")
proto.connectionLost()
self.assertEqual(proto.listOfCompleted,
[delta.DeleteOp(dn='cn=foo,dc=example,dc=com')])
ldaptor-0.0.43/ldaptor/test/test_match.py 0000644 0001750 0001750 00000036076 10345037720 016513 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.ldapserver module.
"""
from twisted.trial import unittest
from ldaptor import inmemory
from ldaptor.protocols import pureldap, pureber
from ldaptor.protocols.ldap import ldapsyntax
class TestEntryMatch(unittest.TestCase):
def test_matchAll(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilterMatchAll)
self.assertEquals(result, True)
def test_present_match(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_present('aValue'))
self.assertEquals(result, True)
def test_present_noMatch(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_present('noSuchValue'))
self.assertEquals(result, False)
def test_and_match(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(
pureldap.LDAPFilter_and([
pureldap.LDAPFilter_present('aValue'),
pureldap.LDAPFilter_present('bValue'),
]))
self.assertEquals(result, True)
def test_and_noMatch(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(
pureldap.LDAPFilter_and([
pureldap.LDAPFilter_present('cValue'),
pureldap.LDAPFilter_present('dValue'),
]))
self.assertEquals(result, False)
def test_or_match(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(
pureldap.LDAPFilter_or([
pureldap.LDAPFilter_present('cValue'),
pureldap.LDAPFilter_present('bValue'),
]))
self.assertEquals(result, True)
def test_or_noMatch(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(
pureldap.LDAPFilter_or([
pureldap.LDAPFilter_present('cValue'),
pureldap.LDAPFilter_present('dValue'),
]))
self.assertEquals(result, False)
def test_not(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(
pureldap.LDAPFilter_not(
pureldap.LDAPFilter_or([
pureldap.LDAPFilter_present('cValue'),
pureldap.LDAPFilter_present('dValue'),
])))
self.assertEquals(result, True)
def test_equality_match(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureber.BEROctetString('aValue'),
assertionValue=pureber.BEROctetString('a')))
self.assertEquals(result, True)
def test_equality_match_caseInsensitive(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureber.BEROctetString('avaLUe'),
assertionValue=pureber.BEROctetString('A')))
self.assertEquals(result, True)
def test_equality_noMatch(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureber.BEROctetString('aValue'),
assertionValue=pureber.BEROctetString('b')))
self.assertEquals(result, False)
def test_substrings_match(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('a'),
]))
self.assertEquals(result, True)
def test_substrings_match2(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['abcde'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('a'),
pureldap.LDAPFilter_substrings_final('e'),
]))
self.assertEquals(result, True)
def test_substrings_match3(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['abcde'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('a'),
pureldap.LDAPFilter_substrings_any('c'),
pureldap.LDAPFilter_substrings_final('e'),
]))
self.assertEquals(result, True)
def test_substrings_match4(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['abcde'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('a'),
pureldap.LDAPFilter_substrings_any('b'),
pureldap.LDAPFilter_substrings_any('c'),
pureldap.LDAPFilter_substrings_any('d'),
pureldap.LDAPFilter_substrings_final('e'),
]))
self.assertEquals(result, True)
def test_substrings_match5(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['aoeuboeucoeudoeue'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('a'),
pureldap.LDAPFilter_substrings_any('b'),
pureldap.LDAPFilter_substrings_any('c'),
pureldap.LDAPFilter_substrings_any('d'),
pureldap.LDAPFilter_substrings_final('e'),
]))
self.assertEquals(result, True)
def test_substrings_match6(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['aBCdE'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('A'),
pureldap.LDAPFilter_substrings_any('b'),
pureldap.LDAPFilter_substrings_any('C'),
pureldap.LDAPFilter_substrings_any('D'),
pureldap.LDAPFilter_substrings_final('e'),
]))
self.assertEquals(result, True)
def test_substrings_match7(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['Foo'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('f'),
]))
self.assertEquals(result, True)
def test_substrings_noMatch(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['a'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('bad'),
pureldap.LDAPFilter_substrings_any('dog'),
pureldap.LDAPFilter_substrings_any('no'),
pureldap.LDAPFilter_substrings_final('bone'),
]))
self.assertEquals(result, False)
def test_substrings_noMatch2(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['aoeuboeucoeudoeue'],
'bValue': ['b'],
})
result = o.match(pureldap.LDAPFilter_substrings(
type='aValue',
substrings=[
pureldap.LDAPFilter_substrings_initial('a'),
pureldap.LDAPFilter_substrings_any('b'),
pureldap.LDAPFilter_substrings_any('Z'),
pureldap.LDAPFilter_substrings_any('d'),
pureldap.LDAPFilter_substrings_final('e'),
]))
self.assertEquals(result, False)
def test_greaterOrEqual_noMatch_nosuchattr(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'num': [4],
})
result = o.match(pureldap.LDAPFilter_greaterOrEqual('foo',
42))
self.assertEquals(result, False)
def test_greaterOrEqual_match_greater(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'num': [4],
})
result = o.match(pureldap.LDAPFilter_greaterOrEqual('num',
3))
self.assertEquals(result, True)
def test_greaterOrEqual_match_equal(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'num': [4],
})
result = o.match(pureldap.LDAPFilter_greaterOrEqual('num',
4))
self.assertEquals(result, True)
def test_greaterOrEqual_noMatch(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'bValue': [4],
})
result = o.match(pureldap.LDAPFilter_greaterOrEqual('num',
5))
self.assertEquals(result, False)
def test_lessOrEqual_noMatch_nosuchattr(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'num': [4],
})
result = o.match(pureldap.LDAPFilter_lessOrEqual('foo',
42))
self.assertEquals(result, False)
def test_lessOrEqual_match_less(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'num': [4],
})
result = o.match(pureldap.LDAPFilter_lessOrEqual('num',
5))
self.assertEquals(result, True)
def test_lessOrEqual_match_equal(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'num': [4],
})
result = o.match(pureldap.LDAPFilter_lessOrEqual('num',
4))
self.assertEquals(result, True)
def test_lessOrEqual_noMatch(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'num': [4],
})
result = o.match(pureldap.LDAPFilter_lessOrEqual('num',
3))
self.assertEquals(result, False)
def test_notImplemented(self):
o=inmemory.ReadOnlyInMemoryLDAPEntry(dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['a', 'b'],
'aValue': ['b'],
'num': [4],
})
class UnknownMatch(object): pass
unknownMatch = UnknownMatch()
self.assertRaises(ldapsyntax.MatchNotImplemented,
o.match, unknownMatch)
# TODO LDAPFilter_approxMatch
# TODO LDAPFilter_extensibleMatch
ldaptor-0.0.43/ldaptor/test/test_inmemory.py 0000644 0001750 0001750 00000045661 10352535700 017255 0 ustar jan jan """
Test cases for ldaptor.inmemory module.
"""
from twisted.trial import unittest
from cStringIO import StringIO
from ldaptor import inmemory, delta, testutil
from ldaptor.protocols.ldap import distinguishedname, ldaperrors
class TestInMemoryDatabase(unittest.TestCase):
def setUp(self):
self.root = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
self.meta=self.root.addChild(
rdn='ou=metasyntactic',
attributes={
'objectClass': ['a', 'b'],
'ou': ['metasyntactic'],
})
self.foo=self.meta.addChild(
rdn='cn=foo',
attributes={
'objectClass': ['a', 'b'],
'cn': ['foo'],
})
self.bar=self.meta.addChild(
rdn='cn=bar',
attributes={
'objectClass': ['a', 'b'],
'cn': ['bar'],
})
self.empty=self.root.addChild(
rdn='ou=empty',
attributes={
'objectClass': ['a', 'b'],
'ou': ['empty'],
})
self.oneChild=self.root.addChild(
rdn='ou=oneChild',
attributes={
'objectClass': ['a', 'b'],
'ou': ['oneChild'],
})
self.theChild=self.oneChild.addChild(
rdn='cn=theChild',
attributes={
'objectClass': ['a', 'b'],
'cn': ['theChild'],
})
def test_children_empty(self):
d = self.empty.children()
d.addCallback(self.assertEquals, [])
return d
def test_children_oneChild(self):
d = self.oneChild.children()
def cb(children):
self.assertEquals(len(children), 1)
got = [e.dn for e in children]
want = [distinguishedname.DistinguishedName('cn=theChild,ou=oneChild,dc=example,dc=com')]
got.sort()
want.sort()
self.assertEquals(got, want)
d.addCallback(cb)
return d
def test_children_repeat(self):
"""Test that .children() returns a copy of the data so that modifying it does not affect behaviour."""
d = self.oneChild.children()
def cb1(children1):
self.assertEquals(len(children1), 1)
children1.pop()
d = self.oneChild.children()
return d
d.addCallback(cb1)
def cb2(children2):
self.assertEquals(len(children2), 1)
d.addCallback(cb2)
return d
def test_children_twoChildren(self):
d = self.meta.children()
def cb(children):
self.assertEquals(len(children), 2)
want = [
distinguishedname.DistinguishedName('cn=foo,ou=metasyntactic,dc=example,dc=com'),
distinguishedname.DistinguishedName('cn=bar,ou=metasyntactic,dc=example,dc=com'),
]
got = [e.dn for e in children]
self.assertEquals(got, want)
d.addCallback(cb)
return d
def test_addChild(self):
self.empty.addChild(
rdn='a=b',
attributes={
'objectClass': ['a', 'b'],
'a': 'b',
})
d = self.empty.children()
def cb(children):
self.assertEquals(len(children), 1)
got = [e.dn for e in children]
want = [
distinguishedname.DistinguishedName('a=b,ou=empty,dc=example,dc=com'),
]
got.sort()
want.sort()
self.assertEquals(got, want)
d.addCallback(cb)
return d
def test_addChild_Exists(self):
self.assertRaises(ldaperrors.LDAPEntryAlreadyExists,
self.meta.addChild,
rdn='cn=foo',
attributes={
'objectClass': ['a'],
'cn': 'foo',
})
def test_parent(self):
self.assertEquals(self.foo.parent(), self.meta)
self.assertEquals(self.meta.parent(), self.root)
self.assertEquals(self.root.parent(), None)
def test_subtree_empty(self):
d = self.empty.subtree()
def cb(entries):
self.assertEquals(len(entries), 1)
d.addCallback(cb)
return d
def test_subtree_oneChild(self):
d = self.oneChild.subtree()
d.addCallback(self.assertEquals, [
self.oneChild,
self.theChild,
])
return d
def test_subtree_oneChild_cb(self):
got = []
d = self.oneChild.subtree(got.append)
d.addCallback(self.assertEquals, None)
def cb(dummy):
want = [
self.oneChild,
self.theChild,
]
self.assertEquals(got, want)
d.addCallback(cb)
return d
def test_subtree_many(self):
d = self.root.subtree()
def cb(results):
got = results
want = [
self.root,
self.oneChild,
self.theChild,
self.empty,
self.meta,
self.bar,
self.foo,
]
self.assertEquals(got, want)
d.addCallback(cb)
return d
def test_subtree_many_cb(self):
got = []
d = self.root.subtree(callback=got.append)
def cb(r):
self.assertEquals(r, None)
want = [
self.root,
self.oneChild,
self.theChild,
self.empty,
self.meta,
self.bar,
self.foo,
]
self.assertEquals(got, want)
d.addCallback(cb)
return d
def test_lookup_fail(self):
dn = distinguishedname.DistinguishedName('cn=thud,ou=metasyntactic,dc=example,dc=com')
d = self.root.lookup(dn)
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
self.assertEquals(fail.value.message, dn)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_lookup_fail_outOfTree(self):
dn = distinguishedname.DistinguishedName('dc=invalid')
d = self.root.lookup(dn)
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
self.assertEquals(fail.value.message, dn)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_lookup_deep(self):
dn = distinguishedname.DistinguishedName('cn=bar,ou=metasyntactic,dc=example,dc=com')
d = self.root.lookup(dn)
d.addCallback(self.assertEquals, self.bar)
return d
def test_delete_root(self):
newRoot = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
d = newRoot.delete()
def eb(fail):
fail.trap(inmemory.LDAPCannotRemoveRootError)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_delete_nonLeaf(self):
d = self.meta.delete()
def eb(fail):
fail.trap(ldaperrors.LDAPNotAllowedOnNonLeaf)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_delete(self):
d = self.foo.delete()
d.addCallback(self.assertEquals, self.foo)
d.addCallback(lambda _: self.meta.children())
d.addCallback(self.assertEquals, [self.bar])
return d
def test_deleteChild(self):
d = self.meta.deleteChild('cn=bar')
d.addCallback(self.assertEquals, self.bar)
d.addCallback(lambda _: self.meta.children())
d.addCallback(self.assertEquals, [self.foo])
return d
def test_deleteChild_NonExisting(self):
d = self.root.deleteChild('cn=not-exist')
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
d.addCallbacks(testutil.mustRaise, eb)
return d
def test_setPassword(self):
self.foo.setPassword('s3krit', salt='\xf2\x4a')
self.failUnless('userPassword' in self.foo)
self.assertEquals(self.foo['userPassword'],
['{SSHA}0n/Iw1NhUOKyaI9gm9v5YsO3ZInySg=='])
def test_setPassword_noSalt(self):
self.foo.setPassword('s3krit')
self.failUnless('userPassword' in self.foo)
d = self.foo.bind('s3krit')
d.addCallback(self.assertIdentical, self.foo)
d.addCallback(lambda _: self.foo.bind('s4krit'))
def eb(fail):
fail.trap(ldaperrors.LDAPInvalidCredentials)
d.addCallbacks(testutil.mustRaise, eb)
return d
def testSearch_withCallback(self):
got = []
d = self.root.search(filterText='(|(cn=foo)(cn=bar))',
callback=got.append)
def cb(r):
self.assertEquals(r, None)
want = [
self.bar,
self.foo,
]
self.assertEquals(got, want)
d.addCallback(cb)
return d
def testSearch_withoutCallback(self):
d = self.root.search(filterText='(|(cn=foo)(cn=bar))')
d.addCallback(self.assertEquals, [
self.bar,
self.foo,
])
return d
def test_move_noChildren_sameSuperior(self):
d = self.empty.move('ou=moved,dc=example,dc=com')
def getChildren(dummy):
return self.root.children()
d.addCallback(getChildren)
d.addCallback(self.assertEquals, [
self.meta,
inmemory.ReadOnlyInMemoryLDAPEntry(
dn='ou=moved,dc=example,dc=com',
attributes={ 'objectClass': ['a', 'b'],
'ou': ['moved'],
}),
self.oneChild,
])
return d
def test_move_children_sameSuperior(self):
d = self.meta.move('ou=moved,dc=example,dc=com')
def getChildren(dummy):
return self.root.children()
d.addCallback(getChildren)
d.addCallback(self.assertEquals, [
inmemory.ReadOnlyInMemoryLDAPEntry(
dn='ou=moved,dc=example,dc=com',
attributes={ 'objectClass': ['a', 'b'],
'ou': ['moved'],
}),
self.empty,
self.oneChild,
])
return d
def test_move_noChildren_newSuperior(self):
d = self.empty.move('ou=moved,ou=oneChild,dc=example,dc=com')
def getChildren(dummy):
return self.root.children()
d.addCallback(getChildren)
d.addCallback(self.assertEquals, [
self.meta,
self.oneChild,
])
def getChildren2(dummy):
return self.oneChild.children()
d.addCallback(getChildren2)
d.addCallback(self.assertEquals, [
self.theChild,
inmemory.ReadOnlyInMemoryLDAPEntry(
dn='ou=moved,ou=oneChild,dc=example,dc=com',
attributes={ 'objectClass': ['a', 'b'],
'ou': ['moved'],
}),
])
return d
def test_move_children_newSuperior(self):
d = self.meta.move('ou=moved,ou=oneChild,dc=example,dc=com')
def getChildren(dummy):
return self.root.children()
d.addCallback(getChildren)
d.addCallback(self.assertEquals, [
self.empty,
self.oneChild,
])
def getChildren2(dummy):
return self.oneChild.children()
d.addCallback(getChildren2)
d.addCallback(self.assertEquals, [
self.theChild,
inmemory.ReadOnlyInMemoryLDAPEntry(
dn='ou=moved,ou=oneChild,dc=example,dc=com',
attributes={ 'objectClass': ['a', 'b'],
'ou': ['moved'],
}),
])
return d
def test_commit(self):
"""ReadOnlyInMemoryLDAPEntry.commit() succeeds immediately."""
self.meta['foo'] = ['bar']
d = self.meta.commit()
self.failUnless(d.called)
d.addCallback(self.assertIdentical, self.meta)
return d
class FromLDIF(unittest.TestCase):
def test_single(self):
ldif = StringIO('''\
dn: cn=foo,dc=example,dc=com
objectClass: a
objectClass: b
aValue: a
aValue: b
bValue: c
''')
d = inmemory.fromLDIFFile(ldif)
def cb1(db):
self.assertEquals(
db.dn,
distinguishedname.DistinguishedName('cn=foo,dc=example,dc=com'))
return db.children()
d.addCallback(cb1)
d.addCallback(self.assertEquals, [])
return d
def test_two(self):
ldif = StringIO('''\
dn: dc=example,dc=com
objectClass: dcObject
dc: example
dn: cn=foo,dc=example,dc=com
objectClass: a
cn: foo
''')
d = inmemory.fromLDIFFile(ldif)
def cb1(db):
self.assertEquals(
db.dn,
distinguishedname.DistinguishedName('dc=example,dc=com'))
return db.subtree()
d.addCallback(cb1)
def cb2(children):
self.assertEquals(len(children), 2)
want = [
distinguishedname.DistinguishedName('dc=example,dc=com'),
distinguishedname.DistinguishedName('cn=foo,dc=example,dc=com'),
]
got = [e.dn for e in children]
self.assertEquals(got, want)
d.addCallback(cb2)
return d
def test_missingNode(self):
ldif = StringIO('''\
dn: dc=example,dc=com
objectClass: dcObject
dc: example
dn: cn=foo,ou=nonexisting,dc=example,dc=com
objectClass: a
cn: foo
''')
d = inmemory.fromLDIFFile(ldif)
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
self.failUnlessEqual(
str(fail.value),
'noSuchObject: ou=nonexisting,dc=example,dc=com')
d.addCallbacks(testutil.mustRaise, eb)
return d
class TestDiff(unittest.TestCase):
def testNoChange(self):
a = inmemory.ReadOnlyInMemoryLDAPEntry('dc=example,dc=com',
{
'dc': ['example'],
})
b = inmemory.ReadOnlyInMemoryLDAPEntry('dc=example,dc=com',
{
'dc': ['example'],
})
d = a.diffTree(b)
d.addCallback(self.assertEquals, [])
return d
def testRootChange_Add(self):
a = inmemory.ReadOnlyInMemoryLDAPEntry('dc=example,dc=com',
{
'dc': ['example'],
})
b = inmemory.ReadOnlyInMemoryLDAPEntry('dc=example,dc=com',
{
'dc': ['example'],
'foo': ['bar'],
})
d = a.diffTree(b)
d.addCallback(self.assertEquals,
[ delta.ModifyOp('dc=example,dc=com',
[
delta.Add('foo', ['bar']),
]),
])
return d
def testChildChange_Add(self):
a = inmemory.ReadOnlyInMemoryLDAPEntry('dc=example,dc=com',
{
'dc': ['example'],
})
a.addChild('cn=foo',
{ 'cn': ['foo'],
})
b = inmemory.ReadOnlyInMemoryLDAPEntry('dc=example,dc=com',
{
'dc': ['example'],
})
b.addChild('cn=foo',
{ 'cn': ['foo'],
'foo': ['bar'],
})
d = a.diffTree(b)
d.addCallback(self.assertEquals,
[ delta.ModifyOp('cn=foo,dc=example,dc=com',
[
delta.Add('foo', ['bar']),
]),
])
return d
def testAddChild(self):
a = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
b = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
foo=b.addChild(
rdn='cn=foo',
attributes={
'objectClass': ['a', 'b'],
'cn': ['foo'],
})
bar=b.addChild(
rdn='cn=bar',
attributes={
'objectClass': ['a', 'b'],
'cn': ['bar'],
})
d = a.diffTree(b)
d.addCallback(self.assertEquals, [
delta.AddOp(bar),
delta.AddOp(foo),
])
return d
def testAddSubtree(self):
a = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
b = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
foo=b.addChild(
rdn='ou=foo',
attributes={
'objectClass': ['a', 'b'],
'ou': ['foo'],
})
baz=foo.addChild(
rdn='cn=baz',
attributes={
'objectClass': ['a', 'b'],
'cn': ['baz'],
})
bar=b.addChild(
rdn='cn=bar',
attributes={
'objectClass': ['a', 'b'],
'cn': ['bar'],
})
d = a.diffTree(b)
d.addCallback(self.assertEquals, [
delta.AddOp(bar),
delta.AddOp(foo),
delta.AddOp(baz),
])
return d
def testDeleteChild(self):
a = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
b = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
foo=a.addChild(
rdn='cn=foo',
attributes={
'objectClass': ['a', 'b'],
'cn': ['foo'],
})
bar=a.addChild(
rdn='cn=bar',
attributes={
'objectClass': ['a', 'b'],
'cn': ['bar'],
})
d = a.diffTree(b)
d.addCallback(self.assertEquals, [
delta.DeleteOp(bar),
delta.DeleteOp(foo),
])
return d
def testDeleteSubtree(self):
a = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
b = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
foo=a.addChild(
rdn='ou=foo',
attributes={
'objectClass': ['a', 'b'],
'ou': ['foo'],
})
baz=foo.addChild(
rdn='cn=baz',
attributes={
'objectClass': ['a', 'b'],
'cn': ['baz'],
})
bar=a.addChild(
rdn='cn=bar',
attributes={
'objectClass': ['a', 'b'],
'cn': ['bar'],
})
d = a.diffTree(b)
d.addCallback(self.assertEquals, [
delta.DeleteOp(bar),
delta.DeleteOp(baz),
delta.DeleteOp(foo),
])
return d
ldaptor-0.0.43/ldaptor/test/test_delta.py 0000644 0001750 0001750 00000020616 10345261504 016500 0 ustar jan jan """
Test cases for ldaptor.protocols.ldap.delta
"""
from twisted.trial import unittest
from ldaptor import testutil
from ldaptor import delta, entry, attributeset, inmemory
from ldaptor.protocols.ldap import ldapsyntax, distinguishedname, ldaperrors
class TestModifications(unittest.TestCase):
def setUp(self):
self.foo = ldapsyntax.LDAPEntry(
None,
dn='cn=foo,dc=example,dc=com',
attributes={
'objectClass': ['person'],
'cn': ['foo', 'thud'],
'sn': ['bar'],
'more': ['junk'],
})
def testAddOld(self):
mod = delta.Add('cn', ['quux'])
mod.patch(self.foo)
self.failIf('stuff' in self.foo)
self.failUnlessEqual(self.foo['cn'], ['foo', 'thud', 'quux'])
def testAddNew(self):
mod = delta.Add('stuff', ['val1', 'val2'])
mod.patch(self.foo)
self.failUnlessEqual(self.foo['stuff'], ['val1', 'val2'])
self.failUnlessEqual(self.foo['cn'], ['foo', 'thud'])
def testDelete(self):
mod = delta.Delete('cn', ['thud'])
mod.patch(self.foo)
self.failIf('stuff' in self.foo)
self.failUnlessEqual(self.foo['cn'], ['foo'])
def testDeleteAll(self):
mod = delta.Delete('more')
mod.patch(self.foo)
self.failIf('stuff' in self.foo)
self.failUnlessEqual(self.foo['cn'], ['foo', 'thud'])
def testDelete_FailOnNonExistingAttributeType_All(self):
mod = delta.Delete('notexist', [])
self.assertRaises(KeyError,
mod.patch,
self.foo)
def testDelete_FailOnNonExistingAttributeType_OneValue(self):
mod = delta.Delete('notexist', ['a'])
self.assertRaises(KeyError,
mod.patch,
self.foo)
def testDelete_FailOnNonExistingAttributeValue(self):
mod = delta.Delete('cn', ['notexist'])
self.assertRaises(LookupError,
mod.patch,
self.foo)
def testReplace_Add(self):
mod = delta.Replace('stuff', ['val1', 'val2'])
mod.patch(self.foo)
self.failUnlessEqual(self.foo['stuff'], ['val1', 'val2'])
self.failUnlessEqual(self.foo['sn'], ['bar'])
self.failUnlessEqual(self.foo['more'], ['junk'])
def testReplace_Modify(self):
mod = delta.Replace('sn', ['baz'])
mod.patch(self.foo)
self.failIf('stuff' in self.foo)
self.failUnlessEqual(self.foo['sn'], ['baz'])
self.failUnlessEqual(self.foo['more'], ['junk'])
def testReplace_Delete_Existing(self):
mod = delta.Replace('more', [])
mod.patch(self.foo)
self.failIf('stuff' in self.foo)
self.failUnlessEqual(self.foo['sn'], ['bar'])
self.failIf('more' in self.foo)
def testReplace_Delete_NonExisting(self):
mod = delta.Replace('nonExisting', [])
mod.patch(self.foo)
self.failIf('stuff' in self.foo)
self.failUnlessEqual(self.foo['sn'], ['bar'])
self.failUnlessEqual(self.foo['more'], ['junk'])
class TestModificationOpLDIF(unittest.TestCase):
def testAdd(self):
m=delta.Add('foo', ['bar', 'baz'])
self.assertEquals(m.asLDIF(),
"""\
add: foo
foo: bar
foo: baz
-
""")
def testDelete(self):
m=delta.Delete('foo', ['bar', 'baz'])
self.assertEquals(m.asLDIF(),
"""\
delete: foo
foo: bar
foo: baz
-
""")
def testDeleteAll(self):
m=delta.Delete('foo')
self.assertEquals(m.asLDIF(),
"""\
delete: foo
-
""")
def testReplace(self):
m=delta.Replace('foo', ['bar', 'baz'])
self.assertEquals(m.asLDIF(),
"""\
replace: foo
foo: bar
foo: baz
-
""")
def testReplaceAll(self):
m=delta.Replace('thud')
self.assertEquals(m.asLDIF(),
"""\
replace: thud
-
""")
class TestAddOpLDIF(unittest.TestCase):
def testSimple(self):
op=delta.AddOp(entry.BaseLDAPEntry(
dn='dc=example,dc=com',
attributes={'foo': ['bar', 'baz'],
'quux': ['thud']}))
self.assertEquals(op.asLDIF(),
"""\
dn: dc=example,dc=com
changetype: add
foo: bar
foo: baz
quux: thud
""")
class TestDeleteOpLDIF(unittest.TestCase):
def testSimple(self):
op=delta.DeleteOp('dc=example,dc=com')
self.assertEquals(op.asLDIF(),
"""\
dn: dc=example,dc=com
changetype: delete
""")
class TestOperationLDIF(unittest.TestCase):
def testModify(self):
op=delta.ModifyOp('cn=Paula Jensen, ou=Product Development, dc=airius, dc=com',
[
delta.Add('postaladdress',
['123 Anystreet $ Sunnyvale, CA $ 94086']),
delta.Delete('description'),
delta.Replace('telephonenumber', ['+1 408 555 1234', '+1 408 555 5678']),
delta.Delete('facsimiletelephonenumber', ['+1 408 555 9876']),
])
self.assertEquals(op.asLDIF(),
"""\
dn: cn=Paula Jensen,ou=Product Development,dc=airius,dc=com
changetype: modify
add: postaladdress
postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
-
delete: description
-
replace: telephonenumber
telephonenumber: +1 408 555 1234
telephonenumber: +1 408 555 5678
-
delete: facsimiletelephonenumber
facsimiletelephonenumber: +1 408 555 9876
-
""")
class TestModificationComparison(unittest.TestCase):
def testEquality_Add_True(self):
a = delta.Add('k', ['b', 'c', 'd'])
b = delta.Add('k', ['b', 'c', 'd'])
self.assertEquals(a, b)
def testEquality_AddVsDelete_False(self):
a = delta.Add('k', ['b', 'c', 'd'])
b = delta.Delete('k', ['b', 'c', 'd'])
self.assertNotEquals(a, b)
def testEquality_AttributeSet_False(self):
a = delta.Add('k', ['b', 'c', 'd'])
b = attributeset.LDAPAttributeSet('k', ['b', 'c', 'd'])
self.assertNotEquals(a, b)
def testEquality_List_False(self):
a = delta.Add('k', ['b', 'c', 'd'])
b = ['b', 'c', 'd']
self.assertNotEquals(a, b)
class TestOperations(unittest.TestCase):
def setUp(self):
self.root = inmemory.ReadOnlyInMemoryLDAPEntry(
dn=distinguishedname.DistinguishedName('dc=example,dc=com'))
self.meta=self.root.addChild(
rdn='ou=metasyntactic',
attributes={
'objectClass': ['a', 'b'],
'ou': ['metasyntactic'],
})
self.foo=self.meta.addChild(
rdn='cn=foo',
attributes={
'objectClass': ['a', 'b'],
'cn': ['foo'],
})
self.bar=self.meta.addChild(
rdn='cn=bar',
attributes={
'objectClass': ['a', 'b'],
'cn': ['bar'],
})
self.empty=self.root.addChild(
rdn='ou=empty',
attributes={
'objectClass': ['a', 'b'],
'ou': ['empty'],
})
self.oneChild=self.root.addChild(
rdn='ou=oneChild',
attributes={
'objectClass': ['a', 'b'],
'ou': ['oneChild'],
})
self.theChild=self.oneChild.addChild(
rdn='cn=theChild',
attributes={
'objectClass': ['a', 'b'],
'cn': ['theChild'],
})
def testAddOp_DNExists(self):
foo2 = entry.BaseLDAPEntry(
dn='cn=foo,ou=metasyntactic,dc=example,dc=com',
attributes={'foo': ['bar', 'baz'],
'quux': ['thud']})
op = delta.AddOp(foo2)
d = op.patch(self.root)
def eb(fail):
fail.trap(ldaperrors.LDAPEntryAlreadyExists)
d.addCallbacks(testutil.mustRaise, eb)
return d
def testDeleteOp_DNNotFound(self):
op = delta.DeleteOp('cn=nope,dc=example,dc=com')
d = op.patch(self.root)
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
d.addCallbacks(testutil.mustRaise, eb)
return d
def testModifyOp_DNNotFound(self):
op = delta.ModifyOp('cn=nope,dc=example,dc=com',
[delta.Add('foo', ['bar'])])
d = op.patch(self.root)
def eb(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
d.addCallbacks(testutil.mustRaise, eb)
return d
ldaptor-0.0.43/ldaptor/entryhelpers.py 0000644 0001750 0001750 00000023024 10345037720 016112 0 ustar jan jan import sets
from twisted.internet import defer
from ldaptor import delta, ldapfilter
from ldaptor.protocols import pureldap
from ldaptor.protocols.ldap import ldapsyntax, ldaperrors
class DiffTreeMixin(object):
def _diffTree_gotMyChildren(self, myChildren, other, result):
d = other.children()
d.addCallback(self._diffTree_gotBothChildren, myChildren, other, result)
return d
def _diffTree_gotBothChildren(self,
otherChildren,
myChildren,
other,
result):
def rdnToChild(rdn, l):
r = [x for x in l if x.dn.split()[0] == rdn]
assert len(r) == 1
return r[0]
my = sets.Set([x.dn.split()[0] for x in myChildren])
his = sets.Set([x.dn.split()[0] for x in otherChildren])
# differences in common children
commonRDN = list(my & his)
commonRDN.sort() # for reproducability only
d = self._diffTree_commonChildren([
(rdnToChild(rdn, myChildren), rdnToChild(rdn, otherChildren))
for rdn in commonRDN
], result)
# added children
addedRDN = list(his - my)
addedRDN.sort() # for reproducability only
d2 = self._diffTree_addedChildren([
rdnToChild(rdn, otherChildren)
for rdn in addedRDN
], result)
d.addCallback(lambda _: d2)
# deleted children
deletedRDN = list(my - his)
deletedRDN.sort() # for reproducability only
d3 = self._diffTree_deletedChildren([
rdnToChild(rdn, myChildren)
for rdn in deletedRDN
], result)
d.addCallback(lambda _: d3)
return d
def _diffTree_commonChildren(self, children, result):
if not children:
return defer.succeed(result)
first, rest = children[0], children[1:]
a, b = first
d = a.diffTree(b, result)
d.addCallback(lambda _: self._diffTree_commonChildren(rest, result))
return d
def _diffTree_addedChildren(self, children, result):
if not children:
return result
first, rest = children[0], children[1:]
d = first.subtree()
def _gotSubtree(l, result):
for c in l:
o = delta.AddOp(c)
result.append(o)
return result
d.addCallback(_gotSubtree, result)
d.addCallback(lambda _: self._diffTree_addedChildren(rest, result))
return d
def _diffTree_deletedChildren(self, children, result):
if not children:
return result
first, rest = children[0], children[1:]
d = first.subtree()
def _gotSubtree(l, result):
l.reverse() # remove children before their parent
for c in l:
o = delta.DeleteOp(c)
result.append(o)
return result
d.addCallback(_gotSubtree, result)
d.addCallback(lambda _: self._diffTree_deletedChildren(rest, result))
return d
def diffTree(self, other, result=None):
assert self.dn == other.dn, \
("diffTree arguments must refer to same LDAP tree:"
"%r != %r" % (str(self.dn), str(other.dn))
)
if result is None:
result = []
# differences in root
rootDiff = self.diff(other)
if rootDiff is not None:
result.append(rootDiff)
d = self.children()
d.addCallback(self._diffTree_gotMyChildren, other, result)
return d
class SubtreeFromChildrenMixin(object):
def subtree(self, callback=None):
if callback is None:
result = []
d = self.subtree(callback=result.append)
d.addCallback(lambda _: result)
return d
else:
callback(self)
d = self.children()
def _processOneChild(_, children, callback):
if not children:
return None
c = children.pop()
d = c.subtree(callback)
d.addCallback(_processOneChild, children, callback)
def _gotChildren(children, callback):
_processOneChild(None, children, callback)
d.addCallback(_gotChildren, callback)
return d
class MatchMixin(object):
def match(self, filter):
if isinstance(filter, pureldap.LDAPFilter_present):
return filter.value in self
elif isinstance(filter, pureldap.LDAPFilter_equalityMatch):
# TODO case insensitivity depends on different attribute syntaxes
if (filter.assertionValue.value.lower() 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 not in self:
return False
for value in self[filter.attributeDesc]:
if value >= filter.assertionValue:
return True
return False
elif isinstance(filter, pureldap.LDAPFilter_lessOrEqual):
if filter.attributeDesc not in self:
return False
for value in self[filter.attributeDesc]:
if value <= filter.assertionValue:
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)
else:
raise ldapsyntax.MatchNotImplemented, filter
class SearchByTreeWalkingMixin(object):
def search(self,
filterText=None,
filterObject=None,
attributes=(),
scope=None,
derefAliases=None,
sizeLimit=0,
timeLimit=0,
typesOnly=0,
callback=None):
if filterObject is None and filterText is None:
filterObject=pureldap.LDAPFilterMatchAll
elif filterObject is None and filterText is not None:
filterObject=ldapfilter.parseFilter(filterText)
elif filterObject is not None and filterText is None:
pass
elif filterObject is not None and filterText is not None:
f=ldapfilter.parseFilter(filterText)
filterObject=pureldap.LDAPFilter_and((f, filterObject))
if scope is None:
scope = pureldap.LDAP_SCOPE_wholeSubtree
if derefAliases is None:
derefAliases = pureldap.LDAP_DEREF_neverDerefAliases
# choose iterator: base/children/subtree
if scope == pureldap.LDAP_SCOPE_wholeSubtree:
iterator = self.subtree
elif scope == pureldap.LDAP_SCOPE_singleLevel:
iterator = self.children
elif scope == pureldap.LDAP_SCOPE_baseObject:
def iterateSelf(callback):
callback(self)
return defer.succeed(None)
iterator = iterateSelf
else:
raise ldaperrors.LDAPProtocolError, \
'unknown search scope: %r' % scope
results = []
if callback is None:
matchCallback = results.append
else:
matchCallback = callback
# gather results, send them
def _tryMatch(entry):
if entry.match(filterObject):
matchCallback(entry)
d = iterator(callback=_tryMatch)
if callback is None:
return defer.succeed(results)
else:
return defer.succeed(None)
ldaptor-0.0.43/ldaptor/protocols/ 0000755 0001750 0001750 00000000000 10403234307 015032 5 ustar jan jan ldaptor-0.0.43/ldaptor/protocols/pureber.py 0000644 0001750 0001750 00000025663 10345573607 017102 0 ustar jan jan # Twisted, the Framework of Your Internet
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Pure, simple, BER encoding and decoding"""
# This BER library is currently aimed at supporting LDAP, thus
# the following restrictions from RFC2251 apply:
#
# (1) Only the definite form of length encoding will be used.
#
# (2) OCTET STRING values will be encoded in the primitive form
# only.
#
# (3) If the value of a BOOLEAN type is true, the encoding MUST have
# its contents octets set to hex "FF".
#
# (4) If a value of a type is its default value, it MUST be absent.
# Only some BOOLEAN and INTEGER types have default values in
# this protocol definition.
import string
# xxxxxxxx
# |/|\.../
# | | |
# | | tag
# | |
# | primitive (0) or structured (1)
# |
# class
CLASS_MASK = 0xc0
CLASS_UNIVERSAL = 0x00
CLASS_APPLICATION = 0x40
CLASS_CONTEXT = 0x80
CLASS_PRIVATE = 0xc0
STRUCTURED_MASK = 0x20
STRUCTURED = 0x20
NOT_STRUCTURED = 0x00
TAG_MASK = 0x1f
# LENGTH
# 0xxxxxxx = 0..127
# 1xxxxxxx = len is stored in the next 0xxxxxxx octets
# indefinite form not supported
class UnknownBERTag(Exception):
def __init__(self, tag, context):
Exception.__init__(self)
self.tag = tag
self.context = context
def __str__(self):
return "BERDecoderContext has no tag 0x%02x: %s" \
% (self.tag, self.context)
import UserList
def berDecodeLength(m, offset=0):
"""
Return a tuple of (length, lengthLength).
m must be atleast one byte long.
"""
l=ber2int(m[offset+0])
ll=1
if l&0x80:
ll=1+(l&0x7F)
need(m, offset+ll)
l=ber2int(m[offset+1:offset+ll], signed=0)
return (l, ll)
def int2berlen(i):
assert i>=0
e=int2ber(i, signed=False)
if i <= 127:
return e
else:
l=len(e)
assert l>0
assert l<=127
return chr(0x80|l) + e
def int2ber(i, signed=True):
encoded=''
while ((signed and (i>127 or i<-128))
or (not signed and (i>255))):
encoded=chr(i%256)+encoded
i=i>>8
encoded=chr(i%256)+encoded
return encoded
def ber2int(e, signed=True):
need(e, 1)
v=0L+ord(e[0])
if v&0x80 and signed:
v=v-256
for i in range(1, len(e)):
v=(v<<8) | ord(e[i])
return v
class BERBase:
tag = None
def identification(self):
return self.tag
def __init__(self, tag=None):
if tag is not None:
self.tag=tag
def __len__(self):
return len(str(self))
def __cmp__(self, other):
if isinstance(other, BERBase):
return cmp(str(self), str(other))
else:
return -1
def __eq__(self, other):
if isinstance(other, BERBase):
return str(self) == str(other)
else:
return False
def __ne__(self, other):
if isinstance(other, BERBase):
return str(self) != str(other)
else:
return False
class BERStructured(BERBase):
def identification(self):
return STRUCTURED|self.tag
class BERException(Exception): pass
class BERExceptionInsufficientData(Exception): pass
def need(buf, n):
d=n-len(buf)
if d>0:
raise BERExceptionInsufficientData, d
class BERInteger(BERBase):
tag = 0x02
value = None
def fromBER(klass, tag, content, berdecoder=None):
assert len(content)>0
value=ber2int(content)
r = klass(value=value, tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, value=None, tag=None):
"""Create a new BERInteger object.
value is an integer.
"""
BERBase.__init__(self, tag)
assert value is not None
self.value=value
def __str__(self):
encoded=int2ber(self.value)
return chr(self.identification()) \
+int2berlen(len(encoded)) \
+encoded
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"(value=%r)"%self.value
else:
return self.__class__.__name__+"(value=%r, tag=%d)" \
%(self.value, self.tag)
class BEROctetString(BERBase):
tag = 0x04
value = None
def fromBER(klass, tag, content, berdecoder=None):
assert len(content)>=0
r = klass(value=content, tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, value=None, tag=None):
BERBase.__init__(self, tag)
assert value is not None
self.value=value
def __str__(self):
value = str(self.value)
return chr(self.identification()) \
+int2berlen(len(value)) \
+value
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"(value=%s)" \
%repr(self.value)
else:
return self.__class__.__name__ \
+"(value=%s, tag=%d)" \
%(repr(self.value), self.tag)
class BERNull(BERBase):
tag = 0x05
def fromBER(klass, tag, content, berdecoder=None):
assert len(content) == 0
r = klass(tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, tag=None):
BERBase.__init__(self, tag)
def __str__(self):
return chr(self.identification())+chr(0)
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"()"
else:
return self.__class__.__name__+"(tag=%d)"%self.tag
class BERBoolean(BERBase):
tag = 0x01
def fromBER(klass, tag, content, berdecoder=None):
assert len(content) > 0
value = ber2int(content)
r = klass(value=value, tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, value=None, tag=None):
"""Create a new BERInteger object.
value is an integer.
"""
BERBase.__init__(self, tag)
assert value is not None
if value:
value=0xFF
self.value=value
def __str__(self):
assert self.value==0 or self.value==0xFF
return chr(self.identification()) \
+int2berlen(1) \
+chr(self.value)
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"(value=%d)"%self.value
else:
return self.__class__.__name__+"(value=%d, tag=%d)" \
%(self.value, self.tag)
class BEREnumerated(BERInteger):
tag = 0x0a
class BERSequence(BERStructured, UserList.UserList):
# TODO __getslice__ calls __init__ with no args.
tag = 0x10
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, berdecoder)
r = klass(l, tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, value=None, tag=None):
BERStructured.__init__(self, tag)
UserList.UserList.__init__(self)
assert value is not None
self[:]=value
def __str__(self):
r=string.join(map(str, self.data), '')
return chr(self.identification())+int2berlen(len(r))+r
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"(value=%s)"%repr(self.data)
else:
return self.__class__.__name__+"(value=%s, tag=%d)" \
%(repr(self.data), self.tag)
class BERSequenceOf(BERSequence):
pass
class BERSet(BERSequence):
tag = 0x11
pass
class BERDecoderContext:
Identities = {
BERInteger.tag: BERInteger,
BEROctetString.tag: BEROctetString,
BERNull.tag: BERNull,
BERBoolean.tag: BERBoolean,
BEREnumerated.tag: BEREnumerated,
BERSequence.tag: BERSequence,
BERSet.tag: BERSet,
}
def __init__(self, fallback=None, inherit=None):
self.fallback=fallback
self.inherit_context=inherit
def lookup_id(self, id):
try:
return self.Identities[id]
except KeyError:
if self.fallback:
return self.fallback.lookup_id(id)
else:
return None
def inherit(self):
return self.inherit_context or self
def __repr__(self):
identities = []
for tag, class_ in self.Identities.items():
identities.append('0x%02x: %s' % (tag, class_.__name__))
return "<"+self.__class__.__name__ \
+" identities={%s}" % ', '.join(identities) \
+" fallback="+repr(self.fallback) \
+" inherit="+repr(self.inherit_context) \
+">"
def berDecodeObject(context, m):
"""berDecodeObject(context, string) -> (berobject, bytesUsed)
berobject may be None.
"""
while m:
need(m, 2)
i=ber2int(m[0], signed=0)&(CLASS_MASK|TAG_MASK)
length, lenlen = berDecodeLength(m, offset=1)
need(m, 1+lenlen+length)
m2 = m[1+lenlen:1+lenlen+length]
berclass=context.lookup_id(i)
if berclass:
inh=context.inherit()
assert inh
r = berclass.fromBER(tag=i,
content=m2,
berdecoder=inh)
return (r, 1+lenlen+length)
else:
#raise UnknownBERTag, (i, context)
print str(UnknownBERTag(i, context)) #TODO
return (None, 1+lenlen+length)
return (None, 0)
def berDecodeMultiple(content, berdecoder):
"""berDecodeMultiple(content, berdecoder) -> [objects]
Decodes everything in content and returns a list of decoded
objects.
All of content will be decoded, and content must contain complete
BER objects.
"""
l = []
while content:
n, bytes = berDecodeObject(berdecoder, content)
if n is not None:
l.append(n)
assert bytes <= len(content)
content = content[bytes:]
return l
#TODO unimplemented classes are below:
#class BERObjectIdentifier(BERBase):
# tag = 0x06
# pass
#class BERIA5String(BERBase):
# tag = 0x16
# pass
#class BERPrintableString(BERBase):
# tag = 0x13
# pass
#class BERT61String(BERBase):
# tag = 0x14
# pass
#class BERUTCTime(BERBase):
# tag = 0x17
# pass
#class BERBitString(BERBase):
# tag = 0x03
# pass
ldaptor-0.0.43/ldaptor/protocols/pureldap.py 0000644 0001750 0001750 00000122413 10365653714 017241 0 ustar jan jan # Twisted, the Framework of Your Internet
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""LDAP protocol message conversion; no application logic here."""
from pureber import *
next_ldap_message_id=1
def alloc_ldap_message_id():
global next_ldap_message_id
r=next_ldap_message_id
next_ldap_message_id=next_ldap_message_id+1
return r
def escape(s):
s = s.replace('\\', r'\5c')
s = s.replace('*', r'\2a')
s = s.replace('(', r'\28')
s = s.replace(')', r'\29')
s = s.replace('\0', r'\00')
return s
class LDAPString(BEROctetString):
pass
class LDAPAttributeValue(BEROctetString):
pass
class LDAPMessage(BERSequence):
id = None
value = None
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, berdecoder)
id_=l[0].value
value=l[1]
if l[2:]:
controls = []
for c in l[2]:
controls.append((
c.controlType,
c.criticality,
c.controlValue,
))
else:
controls = None
assert not l[3:]
r = klass(id=id_,
value=value,
controls=controls,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, value=None, controls=None, id=None, tag=None):
BERSequence.__init__(self, value=[], tag=tag)
assert value is not None
self.id=id
if self.id is None:
self.id=alloc_ldap_message_id()
self.value=value
self.controls = controls
def __str__(self):
l = [BERInteger(self.id), self.value]
if self.controls is not None:
l.append(LDAPControls([LDAPControl(*a) for a in self.controls]))
return str(BERSequence(l))
def __repr__(self):
l=[]
l.append('id=%r' % self.id)
l.append('value=%r' % self.value)
if self.tag!=self.__class__.tag:
l.append('tag=%d' % self.tag)
return self.__class__.__name__+'('+', '.join(l)+')'
class LDAPProtocolOp:
def __init__(self):
pass
def __str__(self):
raise NotImplementedError
class LDAPProtocolRequest(LDAPProtocolOp):
needs_answer=1
pass
class LDAPProtocolResponse(LDAPProtocolOp):
pass
class LDAPBERDecoderContext_LDAPBindRequest(BERDecoderContext):
Identities = {
CLASS_CONTEXT|0x00: BEROctetString,
}
class LDAPBindRequest(LDAPProtocolRequest, BERSequence):
tag=CLASS_APPLICATION|0x00
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content,
LDAPBERDecoderContext_LDAPBindRequest(
fallback=berdecoder))
r = klass(version=l[0].value,
dn=l[1].value,
auth=l[2].value,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, version=None, dn=None, auth=None, tag=None):
LDAPProtocolRequest.__init__(self)
BERSequence.__init__(self, [], tag=tag)
self.version=version
if self.version is None:
self.version=3
self.dn=dn
if self.dn is None:
self.dn=''
self.auth=auth
if self.auth is None:
self.auth=''
def __str__(self):
return str(BERSequence([
BERInteger(self.version),
BEROctetString(self.dn),
BEROctetString(self.auth, tag=CLASS_CONTEXT|0),
], tag=self.tag))
def __repr__(self):
l=[]
l.append('version=%d' % self.version)
l.append('dn=%s' % repr(self.dn))
l.append('auth=%s' % repr(self.auth))
if self.tag!=self.__class__.tag:
l.append('tag=%d' % self.tag)
return self.__class__.__name__+'('+', '.join(l)+')'
class LDAPReferral(BERSequence):
tag = CLASS_CONTEXT | 0x03
class LDAPResult(LDAPProtocolResponse, BERSequence):
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_LDAPBindRequest(
fallback=berdecoder))
assert 3<=len(l)<=4
referral = None
#if (l[3:] and isinstance(l[3], LDAPReferral)):
#TODO support referrals
#self.referral=self.data[0]
r = klass(resultCode=l[0].value,
matchedDN=l[1].value,
errorMessage=l[2].value,
referral=referral,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None):
LDAPProtocolResponse.__init__(self)
BERSequence.__init__(self, value=[], tag=tag)
assert resultCode is not None
self.resultCode=resultCode
if matchedDN is None:
matchedDN=''
self.matchedDN=matchedDN
if errorMessage is None:
errorMessage=''
self.errorMessage=errorMessage
self.referral=referral
self.serverSaslCreds=serverSaslCreds
def __str__(self):
assert self.referral is None #TODO
return str(BERSequence([
BEREnumerated(self.resultCode),
BEROctetString(self.matchedDN),
BEROctetString(self.errorMessage),
#TODO referral [3] Referral OPTIONAL
], tag=self.tag))
def __repr__(self):
l=[]
l.append('resultCode=%r' % self.resultCode)
if self.matchedDN:
l.append('matchedDN=%r' % str(self.matchedDN))
if self.errorMessage:
l.append('errorMessage=%r' % str(self.errorMessage))
if self.referral:
l.append('referral=%r' % self.referral)
if self.tag!=self.__class__.tag:
l.append('tag=%d' % self.tag)
return self.__class__.__name__+'('+', '.join(l)+')'
class LDAPBindResponse_serverSaslCreds(BERSequence):
tag = CLASS_CONTEXT|0x03
pass
class LDAPBERDecoderContext_BindResponse(BERDecoderContext):
Identities = {
LDAPBindResponse_serverSaslCreds.tag: LDAPBindResponse_serverSaslCreds,
}
class LDAPBindResponse(LDAPResult):
tag=CLASS_APPLICATION|0x01
resultCode = None
matchedDN = None
errorMessage = None
referral = None
serverSaslCreds = None
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_BindResponse(
fallback=berdecoder))
assert 3<=len(l)<=4
try:
if isinstance(l[0], LDAPBindResponse_serverSaslCreds):
serverSaslCreds=l[0]
del l[0]
else:
serverSaslCreds=None
except IndexError:
serverSaslCreds=None
referral = None
#if (l[3:] and isinstance(l[3], LDAPReferral)):
#TODO support referrals
#self.referral=self.data[0]
r = klass(resultCode=l[0].value,
matchedDN=l[1].value,
errorMessage=l[2].value,
referral=referral,
serverSaslCreds=serverSaslCreds,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None):
LDAPResult.__init__(self, resultCode=resultCode, matchedDN=matchedDN, errorMessage=errorMessage, referral=referral, tag=None)
assert self.serverSaslCreds is None #TODO
def __str__(self):
assert self.serverSaslCreds is None #TODO
return LDAPResult.__str__(self)
def __repr__(self):
assert self.serverSaslCreds is None #TODO
return LDAPResult.__repr__(self)
class LDAPUnbindRequest(LDAPProtocolRequest, BERNull):
tag=CLASS_APPLICATION|0x02
needs_answer=0
def __init__(self, *args, **kwargs):
LDAPProtocolRequest.__init__(self)
BERNull.__init__(self, *args, **kwargs)
def __str__(self):
return BERNull.__str__(self)
class LDAPAttributeDescription(BEROctetString):
pass
class LDAPAttributeValueAssertion(BERSequence):
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, berdecoder)
assert len(l) == 2
r = klass(attributeDesc=l[0],
assertionValue=l[1],
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, attributeDesc=None, assertionValue=None, tag=None):
BERSequence.__init__(self, value=[], tag=tag)
assert attributeDesc is not None
self.attributeDesc=attributeDesc
self.assertionValue=assertionValue
def __str__(self):
return str(BERSequence([self.attributeDesc,
self.assertionValue],
tag=self.tag))
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"(attributeDesc=%s, assertionValue=%s)"\
%(repr(self.attributeDesc), repr(self.assertionValue))
else:
return self.__class__.__name__+"(attributeDesc=%s, assertionValue=%s, tag=%d)"\
%(repr(self.attributeDesc), repr(self.assertionValue), self.tag)
class LDAPFilter(BERStructured):
def __init__(self, tag=None):
BERStructured.__init__(self, tag=tag)
class LDAPFilterSet(BERSet):
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_Filter(fallback=berdecoder))
r = klass(l, tag=tag)
return r
fromBER = classmethod(fromBER)
class LDAPFilter_and(LDAPFilterSet):
tag = CLASS_CONTEXT|0x00
def asText(self):
return '(&'+''.join([x.asText() for x in self])+')'
class LDAPFilter_or(LDAPFilterSet):
tag = CLASS_CONTEXT|0x01
def asText(self):
return '(|'+''.join([x.asText() for x in self])+')'
class LDAPFilter_not(LDAPFilter):
tag = CLASS_CONTEXT|0x02
def fromBER(klass, tag, content, berdecoder=None):
value, bytes = berDecodeObject(LDAPBERDecoderContext_Filter(fallback=berdecoder, inherit=berdecoder), content)
assert bytes == len(content)
r = klass(value=value,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, value, tag=tag):
LDAPFilter.__init__(self, tag=tag)
assert value is not None
self.value=value
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__\
+"(value=%s)"\
%repr(self.value)
else:
return self.__class__.__name__\
+"(value=%s, tag=%d)"\
%(repr(self.value), self.tag)
def __str__(self):
r=str(self.value)
return chr(self.identification())+int2berlen(len(r))+r
def asText(self):
return '(!'+self.value.asText()+')'
class LDAPFilter_equalityMatch(LDAPAttributeValueAssertion):
tag = CLASS_CONTEXT|0x03
def asText(self):
return '('+self.attributeDesc.value+'=' \
+escape(self.assertionValue.value)+')'
class LDAPFilter_substrings_initial(LDAPString):
tag = CLASS_CONTEXT|0x00
def asText(self):
return escape(self.value)
class LDAPFilter_substrings_any(LDAPString):
tag = CLASS_CONTEXT|0x01
def asText(self):
return escape(self.value)
class LDAPFilter_substrings_final(LDAPString):
tag = CLASS_CONTEXT|0x02
def asText(self):
return escape(self.value)
class LDAPBERDecoderContext_Filter_substrings(BERDecoderContext):
Identities = {
LDAPFilter_substrings_initial.tag: LDAPFilter_substrings_initial,
LDAPFilter_substrings_any.tag: LDAPFilter_substrings_any,
LDAPFilter_substrings_final.tag: LDAPFilter_substrings_final,
}
class LDAPFilter_substrings(BERSequence):
tag = CLASS_CONTEXT|0x04
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_Filter_substrings(fallback=berdecoder))
assert len(l) == 2
assert len(l[1])>=1
r = klass(type=l[0].value,
substrings=list(l[1]),
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, type=None, substrings=None, tag=None):
BERSequence.__init__(self, value=[], tag=tag)
assert type is not None
assert substrings is not None
self.type=type
self.substrings=substrings
def __str__(self):
return str(BERSequence([
LDAPString(self.type),
BERSequence(self.substrings)], tag=self.tag))
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__\
+"(type=%s, substrings=%s)"\
%(repr(self.type), repr(self.substrings))
else:
return self.__class__.__name__\
+"(type=%s, substrings=%s, tag=%d)"\
%(repr(self.type), repr(self.substrings), self.tag)
def asText(self):
initial=None
final=None
any=[]
for s in self.substrings:
assert s is not None
if isinstance(s, LDAPFilter_substrings_initial):
assert initial is None
assert not any
assert final is None
initial=s.asText()
elif isinstance(s, LDAPFilter_substrings_final):
assert final is None
final=s.asText()
elif isinstance(s, LDAPFilter_substrings_any):
assert final is None
any.append(s.asText())
else:
raise 'TODO'
if initial is None:
initial=''
if final is None:
final=''
return '('+self.type+'=' \
+'*'.join([initial]+any+[final])+')'
class LDAPFilter_greaterOrEqual(LDAPAttributeValueAssertion):
tag = CLASS_CONTEXT|0x05
def asText(self):
return '('+self.attributeDesc.value+'>=' \
+escape(self.assertionValue.value)+')'
class LDAPFilter_lessOrEqual(LDAPAttributeValueAssertion):
tag = CLASS_CONTEXT|0x06
def asText(self):
return '('+self.attributeDesc.value+'<=' \
+escape(self.assertionValue.value)+')'
class LDAPFilter_present(LDAPAttributeDescription):
tag = CLASS_CONTEXT|0x07
def asText(self):
return '(%s=*)' % self.value
class LDAPFilter_approxMatch(LDAPAttributeValueAssertion):
tag = CLASS_CONTEXT|0x08
def asText(self):
return '('+self.attributeDesc.value+'~=' \
+escape(self.assertionValue.value)+')'
class LDAPMatchingRuleId(LDAPString):
pass
class LDAPAssertionValue(BEROctetString):
pass
class LDAPMatchingRuleAssertion_matchingRule(LDAPMatchingRuleId):
tag = CLASS_CONTEXT|0x01
pass
class LDAPMatchingRuleAssertion_type(LDAPAttributeDescription):
tag = CLASS_CONTEXT|0x02
pass
class LDAPMatchingRuleAssertion_matchValue(LDAPAssertionValue):
tag = CLASS_CONTEXT|0x03
pass
class LDAPMatchingRuleAssertion_dnAttributes(BERBoolean):
tag = CLASS_CONTEXT|0x04
pass
class LDAPBERDecoderContext_MatchingRuleAssertion(BERDecoderContext):
Identities = {
LDAPMatchingRuleAssertion_matchingRule.tag: LDAPMatchingRuleAssertion_matchingRule,
LDAPMatchingRuleAssertion_type.tag: LDAPMatchingRuleAssertion_type,
LDAPMatchingRuleAssertion_matchValue.tag: LDAPMatchingRuleAssertion_matchValue,
LDAPMatchingRuleAssertion_dnAttributes.tag: LDAPMatchingRuleAssertion_dnAttributes,
}
class LDAPMatchingRuleAssertion(BERSequence):
matchingRule=None
type=None
matchValue=None
dnAttributes=None
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_MatchingRuleAssertion(fallback=berdecoder, inherit=berdecoder))
assert 1<=len(l)<=4
if isinstance(l[0], LDAPMatchingRuleAssertion_matchingRule):
matchingRule=l[0]
del l[0]
if len(l)>1 \
and isinstance(l[0], LDAPMatchingRuleAssertion_type):
type=l[0]
del l[0]
if len(l)>1 \
and isinstance(l[0], LDAPMatchingRuleAssertion_matchValue):
matchValue=l[0]
del l[0]
if len(l)>1 \
and isinstance(l[0], LDAPMatchingRuleAssertion_dnAttributes):
dnAttributes=l[0]
del l[0]
assert matchValue
if not dnAttributes:
dnAttributes=None
assert 8<=len(l)<=8
r = klass(matchingRule=matchingRule,
type=type,
matchValue=matchValue,
dnAttributes=dnAttributes,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, matchingRule=None, type=None,
matchValue=None, dnAttributes=None,
tag=None):
BERSequence.__init__(self, value=[], tag=tag)
assert matchValue is not None
self.matchingRule=matchingRule
self.type=type
self.matchValue=matchValue
self.dnAttributes=dnAttributes
if not self.dnAttributes:
self.dnAttributes=None
def __str__(self):
return str(BERSequence(
filter(lambda x: x is not None, [self.matchingRule, self.type, self.matchValue, self.dnAttributes]), tag=self.tag))
def __repr__(self):
l=[]
l.append('matchingRule=%s' % repr(self.matchingRule))
l.append('type=%s' % repr(self.type))
l.append('matchValue=%s' % repr(self.matchValue))
l.append('dnAttributes=%s' % repr(self.dnAttributes))
if self.tag!=self.__class__.tag:
l.append('tag=%d' % self.tag)
return self.__class__.__name__+'('+', '.join(l)+')'
class LDAPFilter_extensibleMatch(LDAPMatchingRuleAssertion):
tag = CLASS_CONTEXT|0x09
pass
class LDAPBERDecoderContext_Filter(BERDecoderContext):
Identities = {
LDAPFilter_and.tag: LDAPFilter_and,
LDAPFilter_or.tag: LDAPFilter_or,
LDAPFilter_not.tag: LDAPFilter_not,
LDAPFilter_equalityMatch.tag: LDAPFilter_equalityMatch,
LDAPFilter_substrings.tag: LDAPFilter_substrings,
LDAPFilter_greaterOrEqual.tag: LDAPFilter_greaterOrEqual,
LDAPFilter_lessOrEqual.tag: LDAPFilter_lessOrEqual,
LDAPFilter_present.tag: LDAPFilter_present,
LDAPFilter_approxMatch.tag: LDAPFilter_approxMatch,
LDAPFilter_extensibleMatch.tag: LDAPFilter_extensibleMatch,
}
LDAP_SCOPE_baseObject=0
LDAP_SCOPE_singleLevel=1
LDAP_SCOPE_wholeSubtree=2
LDAP_DEREF_neverDerefAliases=0
LDAP_DEREF_derefInSearching=1
LDAP_DEREF_derefFindingBaseObj=2
LDAP_DEREF_derefAlways=3
LDAPFilterMatchAll = LDAPFilter_present('objectClass')
class LDAPSearchRequest(LDAPProtocolRequest, BERSequence):
tag=CLASS_APPLICATION|0x03
baseObject=''
scope=LDAP_SCOPE_wholeSubtree
derefAliases=LDAP_DEREF_neverDerefAliases
sizeLimit=0
timeLimit=0
typesOnly=0
filter=LDAPFilterMatchAll
attributes=[] #TODO AttributeDescriptionList
#TODO decode
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_Filter(fallback=berdecoder, inherit=berdecoder))
assert 8<=len(l)<=8
r = klass(baseObject=l[0].value,
scope=l[1].value,
derefAliases=l[2].value,
sizeLimit=l[3].value,
timeLimit=l[4].value,
typesOnly=l[5].value,
filter=l[6],
attributes=[x.value for x in l[7]],
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self,
baseObject=None,
scope=None,
derefAliases=None,
sizeLimit=None,
timeLimit=None,
typesOnly=None,
filter=None,
attributes=None,
tag=None):
LDAPProtocolRequest.__init__(self)
BERSequence.__init__(self, [], tag=tag)
if baseObject is not None:
self.baseObject=baseObject
if scope is not None:
self.scope=scope
if derefAliases is not None:
self.derefAliases=derefAliases
if sizeLimit is not None:
self.sizeLimit=sizeLimit
if timeLimit is not None:
self.timeLimit=timeLimit
if typesOnly is not None:
self.typesOnly=typesOnly
if filter is not None:
self.filter=filter
if attributes is not None:
self.attributes=attributes
def __str__(self):
return str(BERSequence([
BEROctetString(self.baseObject),
BEREnumerated(self.scope),
BEREnumerated(self.derefAliases),
BERInteger(self.sizeLimit),
BERInteger(self.timeLimit),
BERBoolean(self.typesOnly),
self.filter,
BERSequenceOf(map(BEROctetString, self.attributes)),
], tag=self.tag))
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__\
+("(baseObject=%s, scope=%s, derefAliases=%s, " \
+"sizeLimit=%s, timeLimit=%s, typesOnly=%s, " \
"filter=%s, attributes=%s)") \
%(repr(self.baseObject), self.scope,
self.derefAliases, self.sizeLimit,
self.timeLimit, self.typesOnly,
repr(self.filter), self.attributes)
else:
return self.__class__.__name__\
+("(baseObject=%s, scope=%s, derefAliases=%s, " \
+"sizeLimit=%s, timeLimit=%s, typesOnly=%s, " \
"filter=%s, attributes=%s, tag=%d)") \
%(repr(self.baseObject), self.scope,
self.derefAliases, self.sizeLimit,
self.timeLimit, self.typesOnly,
self.filter, self.attributes, self.tag)
class LDAPSearchResultEntry(LDAPProtocolResponse, BERSequence):
tag=CLASS_APPLICATION|0x04
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_Filter(fallback=berdecoder, inherit=berdecoder))
objectName=l[0].value
attributes=[]
for attr, li in l[1].data:
attributes.append((attr.value, map(lambda x: x.value, li)))
r = klass(objectName=objectName,
attributes=attributes,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, objectName, attributes, tag=None):
LDAPProtocolResponse.__init__(self)
BERSequence.__init__(self, [], tag=tag)
assert objectName is not None
assert attributes is not None
self.objectName=objectName
self.attributes=attributes
def __str__(self):
return str(BERSequence([
BEROctetString(self.objectName),
BERSequence(map(lambda (attr,li):
BERSequence([BEROctetString(attr),
BERSet(map(BEROctetString,
li))]),
self.attributes)),
], tag=self.tag))
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__\
+"(objectName=%s, attributes=%s"\
%(repr(str(self.objectName)),
repr(map(lambda (a,l):
(str(a),
map(lambda i, l=l: str(i), l)),
self.attributes)))
else:
return self.__class__.__name__\
+"(objectName=%s, attributes=%s, tag=%d"\
%(repr(str(self.objectName)),
repr(map(lambda (a,l):
(str(a),
map(lambda i, l=l: str(i), l)),
self.attributes)),
self.tag)
class LDAPSearchResultDone(LDAPResult):
tag=CLASS_APPLICATION|0x05
pass
class LDAPControls(BERSequence):
tag = CLASS_CONTEXT|0x00
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_LDAPControls(
inherit=berdecoder))
r = klass(l, tag=tag)
return r
fromBER = classmethod(fromBER)
class LDAPControl(BERSequence):
criticality = None
controlValue = None
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, berdecoder)
kw = {}
if l[1:]:
kw['criticality'] = l[1].value
if l[2:]:
kw['controlValue'] = l[2].value
# TODO is controlType, controlValue allowed without criticality?
assert not l[3:]
r = klass(controlType=l[0].value,
tag=tag,
**kw)
return r
fromBER = classmethod(fromBER)
def __init__(self,
controlType, criticality=None, controlValue=None,
id=None, tag=None):
BERSequence.__init__(self, value=[], tag=tag)
assert controlType is not None
self.controlType = controlType
self.criticality = criticality
self.controlValue = controlValue
def __str__(self):
self.data=[LDAPOID(self.controlType)]
if self.criticality is not None:
self.data.append(BERBoolean(self.criticality))
if self.controlValue is not None:
self.data.append(BEROctetString(self.controlValue))
return BERSequence.__str__(self)
class LDAPBERDecoderContext_LDAPControls(BERDecoderContext):
Identities = {
LDAPControl.tag: LDAPControl,
}
class LDAPBERDecoderContext_LDAPMessage(BERDecoderContext):
Identities = {
LDAPControls.tag: LDAPControls,
}
class LDAPBERDecoderContext_TopLevel(BERDecoderContext):
Identities = {
BERSequence.tag: LDAPMessage,
}
class LDAPModifyRequest(LDAPProtocolRequest, BERSequence):
tag=CLASS_APPLICATION|0x06
object = None
modification = None
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, berdecoder)
assert len(l) == 2
r = klass(object=l[0].value,
modification=l[1].data,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, object=None, modification=None, tag=None):
"""
Initialize the object
Example usage::
l = LDAPModifyRequest(
object='cn=foo,dc=example,dc=com',
modification=[
BERSequence([
BEREnumerated(0),
BERSequence([
LDAPAttributeDescription('attr1'),
BERSet([
LDAPString('value1'),
LDAPString('value2'),
]),
]),
]),
BERSequence([
BEREnumerated(1),
BERSequence([
LDAPAttributeDescription('attr2'),
]),
]),
])
But more likely you just want to say::
mod = delta.ModifyOp('cn=foo,dc=example,dc=com',
[delta.Add('attr1', ['value1', 'value2']),
delta.Delete('attr1', ['value1', 'value2'])])
l = mod.asLDAP()
"""
LDAPProtocolRequest.__init__(self)
BERSequence.__init__(self, [], tag=tag)
self.object=object
self.modification=modification
def __str__(self):
l=[LDAPString(self.object)]
if self.modification is not None:
l.append(BERSequence(self.modification))
return str(BERSequence(l, tag=self.tag))
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"(object=%s, modification=%s)"\
%(repr(self.object), repr(self.modification))
else:
return self.__class__.__name__+"(object=%s, modification=%s, tag=%d)" \
%(repr(self.object), repr(self.modification), self.tag)
class LDAPModifyResponse(LDAPResult):
tag = CLASS_APPLICATION|0x07
class LDAPAddRequest(LDAPProtocolRequest, BERSequence):
tag = CLASS_APPLICATION|0x08
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, berdecoder)
r = klass(entry=l[0].value,
attributes=l[1],
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, entry=None, attributes=None, tag=None):
"""
Initialize the object
Example usage::
l=LDAPAddRequest(entry='cn=foo,dc=example,dc=com',
attributes=[(LDAPAttributeDescription("attrFoo"),
BERSet(value=(
LDAPAttributeValue("value1"),
LDAPAttributeValue("value2"),
))),
(LDAPAttributeDescription("attrBar"),
BERSet(value=(
LDAPAttributeValue("value1"),
LDAPAttributeValue("value2"),
))),
])
"""
LDAPProtocolRequest.__init__(self)
BERSequence.__init__(self, [], tag=tag)
self.entry=entry
self.attributes=attributes
def __str__(self):
return str(BERSequence([
LDAPString(self.entry),
BERSequence(map(BERSequence, self.attributes)),
], tag=self.tag))
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"(entry=%s, attributes=%s)"\
%(repr(self.entry), repr(self.attributes))
else:
return self.__class__.__name__+"(entry=%s, attributes=%s, tag=%d)" \
%(repr(self.entry), repr(self.attributes), self.tag)
class LDAPAddResponse(LDAPResult):
tag = CLASS_APPLICATION|0x09
class LDAPDelRequest(LDAPProtocolRequest, LDAPString):
tag = CLASS_APPLICATION|0x0a
def __init__(self, value=None, entry=None, tag=None):
"""
Initialize the object
l=LDAPDelRequest(entry='cn=foo,dc=example,dc=com')
"""
if entry is None and value is not None:
entry = value
LDAPProtocolRequest.__init__(self)
LDAPString.__init__(self, value=entry, tag=tag)
def __str__(self):
return LDAPString.__str__(self)
def __repr__(self):
if self.tag==self.__class__.tag:
return self.__class__.__name__+"(entry=%s)" \
%repr(self.value)
else:
return self.__class__.__name__ \
+"(entry=%s, tag=%d)" \
%(repr(self.value), self.tag)
class LDAPDelResponse(LDAPResult):
tag = CLASS_APPLICATION|0x0b
pass
class LDAPModifyDNResponse_newSuperior(LDAPString):
tag = CLASS_CONTEXT|0x00
pass
class LDAPBERDecoderContext_ModifyDNRequest(BERDecoderContext):
Identities = {
LDAPModifyDNResponse_newSuperior.tag: LDAPModifyDNResponse_newSuperior,
}
class LDAPModifyDNRequest(LDAPProtocolRequest, BERSequence):
tag=CLASS_APPLICATION|12
entry=None
newrdn=None
deleteoldrdn=None
newSuperior=None
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_ModifyDNRequest(fallback=berdecoder))
kw = {}
try:
kw['newSuperior'] = str(l[3].value)
except IndexError:
pass
r = klass(entry=str(l[0].value),
newrdn=str(l[1].value),
deleteoldrdn=l[2].value,
tag=tag,
**kw)
return r
fromBER = classmethod(fromBER)
def __init__(self, entry, newrdn, deleteoldrdn, newSuperior=None,
tag=None):
"""
Initialize the object
Example usage::
l=LDAPModifyDNRequest(entry='cn=foo,dc=example,dc=com',
newrdn='someAttr=value',
deleteoldrdn=0)
"""
LDAPProtocolRequest.__init__(self)
BERSequence.__init__(self, [], tag=tag)
assert entry is not None
assert newrdn is not None
assert deleteoldrdn is not None
self.entry=entry
self.newrdn=newrdn
self.deleteoldrdn=deleteoldrdn
self.newSuperior=newSuperior
def __str__(self):
l=[
LDAPString(self.entry),
LDAPString(self.newrdn),
BERBoolean(self.deleteoldrdn),
]
if self.newSuperior is not None:
l.append(LDAPString(self.newSuperior, tag=CLASS_CONTEXT|0))
return str(BERSequence(l, tag=self.tag))
def __repr__(self):
l = [
"entry=%s" % repr(self.entry),
"newrdn=%s" % repr(self.newrdn),
"deleteoldrdn=%s" % repr(self.deleteoldrdn),
]
if self.newSuperior is not None:
l.append("newSuperior=%s" % repr(self.newSuperior))
if self.tag!=self.__class__.tag:
l.append("tag=%d" % self.tag)
return self.__class__.__name__ + "(" + ', '.join(l) + ")"
class LDAPModifyDNResponse(LDAPResult):
tag=CLASS_APPLICATION|13
#class LDAPCompareResponse(LDAPProtocolResponse):
#class LDAPCompareRequest(LDAPProtocolRequest):
#class LDAPAbandonRequest(LDAPProtocolRequest):
# needs_answer=0
class LDAPOID(BEROctetString):
pass
class LDAPResponseName(LDAPOID):
tag = CLASS_CONTEXT|10
class LDAPResponse(BEROctetString):
tag = CLASS_CONTEXT|11
class LDAPBERDecoderContext_LDAPExtendedRequest(BERDecoderContext):
Identities = {
CLASS_CONTEXT|0x00: BEROctetString,
CLASS_CONTEXT|0x01: BEROctetString,
}
class LDAPExtendedRequest(LDAPProtocolRequest, BERSequence):
tag = CLASS_APPLICATION|23
requestName = None
requestValue = None
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content,
LDAPBERDecoderContext_LDAPExtendedRequest(
fallback=berdecoder))
kw = {}
try:
kw['requestValue'] = l[1].value
except IndexError:
pass
r = klass(requestName=l[0].value,
tag=tag,
**kw)
return r
fromBER = classmethod(fromBER)
def __init__(self, requestName, requestValue=None,
tag=None):
LDAPProtocolRequest.__init__(self)
BERSequence.__init__(self, [], tag=tag)
assert requestName is not None
assert isinstance(requestName, basestring)
self.requestName=requestName
assert isinstance(requestValue, basestring)
self.requestValue=requestValue
def __str__(self):
l=[LDAPOID(self.requestName, tag=CLASS_CONTEXT|0)]
if self.requestValue is not None:
l.append(BEROctetString(str(self.requestValue), tag=CLASS_CONTEXT|1))
return str(BERSequence(l, tag=self.tag))
class LDAPPasswordModifyRequest_userIdentity(BEROctetString):
tag=CLASS_CONTEXT|0
class LDAPPasswordModifyRequest_oldPasswd(BEROctetString):
tag=CLASS_CONTEXT|1
class LDAPPasswordModifyRequest_newPasswd(BEROctetString):
tag=CLASS_CONTEXT|2
class LDAPBERDecoderContext_LDAPPasswordModifyRequest(BERDecoderContext):
Identities = {
LDAPPasswordModifyRequest_userIdentity.tag:
LDAPPasswordModifyRequest_userIdentity,
LDAPPasswordModifyRequest_oldPasswd.tag:
LDAPPasswordModifyRequest_oldPasswd,
LDAPPasswordModifyRequest_newPasswd.tag:
LDAPPasswordModifyRequest_newPasswd,
}
class LDAPPasswordModifyRequest(LDAPExtendedRequest):
oid = '1.3.6.1.4.1.4203.1.11.1'
def __init__(self, requestName=None,
userIdentity=None, oldPasswd=None, newPasswd=None,
tag=None):
assert (requestName is None
or requestName == self.oid), \
'%s requestName was %s instead of %s' \
% (self.__class__.__name__, requestName, self.oid)
#TODO genPasswd
l=[]
if userIdentity is not None:
l.append(LDAPPasswordModifyRequest_userIdentity(userIdentity))
if oldPasswd is not None:
l.append(LDAPPasswordModifyRequest_oldPasswd(oldPasswd))
if newPasswd is not None:
l.append(LDAPPasswordModifyRequest_newPasswd(newPasswd))
LDAPExtendedRequest.__init__(
self,
requestName=self.oid,
requestValue=str(BERSequence(l)),
tag=tag)
def __repr__(self):
l=[]
# TODO userIdentity, oldPasswd, newPasswd
if self.tag!=self.__class__.tag:
l.append('tag=%d' % self.tag)
return self.__class__.__name__+'('+', '.join(l)+')'
class LDAPBERDecoderContext_LDAPExtendedResponse(BERDecoderContext):
Identities = {
LDAPResponseName.tag: LDAPResponseName,
LDAPResponse.tag: LDAPResponse,
}
class LDAPExtendedResponse(LDAPResult):
tag = CLASS_APPLICATION|0x18
responseName = None
response = None
def fromBER(klass, tag, content, berdecoder=None):
l = berDecodeMultiple(content, LDAPBERDecoderContext_LDAPExtendedResponse(
fallback=berdecoder))
assert 3<=len(l)<=4
referral = None
#if (l[3:] and isinstance(l[3], LDAPReferral)):
#TODO support referrals
#self.referral=self.data[0]
r = klass(resultCode=l[0].value,
matchedDN=l[1].value,
errorMessage=l[2].value,
referral=referral,
tag=tag)
return r
fromBER = classmethod(fromBER)
def __init__(self, resultCode=None, matchedDN=None, errorMessage=None,
referral=None, serverSaslCreds=None,
responseName=None, response=None,
tag=None):
LDAPResult.__init__(self,
resultCode=resultCode,
matchedDN=matchedDN,
errorMessage=errorMessage,
referral=referral,
serverSaslCreds=serverSaslCreds)
self.responseName=responseName
self.response=response
def __str__(self):
assert self.referral is None #TODO
l=[BEREnumerated(self.resultCode),
BEROctetString(self.matchedDN),
BEROctetString(self.errorMessage),
#TODO referral [3] Referral OPTIONAL
]
if self.responseName is not None:
l.append(LDAPOID(self.responseName, tag=CLASS_CONTEXT|0x0a))
if self.response is not None:
l.append(BEROctetString(self.response, tag=CLASS_CONTEXT|0x0b))
return str(BERSequence(l, tag=self.tag))
class LDAPStartTLSRequest(LDAPExtendedRequest):
"""
Request to start Transport Layer Security.
See RFC 2830 for details.
"""
oid = '1.3.6.1.4.1.1466.20037'
def __init__(self, requestName=None, tag=None):
assert (requestName is None
or requestName == self.oid), \
'%s requestName was %s instead of %s' \
% (self.__class__.__name__, requestName, self.oid)
LDAPExtendedRequest.__init__(
self,
requestName=self.oid,
tag=tag)
def __repr__(self):
l=[]
if self.tag!=self.__class__.tag:
l.append('tag=%d' % self.tag)
return self.__class__.__name__+'('+', '.join(l)+')'
class LDAPBERDecoderContext(BERDecoderContext):
Identities = {
LDAPBindResponse.tag: LDAPBindResponse,
LDAPBindRequest.tag: LDAPBindRequest,
LDAPUnbindRequest.tag: LDAPUnbindRequest,
LDAPSearchRequest.tag: LDAPSearchRequest,
LDAPSearchResultEntry.tag: LDAPSearchResultEntry,
LDAPSearchResultDone.tag: LDAPSearchResultDone,
LDAPReferral.tag: LDAPReferral,
LDAPModifyRequest.tag: LDAPModifyRequest,
LDAPModifyResponse.tag: LDAPModifyResponse,
LDAPAddRequest.tag: LDAPAddRequest,
LDAPAddResponse.tag: LDAPAddResponse,
LDAPDelRequest.tag: LDAPDelRequest,
LDAPDelResponse.tag: LDAPDelResponse,
LDAPExtendedRequest.tag: LDAPExtendedRequest,
LDAPExtendedResponse.tag: LDAPExtendedResponse,
LDAPModifyDNRequest.tag: LDAPModifyDNRequest,
LDAPModifyDNResponse.tag: LDAPModifyDNResponse,
}
ldaptor-0.0.43/ldaptor/protocols/__init__.py 0000644 0001750 0001750 00000000000 07516345760 017152 0 ustar jan jan ldaptor-0.0.43/ldaptor/protocols/ldap/ 0000755 0001750 0001750 00000000000 10403234307 015752 5 ustar jan jan ldaptor-0.0.43/ldaptor/protocols/ldap/ldaperrors.py 0000644 0001750 0001750 00000007527 10344535643 020527 0 ustar jan jan # Twisted, the Framework of Your Internet
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# make pyflakes not complain about undefined names
reverse = None
LDAPOther = None
def get(resultCode, errorMessage):
"""Get an instance of the correct exception for this resultCode."""
klass = reverse.get(resultCode)
if klass is not None:
return klass(errorMessage)
else:
return LDAPUnknownError(resultCode, errorMessage)
class LDAPResult:
resultCode=None
name=None
class Success(LDAPResult):
resultCode=0
name='success'
def __init__(self, msg):
pass
class LDAPException(Exception, LDAPResult):
def __init__(self, message=None):
Exception.__init__(self)
self.message=message
def __str__(self):
message=self.message
if message:
return '%s: %s' % (self.name, message)
elif self.name:
return self.name
else:
return 'Unknown LDAP error %r' % self
class LDAPUnknownError(LDAPException):
resultCode=None
def __init__(self, resultCode, message=None):
assert resultCode not in reverse, \
"resultCode %r must be unknown" % resultCode
self.code=resultCode
LDAPException.__init__(self, message)
def __str__(self):
codeName='unknownError(%d)'%self.code
if self.message:
return '%s: %s' % (codeName, self.message)
else:
return codeName
import new
def init(**errors):
global reverse
reverse = {}
for name, value in errors.items():
if value == errors['success']:
klass = Success
else:
classname = 'LDAP'+name[0].upper()+name[1:]
klass = new.classobj(classname,
(LDAPException,),
{ 'resultCode': value,
'name': name,
})
globals()[classname] = klass
reverse[value] = klass
init(
success=0,
operationsError=1,
protocolError=2,
timeLimitExceeded=3,
sizeLimitExceeded=4,
compareFalse=5,
compareTrue=6,
authMethodNotSupported=7,
strongAuthRequired=8,
# 9 reserved
referral=10 ,
adminLimitExceeded=11 ,
unavailableCriticalExtension=12 ,
confidentialityRequired=13 ,
saslBindInProgress=14 ,
noSuchAttribute=16,
undefinedAttributeType=17,
inappropriateMatching=18,
constraintViolation=19,
attributeOrValueExists=20,
invalidAttributeSyntax=21,
# 22-31 unused
noSuchObject=32,
aliasProblem=33,
invalidDNSyntax=34,
# 35 reserved for undefined isLeaf
aliasDereferencingProblem=36,
# 37-47 unused
inappropriateAuthentication=48,
invalidCredentials=49,
insufficientAccessRights=50,
busy=51,
unavailable=52,
unwillingToPerform=53,
loopDetect=54,
# 55-63 unused
namingViolation=64,
objectClassViolation=65,
notAllowedOnNonLeaf=66,
notAllowedOnRDN=67,
entryAlreadyExists=68,
objectClassModsProhibited=69,
# 70 reserved for CLDAP
affectsMultipleDSAs=71,
# 72-79 unused
other=80,
# 81-90 reserved for APIs
)
other=LDAPOther.resultCode
ldaptor-0.0.43/ldaptor/protocols/ldap/ldapsyntax.py 0000644 0001750 0001750 00000056576 10345562475 020555 0 ustar jan jan """Pythonic API for LDAP operations."""
from zope.interface import implements
from twisted.internet import defer
from twisted.python.failure import Failure
from ldaptor.protocols.ldap import ldapclient, ldif, distinguishedname, ldaperrors
from ldaptor.protocols import pureldap, pureber
from ldaptor.samba import smbpassword
from ldaptor import ldapfilter, interfaces, delta, attributeset, entry
class PasswordSetAggregateError(Exception):
"""Some of the password plugins failed"""
def __init__(self, errors):
Exception.__init__(self)
self.errors=errors
def __str__(self):
return '%s: %s.' % (
self.__doc__,
'; '.join([ '%s failed with %s' % (name, fail.getErrorMessage())
for name, fail in self.errors]))
def __repr__(self):
return '<'+self.__class__.__name__+' errors='+repr(self.errors)+'>'
class PasswordSetAborted(Exception):
"""Aborted"""
def __str__(self):
return self.__doc__
class DNNotPresentError(Exception):
"""The requested DN cannot be found by the server."""
pass
class ObjectInBadStateError(Exception):
"""The LDAP object in in a bad state."""
pass
class ObjectDeletedError(ObjectInBadStateError):
"""The LDAP object has already been removed, unable to perform operations on it."""
pass
class ObjectDirtyError(ObjectInBadStateError):
"""The LDAP object has a journal which needs to be committed or undone before this operation."""
pass
class NoContainingNamingContext(Exception):
"""The server contains to LDAP naming context that would contain this object."""
pass
class CannotRemoveRDNError(Exception):
"""The attribute to be removed is the RDN for the object and cannot be removed."""
def __init__(self, key, val=None):
Exception.__init__(self)
self.key=key
self.val=val
def __str__(self):
if self.val is None:
r=repr(self.key)
else:
r='%s=%s' % (repr(self.key), repr(self.val))
return """The attribute to be removed, %s, is the RDN for the object and cannot be removed.""" % r
class MatchNotImplemented(NotImplementedError):
"""Match type not implemented"""
def __init__(self, op):
Exception.__init__(self)
self.op=op
def __str__(self):
return '%s: %r' % (self.__doc__, self.op)
class JournaledLDAPAttributeSet(attributeset.LDAPAttributeSet):
def __init__(self, ldapObject, *a, **kw):
self.ldapObject = ldapObject
super(JournaledLDAPAttributeSet, self).__init__(*a, **kw)
def add(self, value):
self.ldapObject.journal(delta.Add(self.key, [value]))
super(JournaledLDAPAttributeSet, self).add(value)
def update(self, sequence):
self.ldapObject.journal(delta.Add(self.key, sequence))
super(JournaledLDAPAttributeSet, self).update(sequence)
def remove(self, value):
if value not in self:
raise LookupError, value
self.ldapObject._canRemove(self.key, value)
self.ldapObject.journal(delta.Delete(self.key, [value]))
super(JournaledLDAPAttributeSet, self).remove(value)
def clear(self):
self.ldapObject._canRemoveAll(self.key)
super(JournaledLDAPAttributeSet, self).clear()
self.ldapObject.journal(delta.Delete(self.key))
class LDAPEntryWithClient(entry.EditableLDAPEntry):
implements(interfaces.ILDAPEntry,
interfaces.IEditableLDAPEntry,
interfaces.IConnectedLDAPEntry,
)
_state = 'invalid'
"""
State of an LDAPEntry is one of:
invalid - object not initialized yet
ready - normal
deleted - object has been deleted
"""
def __init__(self, client, dn, attributes={}, complete=0):
"""
Initialize the object.
@param client: The LDAP client connection this object belongs
to.
@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.
"""
super(LDAPEntryWithClient, self).__init__(dn, attributes)
self.client=client
self.complete = complete
self._journal=[]
self._remoteData = entry.EditableLDAPEntry(dn, attributes)
self._state = 'ready'
def buildAttributeSet(self, key, values):
return JournaledLDAPAttributeSet(self, key, values)
def _canRemove(self, key, value):
"""
Called by JournaledLDAPAttributeSet when it is about to remove a value
of an attributeType.
"""
self._checkState()
for rdn in self.dn.split()[0].split():
if rdn.attributeType == key and rdn.value == value:
raise CannotRemoveRDNError, (key, value)
def _canRemoveAll(self, key):
"""
Called by JournaledLDAPAttributeSet when it is about to remove all values
of an attributeType.
"""
self._checkState()
import types
assert not isinstance(self.dn, types.StringType)
for keyval in self.dn.split()[0].split():
if keyval.attributeType == key:
raise CannotRemoveRDNError, (key)
def _checkState(self):
if self._state != 'ready':
if self._state == 'deleted':
raise ObjectDeletedError
else:
raise ObjectInBadStateError, \
"State is %s while expecting %s" \
% (repr(self._state), repr('ready'))
def journal(self, journalOperation):
"""
Add a Modification into the list of modifications
that need to be flushed to the LDAP server.
Normal callers should not use this, they should use the
o['foo']=['bar', 'baz'] -style API that enforces schema,
handles errors and updates the cached data.
"""
self._journal.append(journalOperation)
# start ILDAPEntry
def __getitem__(self, *a, **kw):
self._checkState()
return super(LDAPEntryWithClient, self).__getitem__(*a, **kw)
def get(self, *a, **kw):
self._checkState()
return super(LDAPEntryWithClient, self).get(*a, **kw)
def has_key(self, *a, **kw):
self._checkState()
return super(LDAPEntryWithClient, self).has_key(*a, **kw)
def __contains__(self, key):
self._checkState()
return self.has_key(key)
def keys(self):
self._checkState()
return super(LDAPEntryWithClient, self).keys()
def items(self):
self._checkState()
return super(LDAPEntryWithClient, self).items()
def __str__(self):
a=[]
objectClasses = list(self.get('objectClass', []))
objectClasses.sort()
a.append(('objectClass', objectClasses))
l=list(self.items())
l.sort()
for key, values in l:
if key!='objectClass':
a.append((key, values))
return ldif.asLDIF(self.dn, a)
def __eq__(self, other):
if not isinstance(other, self.__class__):
return 0
if self.dn != other.dn:
return 0
my=self.keys()
my.sort()
its=other.keys()
its.sort()
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 __nonzero__(self):
return True
def bind(self, password):
r=pureldap.LDAPBindRequest(dn=str(self.dn), auth=password)
d = self.client.send(r)
d.addCallback(self._handle_bind_msg)
return d
def _handle_bind_msg(self, msg):
assert isinstance(msg, pureldap.LDAPBindResponse)
assert msg.referral is None #TODO
if msg.resultCode!=ldaperrors.Success.resultCode:
raise ldaperrors.get(msg.resultCode, msg.errorMessage)
return self
# end ILDAPEntry
# start IEditableLDAPEntry
def __setitem__(self, key, value):
self._checkState()
self._canRemoveAll(key)
new=JournaledLDAPAttributeSet(self, key, value)
super(LDAPEntryWithClient, self).__setitem__(key, new)
self.journal(delta.Replace(key, value))
def __delitem__(self, key):
self._checkState()
self._canRemoveAll(key)
super(LDAPEntryWithClient, self).__delitem__(key)
self.journal(delta.Delete(key))
def undo(self):
self._checkState()
self._attributes.clear()
for k, vs in self._remoteData.items():
self._attributes[k] = self.buildAttributeSet(k, vs)
self._journal=[]
def _commit_success(self, msg):
assert isinstance(msg, pureldap.LDAPModifyResponse)
assert msg.referral is None #TODO
if msg.resultCode!=ldaperrors.Success.resultCode:
raise ldaperrors.get(msg.resultCode, msg.errorMessage)
assert msg.matchedDN==''
self._remoteData = entry.EditableLDAPEntry(self.dn, self)
self._journal=[]
return self
def commit(self):
self._checkState()
if not self._journal:
return defer.succeed(self)
op=pureldap.LDAPModifyRequest(
object=str(self.dn),
modification=[x.asLDAP() for x in self._journal])
d = defer.maybeDeferred(self.client.send, op)
d.addCallback(self._commit_success)
return d
def _cbMoveDone(self, msg, newDN):
assert isinstance(msg, pureldap.LDAPModifyDNResponse)
assert msg.referral is None #TODO
if msg.resultCode!=ldaperrors.Success.resultCode:
raise ldaperrors.get(msg.resultCode, msg.errorMessage)
assert msg.matchedDN==''
self.dn = newDN
return self
def move(self, newDN):
self._checkState()
newDN = distinguishedname.DistinguishedName(newDN)
newrdn=newDN.split()[0]
newSuperior=distinguishedname.DistinguishedName(listOfRDNs=newDN.split()[1:])
newDN = distinguishedname.DistinguishedName((newrdn,) + newSuperior.split())
op = pureldap.LDAPModifyDNRequest(entry=str(self.dn),
newrdn=str(newrdn),
deleteoldrdn=1,
newSuperior=str(newSuperior))
d = self.client.send(op)
d.addCallback(self._cbMoveDone, newDN)
return d
def _cbDeleteDone(self, msg):
assert isinstance(msg, pureldap.LDAPResult)
if not isinstance(msg, pureldap.LDAPDelResponse):
raise ldaperrors.get(msg.resultCode,
msg.errorMessage)
assert msg.referral is None #TODO
if msg.resultCode!=ldaperrors.Success.resultCode:
raise ldaperrors.get(msg.resultCode, msg.errorMessage)
assert msg.matchedDN==''
return self
def delete(self):
self._checkState()
op = pureldap.LDAPDelRequest(entry=str(self.dn))
d = self.client.send(op)
d.addCallback(self._cbDeleteDone)
self._state = 'deleted'
return d
def _cbAddDone(self, msg, dn):
assert isinstance(msg, pureldap.LDAPAddResponse), \
"LDAPRequest response was not an LDAPAddResponse: %r" % msg
assert msg.referral is None #TODO
if msg.resultCode!=ldaperrors.Success.resultCode:
raise ldaperrors.get(msg.resultCode, msg.errorMessage)
assert msg.matchedDN==''
e = self.__class__(dn=dn, client=self.client)
return e
def addChild(self, rdn, attributes):
self._checkState()
rdn = distinguishedname.RelativeDistinguishedName(rdn)
dn = distinguishedname.DistinguishedName(
listOfRDNs=(rdn,)+self.dn.split())
ldapAttrs = []
for attrType, values in attributes.items():
ldapAttrType = pureldap.LDAPAttributeDescription(attrType)
l = []
for value in values:
l.append(pureldap.LDAPAttributeValue(value))
ldapValues = pureber.BERSet(l)
ldapAttrs.append((ldapAttrType, ldapValues))
op=pureldap.LDAPAddRequest(entry=str(dn),
attributes=ldapAttrs)
d = self.client.send(op)
d.addCallback(self._cbAddDone, dn)
return d
def _cbSetPassword_ExtendedOperation(self, msg):
assert isinstance(msg, pureldap.LDAPExtendedResponse)
assert msg.referral is None #TODO
if msg.resultCode!=ldaperrors.Success.resultCode:
raise ldaperrors.get(msg.resultCode, msg.errorMessage)
assert msg.matchedDN==''
return self
def setPassword_ExtendedOperation(self, newPasswd):
"""
Set the password on this object.
@param newPasswd: A string containing the new password.
@return: A Deferred that will complete when the operation is
done.
"""
self._checkState()
op = pureldap.LDAPPasswordModifyRequest(userIdentity=str(self.dn), newPasswd=newPasswd)
d = self.client.send(op)
d.addCallback(self._cbSetPassword_ExtendedOperation)
return d
_setPasswordPriority_ExtendedOperation=0
setPasswordMaybe_ExtendedOperation = setPassword_ExtendedOperation
def setPassword_Samba(self, newPasswd, style=None):
"""
Set the Samba password on this object.
@param newPasswd: A string containing the new password.
@param style: one of 'sambaSamAccount', 'sambaAccount' or
None. Specifies the style of samba accounts used. None is
default and is the same as 'sambaSamAccount'.
@return: A Deferred that will complete when the operation is
done.
"""
self._checkState()
nthash=smbpassword.nthash(newPasswd)
lmhash=smbpassword.lmhash(newPasswd)
if style is None:
style = 'sambaSamAccount'
if style == 'sambaSamAccount':
self['sambaNTPassword'] = [nthash]
self['sambaLMPassword'] = [lmhash]
elif style == 'sambaAccount':
self['ntPassword'] = [nthash]
self['lmPassword'] = [lmhash]
else:
raise RuntimeError, "Unknown samba password style %r" % style
return self.commit()
_setPasswordPriority_Samba=20
def setPasswordMaybe_Samba(self, newPasswd):
"""
Set the Samba password on this object if it is a
sambaSamAccount or sambaAccount.
@param newPasswd: A string containing the new password.
@return: A Deferred that will complete when the operation is
done.
"""
if not self.complete and not self.has_key('objectClass'):
d=self.fetch('objectClass')
d.addCallback(lambda dummy, self=self, newPasswd=newPasswd:
self.setPasswordMaybe_Samba(newPasswd))
else:
objectClasses = [s.upper() for s in self.get('objectClass', ())]
if 'sambaAccount'.upper() in objectClasses:
d = self.setPassword_Samba(newPasswd, style="sambaAccount")
elif 'sambaSamAccount'.upper() in objectClasses:
d = self.setPassword_Samba(newPasswd, style="sambaSamAccount")
else:
d = defer.succeed(self)
return d
def _cbSetPassword(self, dl, names):
assert len(dl)==len(names)
l=[]
for name, (ok, x) in zip(names, dl):
if not ok:
l.append((name, x))
if l:
raise PasswordSetAggregateError, l
return self
def _cbSetPassword_one(self, result):
return (True, None)
def _ebSetPassword_one(self, fail):
fail.trap(ldaperrors.LDAPException,
DNNotPresentError)
return (False, fail)
def _setPasswordAll(self, results, newPasswd, prefix, names):
if not names:
return results
name, names = names[0], names[1:]
if results and not results[-1][0]:
# failing
fail = Failure(PasswordSetAborted())
d = defer.succeed(results+[(None, fail)])
else:
fn = getattr(self, prefix+name)
d = defer.maybeDeferred(fn, newPasswd)
d.addCallbacks(self._cbSetPassword_one,
self._ebSetPassword_one)
def cb((success, info)):
return results+[(success, info)]
d.addCallback(cb)
d.addCallback(self._setPasswordAll,
newPasswd, prefix, names)
return d
def setPassword(self, newPasswd):
def _passwordChangerPriorityComparison(me, other):
mePri = getattr(self, '_setPasswordPriority_'+me)
otherPri = getattr(self, '_setPasswordPriority_'+other)
return cmp(mePri, otherPri)
prefix='setPasswordMaybe_'
names=[name[len(prefix):] for name in dir(self) if name.startswith(prefix)]
names.sort(_passwordChangerPriorityComparison)
d = defer.maybeDeferred(self._setPasswordAll,
[],
newPasswd,
prefix,
names)
d.addCallback(self._cbSetPassword, names)
return d
# end IEditableLDAPEntry
# start IConnectedLDAPEntry
def _cbNamingContext_Entries(self, results):
for result in results:
for namingContext in result.get('namingContexts', ()):
dn = distinguishedname.DistinguishedName(namingContext)
if dn.contains(self.dn):
return LDAPEntry(self.client, dn)
raise NoContainingNamingContext, self.dn
def namingContext(self):
o=LDAPEntry(client=self.client, dn='')
d=o.search(filterText='(objectClass=*)',
scope=pureldap.LDAP_SCOPE_baseObject,
attributes=['namingContexts'])
d.addCallback(self._cbNamingContext_Entries)
return d
def _cbFetch(self, results, overWrite):
if len(results)!=1:
raise DNNotPresentError, self.dn
o=results[0]
assert not self._journal
if not overWrite:
for key in self._remoteData.keys():
del self._remoteData[key]
overWrite=o.keys()
self.complete = 1
for k in overWrite:
vs=o.get(k)
if vs is not None:
self._remoteData[k] = vs
self.undo()
return self
def fetch(self, *attributes):
self._checkState()
if self._journal:
raise ObjectDirtyError, 'cannot fetch attributes of %s, it is dirty' % repr(self)
d = self.search(scope=pureldap.LDAP_SCOPE_baseObject,
attributes=attributes)
d.addCallback(self._cbFetch, overWrite=attributes)
return d
def _cbSearchEntry(self, callback, objectName, attributes, complete):
attrib={}
for key, values in attributes:
attrib[str(key)]=[str(x) for x in values]
o=LDAPEntry(client=self.client,
dn=objectName,
attributes=attrib,
complete=complete)
callback(o)
def _cbSearchMsg(self, msg, d, callback, complete, sizeLimitIsNonFatal):
if isinstance(msg, pureldap.LDAPSearchResultDone):
assert msg.referral is None #TODO
e = ldaperrors.get(msg.resultCode, msg.errorMessage)
if not isinstance(e, ldaperrors.Success):
try:
raise e
except ldaperrors.LDAPSizeLimitExceeded, e:
if sizeLimitIsNonFatal:
pass
except:
d.errback(Failure())
return True
# search ended successfully
assert msg.matchedDN==''
d.callback(None)
return True
elif isinstance(msg, pureldap.LDAPSearchResultEntry):
self._cbSearchEntry(callback, msg.objectName, msg.attributes,
complete=complete)
return False
else:
raise ldaperrors.LDAPProtocolError, \
'bad search response: %r' % msg
def search(self,
filterText=None,
filterObject=None,
attributes=(),
scope=None,
derefAliases=None,
sizeLimit=0,
sizeLimitIsNonFatal=False,
timeLimit=0,
typesOnly=0,
callback=None):
self._checkState()
d=defer.Deferred()
if filterObject is None and filterText is None:
filterObject=pureldap.LDAPFilterMatchAll
elif filterObject is None and filterText is not None:
filterObject=ldapfilter.parseFilter(filterText)
elif filterObject is not None and filterText is None:
pass
elif filterObject is not None and filterText is not None:
f=ldapfilter.parseFilter(filterText)
filterObject=pureldap.LDAPFilter_and((f, filterObject))
if scope is None:
scope = pureldap.LDAP_SCOPE_wholeSubtree
if derefAliases is None:
derefAliases = pureldap.LDAP_DEREF_neverDerefAliases
if attributes is None:
attributes = ['1.1']
results=[]
if callback is None:
cb=results.append
else:
cb=callback
try:
op = pureldap.LDAPSearchRequest(
baseObject=str(self.dn),
scope=scope,
derefAliases=derefAliases,
sizeLimit=sizeLimit,
timeLimit=timeLimit,
typesOnly=typesOnly,
filter=filterObject,
attributes=attributes)
self.client.send_multiResponse(
op, self._cbSearchMsg,
d, cb, complete=not attributes,
sizeLimitIsNonFatal=sizeLimitIsNonFatal)
except ldapclient.LDAPClientConnectionLostException:
d.errback(Failure())
else:
if callback is None:
d.addCallback(lambda dummy: results)
return d
def lookup(self, dn):
e = self.__class__(self.client, dn)
d = e.fetch('1.1')
return d
# end IConnectedLDAPEntry
def __repr__(self):
x={}
for key in super(LDAPEntryWithClient, self).keys():
x[key]=self[key]
keys=x.keys()
keys.sort()
a=[]
for key in keys:
a.append('%s: %s' % (repr(key), repr(self[key])))
attributes=', '.join(a)
return '%s(dn=%s, attributes={%s})' % (
self.__class__.__name__,
repr(str(self.dn)),
attributes)
# API backwards compatibility
LDAPEntry = LDAPEntryWithClient
class LDAPEntryWithAutoFill(LDAPEntry):
def __init__(self, *args, **kwargs):
LDAPEntry.__init__(self, *args, **kwargs)
self.autoFillers = []
def _cb_addAutofiller(self, r, autoFiller):
self.autoFillers.append(autoFiller)
return r
def addAutofiller(self, autoFiller):
d = defer.maybeDeferred(autoFiller.start, self)
d.addCallback(self._cb_addAutofiller, autoFiller)
return d
def journal(self, journalOperation):
LDAPEntry.journal(self, journalOperation)
for autoFiller in self.autoFillers:
autoFiller.notify(self, journalOperation.key)
ldaptor-0.0.43/ldaptor/protocols/ldap/ldif.py 0000644 0001750 0001750 00000002650 10344535643 017260 0 ustar jan jan """
Support for writing a set of directory entries as LDIF.
You probably want to use this only indirectly, as in
str(LDAPEntry(...)).
TODO support writing modify operations
TODO support reading modify operations
TODO implement rest of syntax from RFC2849
"""
# RFC2849: The LDAP Data Interchange Format (LDIF) - Technical Specification
import base64
def base64_encode(s):
return ''.join(base64.encodestring(s).split('\n'))+'\n'
def attributeAsLDIF_base64(attribute, value):
return "%s:: %s" % (attribute, base64_encode(value))
def containsNonprintable(s):
for c in s:
if ord(c) > 127 or c in ('\0', '\n', '\r'):
return 1
return 0
def attributeAsLDIF(attribute, value):
if value.startswith('\0') \
or value.startswith('\n') \
or value.startswith('\r') \
or value.startswith(' ') \
or value.startswith(':') \
or value.startswith('<') \
or value.endswith(' ') \
or containsNonprintable(value):
return attributeAsLDIF_base64(attribute, value)
else:
return "%s: %s\n" % (attribute, value)
def asLDIF(dn, attributes):
s="dn: %s\n"%dn
for k,vs in attributes:
for v in vs:
s=s+attributeAsLDIF(k, v)
s=s+"\n"
return s
def header():
return "version: 1\n\n"
def manyAsLDIF(objects):
s=[header()]
for dn, attributes in objects:
s.append(asLDIF(dn, attributes))
return ''.join(s)
ldaptor-0.0.43/ldaptor/protocols/ldap/ldapclient.py 0000644 0001750 0001750 00000017332 10344535643 020464 0 ustar jan jan # Twisted, the Framework of Your Internet
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""LDAP protocol client"""
from ldaptor.protocols import pureldap, pureber
from ldaptor.protocols.ldap import ldaperrors
from twisted.python import log
from twisted.internet import protocol, defer, ssl, reactor
class LDAPClientConnectionLostException(ldaperrors.LDAPException):
def __str__(self):
return 'Connection lost'
class LDAPStartTLSBusyError(ldaperrors.LDAPOperationsError):
def __init__(self, onwire, message=None):
self.onwire = onwire
ldaperrors.LDAPOperationsError.__init__(self, message=message)
def __str__(self):
return 'Cannot STARTTLS while operations on wire: %r' % self.onwire
class LDAPClient(protocol.Protocol):
"""An LDAP client"""
debug = False
def __init__(self):
self.onwire = {}
self.buffer = ''
self.connected = None
berdecoder = pureldap.LDAPBERDecoderContext_TopLevel(
inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())))
def dataReceived(self, recd):
self.buffer += recd
while 1:
try:
o, bytes = pureber.berDecodeObject(self.berdecoder, self.buffer)
except pureldap.BERExceptionInsufficientData:
o, bytes = None, 0
self.buffer = self.buffer[bytes:]
if not o:
break
self.handle(o)
def connectionMade(self):
"""TCP connection has opened"""
self.connected = 1
def connectionLost(self, reason=protocol.connectionDone):
"""Called when TCP connection has been lost"""
self.connected = 0
# notify handlers of operations in flight
while self.onwire:
k, v = self.onwire.popitem()
d, _, _, _ = v
d.errback(reason)
def _send(self, op):
if not self.connected:
raise LDAPClientConnectionLostException()
msg=pureldap.LDAPMessage(op)
if self.debug:
log.debug('C->S %s' % repr(msg))
assert not self.onwire.has_key(msg.id)
return msg
def _cbSend(self, msg, d):
d.callback(msg)
return True
def send(self, op):
"""
Send an LDAP operation to the server.
@param op: the operation to send
@type op: LDAPProtocolRequest
@return: the response from server
@rtype: Deferred LDAPProtocolResponse
"""
msg = self._send(op)
assert op.needs_answer
d = defer.Deferred()
self.onwire[msg.id]=(d, None, None, None)
self.transport.write(str(msg))
return d
def send_multiResponse(self, op, handler, *args, **kwargs):
"""
Send an LDAP operation to the server, expecting one or more
responses.
@param op: the operation to send
@type op: LDAPProtocolRequest
@param handler: a callable that will be called for each
response. It should return a boolean, whether this was the
final response.
@param args: positional arguments to pass to handler
@param kwargs: keyword arguments to pass to handler
@return: the result from the last handler as a deferred that
completes when the last response has been received
@rtype: Deferred LDAPProtocolResponse
"""
msg = self._send(op)
assert op.needs_answer
d = defer.Deferred()
self.onwire[msg.id]=(d, handler, args, kwargs)
self.transport.write(str(msg))
return d
def send_noResponse(self, op):
"""
Send an LDAP operation to the server, with no response
expected.
@param op: the operation to send
@type op: LDAPProtocolRequest
"""
msg = self._send(op)
assert not op.needs_answer
self.transport.write(str(msg))
def unsolicitedNotification(self, msg):
log.msg("Got unsolicited notification: %s" % repr(msg))
def handle(self, msg):
assert isinstance(msg.value, pureldap.LDAPProtocolResponse)
if self.debug:
log.debug('C<-S %s' % repr(msg))
if msg.id==0:
self.unsolicitedNotification(msg.value)
else:
d, handler, args, kwargs = self.onwire[msg.id]
if handler is None:
assert args is None
assert kwargs is None
d.callback(msg.value)
del self.onwire[msg.id]
else:
assert args is not None
assert kwargs is not None
# Return true to mark request as fully handled
if handler(msg.value, *args, **kwargs):
del self.onwire[msg.id]
##Bind
def bind(self, dn='', auth=''):
"""
@depreciated: Use e.bind(auth).
@todo: Remove this method when there are no callers.
"""
if not self.connected:
raise LDAPClientConnectionLostException()
else:
r=pureldap.LDAPBindRequest(dn=dn, auth=auth)
d = self.send(r)
d.addCallback(self._handle_bind_msg)
return d
def _handle_bind_msg(self, msg):
assert isinstance(msg, pureldap.LDAPBindResponse)
assert msg.referral is None #TODO
if msg.resultCode!=ldaperrors.Success.resultCode:
raise ldaperrors.get(msg.resultCode, msg.errorMessage)
return (msg.matchedDN, msg.serverSaslCreds)
##Unbind
def unbind(self):
if not self.connected:
raise "Not connected (TODO)" #TODO make this a real object
r=pureldap.LDAPUnbindRequest()
self.send_noResponse(r)
self.transport.loseConnection()
def _cbStartTLS(self, msg, ctx):
assert isinstance(msg, pureldap.LDAPExtendedResponse)
assert msg.referral is None #TODO
if msg.resultCode!=ldaperrors.Success.resultCode:
raise ldaperrors.get(msg.resultCode, msg.errorMessage)
self.transport.startTLS(ctx)
return self
def startTLS(self, ctx=None):
"""
Start Transport Layer Security.
It is the callers responsibility to make sure other things
are not happening at the same time.
@todo: server hostname check, see rfc2830 section 3.6.
"""
if ctx is None:
ctx = ssl.ClientContextFactory()
# we always delay by one event loop iteration to make
# sure the previous handler has exited and self.onwire
# has been cleaned up
d=defer.Deferred()
d.addCallback(self._startTLS)
reactor.callLater(0, d.callback, ctx)
return d
def _startTLS(self, ctx):
if not self.connected:
raise LDAPClientConnectionLostException
elif self.onwire:
raise LDAPStartTLSBusyError, self.onwire
else:
op=pureldap.LDAPStartTLSRequest()
d = self.send(op)
d.addCallback(self._cbStartTLS, ctx)
return d
ldaptor-0.0.43/ldaptor/protocols/ldap/__init__.py 0000644 0001750 0001750 00000001407 10344535643 020100 0 ustar jan jan # Twisted, the Framework of Your Internet
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""LDAP protocol logic"""
ldaptor-0.0.43/ldaptor/protocols/ldap/proxy.py 0000644 0001750 0001750 00000006465 10344407651 017530 0 ustar jan jan """LDAP protocol proxy server"""
from twisted.internet import reactor, defer
from ldaptor.protocols.ldap import ldapserver, ldapconnector, ldapclient
from ldaptor.protocols import pureldap
class Proxy(ldapserver.BaseLDAPServer):
protocol = ldapclient.LDAPClient
client = None
waitingConnect = []
unbound = False
def __init__(self, config):
"""
Initialize the object.
@param config: The configuration.
@type config: ldaptor.interfaces.ILDAPConfig
"""
ldapserver.BaseLDAPServer.__init__(self)
self.config = config
def _whenConnected(self, fn, *a, **kw):
if self.client is None:
d = defer.Deferred()
self.waitingConnect.append((d, fn, a, kw))
return d
else:
return defer.maybeDeferred(fn, *a, **kw)
def _cbConnectionMade(self, proto):
self.client = proto
while self.waitingConnect:
d, fn, a, kw = self.waitingConnect.pop(0)
d2 = defer.maybeDeferred(fn, *a, **kw)
d2.chainDeferred(d)
def _clientQueue(self, request, controls, reply):
# TODO controls
if request.needs_answer:
d = self.client.send_multiResponse(request, self._gotResponse, reply)
# TODO handle d errbacks
else:
self.client.send_noResponse(request)
def _gotResponse(self, response, reply):
reply(response)
# TODO this is ugly
return isinstance(response, (
pureldap.LDAPSearchResultDone,
pureldap.LDAPBindResponse,
))
def _failConnection(self, reason):
#TODO self.loseConnection()
return reason # TODO
def connectionMade(self):
clientCreator = ldapconnector.LDAPClientCreator(
reactor, self.protocol)
d = clientCreator.connect(
dn='',
overrides=self.config.getServiceLocationOverrides())
d.addCallback(self._cbConnectionMade)
d.addErrback(self._failConnection)
ldapserver.BaseLDAPServer.connectionMade(self)
def connectionLost(self, reason):
assert self.client is not None
if self.client.connected:
if not self.unbound:
self.client.unbind()
self.unbound = True
else:
self.client.transport.loseConnection()
self.client = None
ldapserver.BaseLDAPServer.connectionLost(self, reason)
def _handleUnknown(self, request, controls, reply):
self._whenConnected(self._clientQueue, request, controls, reply)
return None
def handleUnknown(self, request, controls, reply):
d = defer.succeed(request)
d.addCallback(self._handleUnknown, controls, reply)
return d
def handle_LDAPUnbindRequest(self, request, controls, reply):
self.unbound = True
self.handleUnknown(request, controls, reply)
if __name__ == '__main__':
"""
Demonstration LDAP proxy; passes all requests to localhost:389.
"""
from twisted.internet import protocol
from twisted.python import log
import sys
log.startLogging(sys.stderr)
factory = protocol.ServerFactory()
factory.protocol = lambda : Proxy(overrides={
'': ('localhost', 389),
})
reactor.listenTCP(10389, factory)
reactor.run()
ldaptor-0.0.43/ldaptor/protocols/ldap/ldifdelta.py 0000644 0001750 0001750 00000012200 10344407651 020257 0 ustar jan jan from twisted.python.failure import Failure
from twisted.internet import error
from ldaptor.protocols.ldap import ldifprotocol
from ldaptor import delta, entry
WAIT_FOR_CHANGETYPE = 'WAIT_FOR_CHANGETYPE'
WAIT_FOR_MOD_SPEC = 'WAIT_FOR_MOD_SPEC'
IN_MOD_SPEC = 'IN_MOD_SPEC'
IN_ADD_ENTRY = 'IN_ADD_ENTRY'
IN_DELETE = 'IN_DELETE'
class LDIFDeltaMissingChangeTypeError(ldifprotocol.LDIFParseError):
"""LDIF delta entry has no changetype."""
pass
class LDIFDeltaUnknownModificationError(ldifprotocol.LDIFParseError):
"""LDIF delta modification has unknown mod-spec."""
pass
class LDIFDeltaModificationMissingEndDashError(ldifprotocol.LDIFParseError):
"""LDIF delta modification has no ending dash."""
pass
class LDIFDeltaModificationDifferentAttributeTypeError(ldifprotocol.LDIFParseError):
"""The attribute type for the change is not the as in the mod-spec header line."""
pass
class LDIFDeltaAddMissingAttributesError(ldifprotocol.LDIFParseError):
"""Add operation needs to have atleast one attribute type and value."""
pass
class LDIFDeltaDeleteHasJunkAfterChangeTypeError(ldifprotocol.LDIFParseError):
"""Delete operation takes no attribute types or values."""
pass
class LDIFDelta(ldifprotocol.LDIF):
def state_WAIT_FOR_DN(self, line):
super(LDIFDelta, self).state_WAIT_FOR_DN(line)
if self.mode == ldifprotocol.IN_ENTRY:
self.mode = WAIT_FOR_CHANGETYPE
def state_WAIT_FOR_CHANGETYPE(self, line):
assert self.dn is not None, 'self.dn must be set when in entry'
assert self.data is not None, 'self.data must be set when in entry'
if line == '':
raise LDIFDeltaMissingChangeTypeError, self.dn
key, val = self._parseLine(line)
if key != 'changetype':
raise LDIFDeltaMissingChangeTypeError, (self.dn, key, val)
if val == 'modify':
self.modifications = []
self.mode = WAIT_FOR_MOD_SPEC
elif val == 'add':
self.mode = IN_ADD_ENTRY
elif val == 'delete':
self.mode = IN_DELETE
elif val == 'modrdn' or val == 'moddn':
raise NotImplementedError #TODO
MOD_SPEC_TO_DELTA = {
'add': delta.Add,
'delete': delta.Delete,
'replace': delta.Replace,
}
def state_WAIT_FOR_MOD_SPEC(self, line):
if line == '':
# end of entry
self.mode = ldifprotocol.WAIT_FOR_DN
m = delta.ModifyOp(dn=self.dn,
modifications=self.modifications)
self.dn = None
self.data = None
self.modifications = None
self.gotEntry(m)
return
key, val = self._parseLine(line)
if key not in self.MOD_SPEC_TO_DELTA:
raise LDIFDeltaUnknownModificationError, \
(self.dn, key)
self.mod_spec = key
self.mod_spec_attr = val
self.mod_spec_data = []
self.mode = IN_MOD_SPEC
def state_IN_MOD_SPEC(self, line):
if line == '':
raise LDIFDeltaModificationMissingEndDashError
if line == '-':
mod = self.MOD_SPEC_TO_DELTA[self.mod_spec]
de = mod(self.mod_spec_attr, self.mod_spec_data)
self.modifications.append(de)
del self.mod_spec
del self.mod_spec_attr
del self.mod_spec_data
self.mode = WAIT_FOR_MOD_SPEC
return
key, val = self._parseLine(line)
if key != self.mod_spec_attr:
raise LDIFDeltaModificationDifferentAttributeTypeError, \
(key, self.mod_spec_attr)
self.mod_spec_data.append(val)
def state_IN_ADD_ENTRY(self, line):
assert self.dn is not None, 'self.dn must be set when in entry'
assert self.data is not None, 'self.data must be set when in entry'
if line == '':
# end of entry
if not self.data:
raise LDIFDeltaAddMissingAttributesError, \
self.dn
self.mode = ldifprotocol.WAIT_FOR_DN
o = delta.AddOp(entry.BaseLDAPEntry(dn=self.dn,
attributes=self.data))
self.dn = None
self.data = None
self.gotEntry(o)
return
key, val = self._parseLine(line)
if not key in self.data:
self.data[key] = []
self.data[key].append(val)
def state_IN_DELETE(self, line):
assert self.dn is not None, 'self.dn must be set when in entry'
if line == '':
# end of entry
self.mode = ldifprotocol.WAIT_FOR_DN
o = delta.DeleteOp(dn=self.dn)
self.dn = None
self.data = None
self.gotEntry(o)
return
raise LDIFDeltaDeleteHasJunkAfterChangeTypeError, \
(self.dn, line)
def fromLDIFFile(f):
"""Read LDIF data from a file."""
p = LDIFDelta()
l = []
p.gotEntry = l.append
while 1:
data = f.read()
if not data:
break
p.dataReceived(data)
p.connectionLost(Failure(error.ConnectionDone()))
return l
ldaptor-0.0.43/ldaptor/protocols/ldap/ldapserver.py 0000644 0001750 0001750 00000041447 10402661331 020505 0 ustar jan jan # Ldaptor, a Pure-Python library for LDAP
# Copyright (C) 2003 Tommi Virtanen
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""LDAP protocol server"""
import sets
from ldaptor import interfaces, delta
from ldaptor.protocols import pureldap, pureber
from ldaptor.protocols.ldap import distinguishedname, ldaperrors
from twisted.python import log
from twisted.internet import protocol, defer
class LDAPServerConnectionLostException(ldaperrors.LDAPException):
pass
class BaseLDAPServer(protocol.Protocol):
debug = False
def __init__(self):
self.buffer = ''
self.connected = None
berdecoder = pureldap.LDAPBERDecoderContext_TopLevel(
inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())))
def dataReceived(self, recd):
self.buffer += recd
while 1:
try:
o, bytes=pureber.berDecodeObject(self.berdecoder, self.buffer)
except pureldap.BERExceptionInsufficientData:
o, bytes=None, 0
self.buffer = self.buffer[bytes:]
if o is None:
break
self.handle(o)
def connectionMade(self):
"""TCP connection has opened"""
self.connected = 1
def connectionLost(self, reason=protocol.connectionDone):
"""Called when TCP connection has been lost"""
self.connected = 0
def queue(self, id, op):
if not self.connected:
raise LDAPServerConnectionLostException()
msg=pureldap.LDAPMessage(op, id=id)
if self.debug:
log.debug('S->C %s' % repr(msg))
self.transport.write(str(msg))
def unsolicitedNotification(self, msg):
log.msg("Got unsolicited notification: %s" % repr(msg))
def checkControls(self, controls):
if controls is not None:
for controlType, criticality, controlValue in controls:
if criticality:
raise ldaperrors.LDAPUnavailableCriticalExtension, \
'Unknown control %s' % controlType
def handleUnknown(self, request, controls, callback):
log.msg('Unknown request: %r' % request)
msg = pureldap.LDAPExtendedResponse(resultCode=ldaperrors.LDAPProtocolError.resultCode,
responseName='1.3.6.1.4.1.1466.20036',
errorMessage='Unknown request')
return msg
def _cbLDAPError(self, reason, name):
reason.trap(ldaperrors.LDAPException)
return self._callErrorHandler(name=name,
resultCode=reason.value.resultCode,
errorMessage=reason.value.message)
def _cbHandle(self, response, id):
if response is not None:
self.queue(id, response)
def failDefault(self, resultCode, errorMessage):
return pureldap.LDAPExtendedResponse(resultCode=resultCode,
responseName='1.3.6.1.4.1.1466.20036',
errorMessage=errorMessage)
def _callErrorHandler(self, name, resultCode, errorMessage):
errh = getattr(self, 'fail_'+name, self.failDefault)
return errh(resultCode=resultCode, errorMessage=errorMessage)
def _cbOtherError(self, reason, name):
return self._callErrorHandler(name=name,
resultCode=ldaperrors.LDAPProtocolError.resultCode,
errorMessage=reason.getErrorMessage())
def handle(self, msg):
assert isinstance(msg.value, pureldap.LDAPProtocolRequest)
if self.debug:
log.debug('S<-C %s' % repr(msg))
if msg.id==0:
self.unsolicitedNotification(msg.value)
else:
name = msg.value.__class__.__name__
handler = getattr(self, 'handle_'+name, self.handleUnknown)
d = defer.maybeDeferred(handler,
msg.value,
msg.controls,
lambda response: self._cbHandle(response, msg.id))
d.addErrback(self._cbLDAPError, name)
d.addErrback(defer.logError)
d.addErrback(self._cbOtherError, name)
d.addCallback(self._cbHandle, msg.id)
class LDAPServer(BaseLDAPServer):
"""An LDAP server"""
boundUser = None
fail_LDAPBindRequest = pureldap.LDAPBindResponse
def handle_LDAPBindRequest(self, request, controls, reply):
if request.version != 3:
raise ldaperrors.LDAPProtocolError, \
'Version %u not supported' % request.version
self.checkControls(controls)
if request.dn == '':
# anonymous bind
self.boundUser=None
return pureldap.LDAPBindResponse(resultCode=0)
else:
dn = distinguishedname.DistinguishedName(request.dn)
root = interfaces.IConnectedLDAPEntry(self.factory)
d = root.lookup(dn)
def _noEntry(fail):
fail.trap(ldaperrors.LDAPNoSuchObject)
return None
d.addErrback(_noEntry)
def _gotEntry(entry, auth):
if entry is None:
raise ldaperrors.LDAPInvalidCredentials
d = entry.bind(auth)
def _cb(entry):
self.boundUser=entry
msg = pureldap.LDAPBindResponse(
resultCode=ldaperrors.Success.resultCode,
matchedDN=str(entry.dn))
return msg
d.addCallback(_cb)
return d
d.addCallback(_gotEntry, request.auth)
return d
def handle_LDAPUnbindRequest(self, request, controls, reply):
# explicitly do not check unsupported critical controls -- we
# have no way to return an error, anyway.
self.transport.loseConnection()
def getRootDSE(self, request, reply):
root = interfaces.IConnectedLDAPEntry(self.factory)
reply(pureldap.LDAPSearchResultEntry(
objectName='',
attributes=[ ('supportedLDAPVersion', ['3']),
('namingContexts', [str(root.dn)]),
('supportedExtension', [
pureldap.LDAPPasswordModifyRequest.oid,
]),
],
))
return pureldap.LDAPSearchResultDone(resultCode=ldaperrors.Success.resultCode)
def _cbSearchGotBase(self, base, dn, request, reply):
def _sendEntryToClient(entry):
reply(pureldap.LDAPSearchResultEntry(
objectName=str(entry.dn),
attributes=entry.items(),
))
d = base.search(filterObject=request.filter,
attributes=request.attributes,
scope=request.scope,
derefAliases=request.derefAliases,
sizeLimit=request.sizeLimit,
timeLimit=request.timeLimit,
typesOnly=request.typesOnly,
callback=_sendEntryToClient)
def _done(_):
return pureldap.LDAPSearchResultDone(resultCode=ldaperrors.Success.resultCode)
d.addCallback(_done)
return d
def _cbSearchLDAPError(self, reason):
reason.trap(ldaperrors.LDAPException)
return pureldap.LDAPSearchResultDone(resultCode=reason.value.resultCode)
def _cbSearchOtherError(self, reason):
return pureldap.LDAPSearchResultDone(resultCode=ldaperrors.other,
errorMessage=reason.getErrorMessage())
fail_LDAPSearchRequest = pureldap.LDAPSearchResultDone
def handle_LDAPSearchRequest(self, request, controls, reply):
self.checkControls(controls)
if (request.baseObject == ''
and request.scope == pureldap.LDAP_SCOPE_baseObject
and request.filter == pureldap.LDAPFilter_present('objectClass')):
return self.getRootDSE(request, reply)
dn = distinguishedname.DistinguishedName(request.baseObject)
root = interfaces.IConnectedLDAPEntry(self.factory)
d = root.lookup(dn)
d.addCallback(self._cbSearchGotBase, dn, request, reply)
d.addErrback(self._cbSearchLDAPError)
d.addErrback(defer.logError)
d.addErrback(self._cbSearchOtherError)
return d
fail_LDAPDelRequest = pureldap.LDAPDelResponse
def handle_LDAPDelRequest(self, request, controls, reply):
self.checkControls(controls)
dn = distinguishedname.DistinguishedName(request.value)
root = interfaces.IConnectedLDAPEntry(self.factory)
d = root.lookup(dn)
def _gotEntry(entry):
d = entry.delete()
return d
d.addCallback(_gotEntry)
def _report(entry):
return pureldap.LDAPDelResponse(resultCode=0)
d.addCallback(_report)
return d
fail_LDAPAddRequest = pureldap.LDAPAddResponse
def handle_LDAPAddRequest(self, request, controls, reply):
self.checkControls(controls)
attributes = {}
for name, vals in request.attributes:
attributes.setdefault(name.value, sets.Set())
attributes[name.value].update([x.value for x in vals])
dn = distinguishedname.DistinguishedName(request.entry)
rdn = str(dn.split()[0])
parent = dn.up()
root = interfaces.IConnectedLDAPEntry(self.factory)
d = root.lookup(parent)
def _gotEntry(parent):
d = parent.addChild(rdn, attributes)
return d
d.addCallback(_gotEntry)
def _report(entry):
return pureldap.LDAPAddResponse(resultCode=0)
d.addCallback(_report)
return d
fail_LDAPModifyDNRequest = pureldap.LDAPModifyDNResponse
def handle_LDAPModifyDNRequest(self, request, controls, reply):
self.checkControls(controls)
dn = distinguishedname.DistinguishedName(request.entry)
newrdn = distinguishedname.RelativeDistinguishedName(request.newrdn)
deleteoldrdn = bool(request.deleteoldrdn)
if not deleteoldrdn:
#TODO support this
raise ldaperrors.LDAPUnwillingToPerform("Cannot handle preserving old RDN yet.")
newSuperior = request.newSuperior
if newSuperior is None:
newSuperior = dn.up()
else:
newSuperior = distinguishedname.DistinguishedName(newSuperior)
newdn = distinguishedname.DistinguishedName(
listOfRDNs=(newrdn,)+newSuperior.split())
#TODO make this more atomic
root = interfaces.IConnectedLDAPEntry(self.factory)
d = root.lookup(dn)
def _gotEntry(entry):
d = entry.move(newdn)
return d
d.addCallback(_gotEntry)
def _report(entry):
return pureldap.LDAPModifyDNResponse(resultCode=0)
d.addCallback(_report)
return d
fail_LDAPModifyRequest = pureldap.LDAPModifyResponse
def handle_LDAPModifyRequest(self, request, controls, reply):
self.checkControls(controls)
root = interfaces.IConnectedLDAPEntry(self.factory)
mod = delta.ModifyOp.fromLDAP(request)
d = mod.patch(root)
def _patched(entry):
return entry.commit()
d.addCallback(_patched)
def _report(entry):
return pureldap.LDAPModifyResponse(resultCode=0)
d.addCallback(_report)
return d
fail_LDAPExtendedRequest = pureldap.LDAPExtendedResponse
def handle_LDAPExtendedRequest(self, request, controls, reply):
self.checkControls(controls)
for handler in [getattr(self, attr)
for attr in dir(self)
if attr.startswith('extendedRequest_')]:
if getattr(handler, 'oid', None) == request.requestName:
berdecoder = getattr(handler, 'berdecoder', None)
if berdecoder is None:
values = [request.requestValue]
else:
values = pureber.berDecodeMultiple(request.requestValue, berdecoder)
d = defer.maybeDeferred(handler, *values, **{'reply': reply})
def eb(fail, oid):
fail.trap(ldaperrors.LDAPException)
return pureldap.LDAPExtendedResponse(
resultCode=fail.value.resultCode,
errorMessage=fail.value.message,
responseName=oid,
)
d.addErrback(eb, request.requestName)
return d
raise ldaperrors.LDAPProtocolError('Unknown extended request: %s' % request.requestName)
def extendedRequest_LDAPPasswordModifyRequest(self, data, reply):
if not isinstance(data, pureber.BERSequence):
raise ldaperrors.LDAPProtocolError('Extended request PasswordModify expected a BERSequence.')
userIdentity = None
oldPasswd = None
newPasswd = None
for value in data:
if isinstance(value, pureldap.LDAPPasswordModifyRequest_userIdentity):
if userIdentity is not None:
raise ldaperrors.LDAPProtocolError(
'Extended request PasswordModify received userIdentity twice.')
userIdentity = value.value
elif isinstance(value, pureldap.LDAPPasswordModifyRequest_oldPasswd):
if oldPasswd is not None:
raise ldaperrors.LDAPProtocolError('Extended request PasswordModify received oldPasswd twice.')
oldPasswd = value.value
elif isinstance(value, pureldap.LDAPPasswordModifyRequest_newPasswd):
if newPasswd is not None:
raise ldaperrors.LDAPProtocolError('Extended request PasswordModify received newPasswd twice.')
newPasswd = value.value
else:
raise ldaperrors.LDAPProtocolError('Extended request PasswordModify received unexpected item.')
if self.boundUser is None:
raise ldaperrors.LDAPStrongAuthRequired()
if (userIdentity is not None
and userIdentity != self.boundUser.dn):
#TODO this hardcodes ACL
log.msg('User %(actor)s tried to change password of %(target)s' % {
'actor': str(self.boundUser.dn),
'target': str(userIdentity),
})
raise ldaperrors.LDAPInsufficientAccessRights()
if (oldPasswd is not None
or newPasswd is None):
raise ldaperrors.LDAPOperationsError('Password does not support this case.')
self.boundUser.setPassword(newPasswd)
return pureldap.LDAPExtendedResponse(resultCode=ldaperrors.Success.resultCode,
responseName=self.extendedRequest_LDAPPasswordModifyRequest.oid)
# TODO
if userIdentity is None:
userIdentity = str(self.boundUser.dn)
raise NotImplementedError('VALUE %r' % value)
extendedRequest_LDAPPasswordModifyRequest.oid = pureldap.LDAPPasswordModifyRequest.oid
extendedRequest_LDAPPasswordModifyRequest.berdecoder = (
pureber.BERDecoderContext(
inherit=pureldap.LDAPBERDecoderContext_LDAPPasswordModifyRequest(inherit=pureber.BERDecoderContext())))
if __name__ == '__main__':
"""
Demonstration LDAP server; reads LDIF from stdin and
serves that over LDAP on port 10389.
"""
from twisted.internet import reactor
import sys
log.startLogging(sys.stderr)
from twisted.python import components
from ldaptor import inmemory
class LDAPServerFactory(protocol.ServerFactory):
def __init__(self, root):
self.root = root
components.registerAdapter(lambda x: x.root,
LDAPServerFactory,
interfaces.IConnectedLDAPEntry)
def start(db):
factory = LDAPServerFactory(db)
factory.protocol = LDAPServer
reactor.listenTCP(10389, factory)
d = inmemory.fromLDIFFile(sys.stdin)
d.addCallback(start)
d.addErrback(log.err)
reactor.run()
ldaptor-0.0.43/ldaptor/protocols/ldap/autofill/ 0000755 0001750 0001750 00000000000 10403234306 017570 5 ustar jan jan ldaptor-0.0.43/ldaptor/protocols/ldap/autofill/__init__.py 0000644 0001750 0001750 00000000433 10104536552 021707 0 ustar jan jan """LDAP object field value suggestion and autoupdate mechanism."""
class AutofillException(Exception):
pass
class ObjectMissingObjectClassException(AutofillException):
"""
The LDAPEntry is missing an objectClass this autofiller needs to
operate.
"""
pass
ldaptor-0.0.43/ldaptor/protocols/ldap/autofill/posixAccount.py 0000644 0001750 0001750 00000002744 10344407651 022641 0 ustar jan jan from twisted.internet import defer
from ldaptor import numberalloc
from ldaptor.protocols.ldap import ldapsyntax, autofill
class Autofill_posix: #TODO baseclass
def __init__(self,
baseDN,
freeNumberGetter=numberalloc.getFreeNumber):
self.baseDN = baseDN
self.freeNumberGetter = freeNumberGetter
def _cb_gotNumbers(self, r, ldapObject):
uid, gid = r
ok, val = uid
if not ok:
val.trap()
ldapObject['uidNumber'] = [str(val)]
ok, val = gid
if not ok:
val.trap()
ldapObject['gidNumber'] = [str(val)]
def start(self, ldapObject):
assert 'objectClass' in ldapObject
if 'posixAccount' not in ldapObject['objectClass']:
raise autofill.ObjectMissingObjectClassException, ldapObject
assert 'loginShell' not in ldapObject
ldapObject['loginShell'] = ['/bin/sh']
baseObject = ldapsyntax.LDAPEntry(client=ldapObject.client,
dn=self.baseDN)
d1 = self.freeNumberGetter(baseObject, 'uidNumber', min=1000)
d2 = self.freeNumberGetter(baseObject, 'gidNumber', min=1000)
d = defer.DeferredList([d1, d2], fireOnOneErrback=1)
# silence the log
d1.addErrback(lambda x:None)
d2.addErrback(lambda x:None)
d.addCallback(self._cb_gotNumbers, ldapObject)
return d
def notify(self, ldapObject, attributeType):
pass
ldaptor-0.0.43/ldaptor/protocols/ldap/autofill/sambaAccount.py 0000644 0001750 0001750 00000003236 10104536552 022554 0 ustar jan jan from ldaptor.protocols.ldap.autofill import ObjectMissingObjectClassException
class Autofill_samba: #TODO baseclass
def start(self, ldapObject):
assert 'objectClass' in ldapObject
if 'sambaAccount' not in ldapObject['objectClass']:
raise ObjectMissingObjectClassException, ldapObject
assert 'acctFlags' not in ldapObject
ldapObject['acctFlags'] = ['[UX ]']
assert 'pwdLastSet' not in ldapObject
ldapObject['pwdLastSet'] = ['0']
assert 'logonTime' not in ldapObject
ldapObject['logonTime'] = ['0']
assert 'logoffTime' not in ldapObject
ldapObject['logoffTime'] = ['0']
assert 'pwdCanChange' not in ldapObject
ldapObject['pwdCanChange'] = ['0']
assert 'pwdMustChange' not in ldapObject
ldapObject['pwdMustChange'] = ['0']
def notify(self, ldapObject, attributeType):
# rid=2*uid+1000
if attributeType == 'uidNumber':
assert 'uidNumber' in ldapObject
assert len(ldapObject['uidNumber']) == 1
for uidNumber in ldapObject['uidNumber']:
uidNumber = int(uidNumber)
rid = uidNumber*2+1000
ldapObject['rid'] = [str(rid)]
return
# primaryGroupID=2*gid+1001
if attributeType == 'gidNumber':
assert 'gidNumber' in ldapObject
assert len(ldapObject['gidNumber']) == 1
for gidNumber in ldapObject['gidNumber']:
gidNumber = int(gidNumber)
primaryGroupID = gidNumber*2+1001
ldapObject['primaryGroupID'] = [str(primaryGroupID)]
return
ldaptor-0.0.43/ldaptor/protocols/ldap/autofill/sambaSamAccount.py 0000644 0001750 0001750 00000004745 10110431520 023205 0 ustar jan jan from ldaptor.protocols.ldap.autofill import ObjectMissingObjectClassException
class Autofill_samba: #TODO baseclass
def __init__(self, domainSID, fixedPrimaryGroupSID=None):
self.domainSID = domainSID
self.fixedPrimaryGroupSID = fixedPrimaryGroupSID
def start(self, ldapObject):
assert 'objectClass' in ldapObject
if 'sambaSamAccount' not in ldapObject['objectClass']:
raise ObjectMissingObjectClassException, ldapObject
assert 'sambaAcctFlags' not in ldapObject
ldapObject['sambaAcctFlags'] = ['[UX ]']
assert 'sambaPwdLastSet' not in ldapObject
ldapObject['sambaPwdLastSet'] = ['0']
assert 'sambaLogonTime' not in ldapObject
ldapObject['sambaLogonTime'] = ['0']
assert 'sambaLogoffTime' not in ldapObject
ldapObject['sambaLogoffTime'] = ['0']
assert 'sambaPwdCanChange' not in ldapObject
ldapObject['sambaPwdCanChange'] = ['0']
assert 'sambaPwdMustChange' not in ldapObject
ldapObject['sambaPwdMustChange'] = ['0']
if self.fixedPrimaryGroupSID is not None:
assert 'sambaPrimaryGroupSID' not in ldapObject
ldapObject['sambaPrimaryGroupSID'] = ['%s-%d' % (
self.domainSID, self.fixedPrimaryGroupSID)]
# Handle attributeTypes that were added before we got
# started. We know we don't defer in notify, so we can do a
# simple loop here.
for attributeType in ldapObject.keys():
self.notify(ldapObject, attributeType)
def notify(self, ldapObject, attributeType):
# sambaSID=2*uidNumber+1000
if attributeType == 'uidNumber':
assert 'uidNumber' in ldapObject
assert len(ldapObject['uidNumber']) == 1
for uidNumber in ldapObject['uidNumber']:
uidNumber = int(uidNumber)
sid = '%s-%d' % (self.domainSID, uidNumber*2+1000)
ldapObject['sambaSID'] = [str(sid)]
return
# sambaPrimaryGroupSID = fixed or 2*gidNumber+1001
if (self.fixedPrimaryGroupSID is None
and attributeType == 'gidNumber'):
assert 'gidNumber' in ldapObject
assert len(ldapObject['gidNumber']) == 1
for gidNumber in ldapObject['gidNumber']:
gidNumber = int(gidNumber)
sid = '%s-%d' % (self.domainSID, gidNumber*2+1001)
ldapObject['sambaPrimaryGroupSID'] = [str(sid)]
return
ldaptor-0.0.43/ldaptor/protocols/ldap/ldifprotocol.py 0000644 0001750 0001750 00000010023 10052211034 021010 0 ustar jan jan import base64
from twisted.protocols import basic
from twisted.internet import protocol
from ldaptor import entry
class LDIFParseError(Exception):
"""Error parsing LDIF."""
def __str__(self):
s = self.__doc__
if self[:]:
s = ': '.join([s]+map(str, self[:]))
return s+'.'
class LDIFLineWithoutSemicolonError(LDIFParseError):
"""LDIF line without semicolon seen"""
pass
class LDIFEntryStartsWithNonDNError(LDIFParseError):
"""LDIF entry starts with a non-DN line"""
pass
class LDIFEntryStartsWithSpaceError(LDIFParseError):
"""Invalid LDIF value format"""
pass
class LDIFVersionNotANumberError(LDIFParseError):
"""Non-numeric LDIF version number"""
pass
class LDIFUnsupportedVersionError(LDIFParseError):
"""LDIF version not supported"""
pass
class LDIFTruncatedError(LDIFParseError):
"""LDIF appears to be truncated"""
pass
HEADER = 'HEADER'
WAIT_FOR_DN = 'WAIT_FOR_DN'
IN_ENTRY = 'IN_ENTRY'
class LDIF(object, basic.LineReceiver):
delimiter='\n'
mode = HEADER
dn = None
data = None
lastLine = None
version = None
def logicalLineReceived(self, line):
if line.startswith('#'):
# comments are allowed everywhere
return
getattr(self, 'state_' + self.mode)(line)
def lineReceived(self, line):
if line.startswith(' '):
if self.lastLine is None:
raise LDIFEntryStartsWithSpaceError
self.lastLine = self.lastLine + line[1:]
else:
if self.lastLine is not None:
self.logicalLineReceived(self.lastLine)
self.lastLine = line
if line == '':
self.logicalLineReceived(line)
self.lastLine = None
def parseValue(self, val):
if val.startswith(':'):
return base64.decodestring(val[1:].lstrip(' '))
elif val.startswith('<'):
raise NotImplementedError
else:
return val.lstrip(' ')
def _parseLine(self, line):
try:
key, val = line.split(':', 1)
except ValueError:
# unpack list of wrong size
# -> invalid input data
raise LDIFLineWithoutSemicolonError, line
val = self.parseValue(val)
return key, val
def state_HEADER(self, line):
key, val = self._parseLine(line)
self.mode = WAIT_FOR_DN
if key != 'version':
self.logicalLineReceived(line)
else:
try:
version = int(val)
except ValueError:
raise LDIFVersionNotANumberError, val
self.version = version
if version > 1:
raise LDIFUnsupportedVersionError, version
def state_WAIT_FOR_DN(self, line):
assert self.dn is None, 'self.dn must not be set when waiting for DN'
assert self.data is None, 'self.data must not be set when waiting for DN'
if line == '':
# too many empty lines, but be tolerant
return
key, val = self._parseLine(line)
if key.upper() != 'DN':
raise LDIFEntryStartsWithNonDNError, line
self.dn = val
self.data = {}
self.mode = IN_ENTRY
def state_IN_ENTRY(self, line):
assert self.dn is not None, 'self.dn must be set when in entry'
assert self.data is not None, 'self.data must be set when in entry'
if line == '':
# end of entry
self.mode = WAIT_FOR_DN
o = entry.BaseLDAPEntry(dn=self.dn,
attributes=self.data)
self.dn = None
self.data = None
self.gotEntry(o)
return
key, val = self._parseLine(line)
if not key in self.data:
self.data[key] = []
self.data[key].append(val)
def gotEntry(self, obj):
pass
def connectionLost(self, reason=protocol.connectionDone):
if self.mode != WAIT_FOR_DN:
raise LDIFTruncatedError, reason
ldaptor-0.0.43/ldaptor/protocols/ldap/fetchschema.py 0000644 0001750 0001750 00000003753 10344407651 020616 0 ustar jan jan from ldaptor.protocols.ldap import ldaperrors, ldapsyntax
from ldaptor.protocols import pureldap
from ldaptor import schema
def _fetchCb(subschemaSubentry, client):
o=ldapsyntax.LDAPEntry(client=client,
dn=subschemaSubentry)
d=o.search(scope=pureldap.LDAP_SCOPE_baseObject,
sizeLimit=1,
attributes=["attributeTypes", "objectClasses"])
def handleSearchResults(l):
if len(l)==0:
raise ldaperrors.LDAPOther, "No such DN"
elif len(l)==1:
o=l[0]
attributeTypes = []
objectClasses = []
for text in o.get("attributeTypes", []):
attributeTypes.append(schema.AttributeTypeDescription(str(text)))
for text in o.get("objectClasses", []):
objectClasses.append(schema.ObjectClassDescription(str(text)))
assert attributeTypes, "LDAP server doesn't give attributeTypes for subschemaSubentry dn=%s"%o.dn
return (attributeTypes, objectClasses)
else:
raise ldaperrors.LDAPOther, "DN matched multiple entries"
d.addCallback(handleSearchResults)
return d
def fetch(client, baseObject):
o=ldapsyntax.LDAPEntry(client=client,
dn=baseObject)
d=o.search(scope=pureldap.LDAP_SCOPE_baseObject,
sizeLimit=1,
attributes=["subschemaSubentry"])
def handleSearchResults(l):
if len(l)==0:
raise ldaperrors.LDAPOther, "No such DN"
elif len(l)==1:
o=l[0]
assert "subschemaSubentry" in o, "No subschemaSubentry. TODO"
subSchemas = o["subschemaSubentry"]
assert len(subSchemas)==1, "More than one subschemaSubentry is not support yet. TODO"
for s in subSchemas:
return s
else:
raise ldaperrors.LDAPOther, "DN matched multiple entries"
d.addCallback(handleSearchResults)
d.addCallback(_fetchCb, client)
return d
ldaptor-0.0.43/ldaptor/protocols/ldap/distinguishedname.py 0000644 0001750 0001750 00000021101 10344535643 022036 0 ustar jan jan # 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' #'
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
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
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)
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
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, '+')])
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
def count(self):
return len(self.attributeTypesAndValues)
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, ',')])
def split(self):
return self.listOfRDNs
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())
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
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
ldaptor-0.0.43/ldaptor/protocols/ldap/svcbindproxy.py 0000644 0001750 0001750 00000014655 10344407651 021101 0 ustar jan jan from ldaptor.protocols.ldap import proxy
from ldaptor.protocols.ldap import ldapsyntax, ldaperrors
from ldaptor.protocols import pureldap
import datetime
class ServiceBindingProxy(proxy.Proxy):
"""
An LDAP proxy that handles non-anonymous bind requests specially.
BindRequests are intercepted and authentication is attempted
against each configured service. This authentication is performed
against a separate LDAP entry, found by searching for entries with
- objectClass: serviceSecurityObject
- owner: the DN of the original bind attempt
- cn: the service name.
starting at the identity-base as configured in the config file.
Finally, if the authentication does not succeed against any of the
configured services, the proxy can fallback to passing the bind
request to the real server.
"""
services = []
fallback = False
def __init__(self,
services=None,
fallback=None,
*a,
**kw):
"""
Initialize the object.
@param services: List of service names to try to bind against.
@param fallback: If none of the attempts to authenticate
against a specific service succeeded, whether to fall back to
the normal LDAP bind mechanism.
"""
proxy.Proxy.__init__(self, *a, **kw)
if services is not None:
self.services = list(services)
if fallback is not None:
self.fallback = fallback
def _startSearch(self, request, controls, reply):
services = list(self.services)
baseDN = self.config.getIdentityBaseDN()
e = ldapsyntax.LDAPEntryWithClient(client=self.client,
dn=baseDN)
d = self._tryService(services, e, request, controls, reply)
d.addCallback(self._maybeFallback, request, controls, reply)
return d
def _maybeFallback(self, entry, request, controls, reply):
if entry is not None:
msg = pureldap.LDAPBindResponse(
resultCode=ldaperrors.Success.resultCode,
matchedDN=request.dn)
return msg
elif self.fallback:
self.handleUnknown(request, controls, reply)
else:
msg = pureldap.LDAPBindResponse(
resultCode=ldaperrors.LDAPInvalidCredentials.resultCode)
return msg
def timestamp(self):
now = datetime.datetime.now()
return now.strftime('%Y%m%d%H%M%SZ')
def _tryService(self, services, baseEntry, request, controls, reply):
try:
serviceName = services.pop(0)
except IndexError:
return None
timestamp = self.timestamp()
d = baseEntry.search(filterObject=pureldap.LDAPFilter_and([
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('objectClass'),
assertionValue=pureldap.LDAPAssertionValue('serviceSecurityObject')),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('owner'),
assertionValue=pureldap.LDAPAssertionValue(request.dn)),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('cn'),
assertionValue=pureldap.LDAPAssertionValue(serviceName)),
pureldap.LDAPFilter_or([
# no time
pureldap.LDAPFilter_not(pureldap.LDAPFilter_present('validFrom')),
# or already valid
pureldap.LDAPFilter_lessOrEqual(attributeDesc=pureldap.LDAPAttributeDescription('validFrom'),
assertionValue=pureldap.LDAPAssertionValue(timestamp)),
]),
pureldap.LDAPFilter_or([
# no time
pureldap.LDAPFilter_not(pureldap.LDAPFilter_present('validUntil')),
# or still valid
pureldap.LDAPFilter_greaterOrEqual(attributeDesc=pureldap.LDAPAttributeDescription('validUntil'),
assertionValue=pureldap.LDAPAssertionValue(timestamp)),
]),
]),
attributes=('1.1',))
def _gotEntries(entries):
if not entries:
return None
assert len(entries)==1 #TODO
e = entries[0]
d = e.bind(request.auth)
return d
d.addCallback(_gotEntries)
d.addCallbacks(
callback=self._loopIfNone,
callbackArgs=(services, baseEntry,
request, controls, reply),
errback=self._loopIfBindError,
errbackArgs=(services, baseEntry,
request, controls, reply))
return d
def _loopIfNone(self, r, *a, **kw):
if r is None:
d = self._tryService(*a, **kw)
return d
else:
return r
def _loopIfBindError(self, fail, *a, **kw):
fail.trap(ldaperrors.LDAPInvalidCredentials)
d = self._tryService(*a, **kw)
return d
fail_LDAPBindRequest = pureldap.LDAPBindResponse
def handle_LDAPBindRequest(self, request, controls, reply):
if request.version != 3:
raise ldaperrors.LDAPProtocolError, \
'Version %u not supported' % request.version
self.checkControls(controls)
if request.dn == '':
# anonymous bind
return self.handleUnknown(request, controls, reply)
else:
d = self._whenConnected(self._startSearch,
request, controls, reply)
return d
if __name__ == '__main__':
"""
Demonstration LDAP proxy; passes all requests to localhost:389.
"""
from twisted.internet import reactor, protocol
from twisted.python import log
import sys
log.startLogging(sys.stderr)
from ldaptor import config
factory = protocol.ServerFactory()
cfg = config.LDAPConfig(serviceLocationOverrides={
'': ('localhost', 389),
})
factory.protocol = lambda : ServiceBindingProxy(config=cfg,
services=[
'svc1',
'svc2',
'svc3',
],
fallback=True,
)
reactor.listenTCP(10389, factory)
reactor.run()
ldaptor-0.0.43/ldaptor/protocols/ldap/ldapconnector.py 0000644 0001750 0001750 00000006465 10344535643 021205 0 ustar jan jan from twisted.internet import protocol, defer
from ldaptor.protocols.ldap import distinguishedname
try:
from twisted.internet.utils import SRVConnector
except ImportError:
from twisted.names.srvconnect import SRVConnector
class LDAPConnector(SRVConnector):
def __init__(self, reactor, dn, factory,
overrides=None):
if not isinstance(dn, distinguishedname.DistinguishedName):
dn = distinguishedname.DistinguishedName(stringValue=dn)
if overrides is None:
overrides={}
self.override = self._findOverRide(dn, overrides)
domain = dn.getDomainName()
SRVConnector.__init__(self, reactor,
'ldap', domain, factory)
def __getstate__(self):
r={}
r.update(self.__dict__)
r['connector'] = None
return r
def _findOverRide(self, dn, overrides):
while True:
if overrides.has_key(dn):
return overrides[dn]
if dn == '':
break
dn = dn.up()
return None
def _isQueryNeeded(self):
"""Is there both need to do an SRV query."""
if self.override is None:
return True
assert not callable(self.override)
overriddenHost, overriddenPort = self.override
if overriddenHost is None:
return True
if overriddenPort is not None:
return False
return True
def connect(self):
if callable(self.override):
self.override(self.factory)
elif not self._isQueryNeeded():
self.factory.doStart()
self.factory.startedConnecting(self)
self._reallyConnect()
else:
SRVConnector.connect(self)
def pickServer(self):
if self.override is None:
overriddenHost, overriddenPort = None, None
else:
overriddenHost, overriddenPort = self.override
if (overriddenHost is not None
and (overriddenPort is not None
or self.domain is None)):
host = overriddenHost
port = overriddenPort
else:
host, port = SRVConnector.pickServer(self)
if overriddenHost is not None:
host = overriddenHost
if overriddenPort is not None:
port = overriddenPort
try:
port = int(port)
except ValueError:
pass
assert host is not None
if port is None:
port = 389
return host, port
class LDAPClientCreator(protocol.ClientCreator):
def connect(self, dn, overrides=None):
"""Connect to remote host, return Deferred of resulting protocol instance."""
d = defer.Deferred()
f = protocol._InstanceFactory(self.reactor, self.protocolClass(*self.args, **self.kwargs), d)
c = LDAPConnector(self.reactor, dn, f, overrides=overrides)
c.connect()
return d
def connectAnonymously(self, dn, overrides=None):
"""Connect to remote host and bind anonymously, return Deferred of resulting protocol instance."""
d = self.connect(dn, overrides=overrides)
def _bind(proto):
d=proto.bind()
d.addCallback(lambda _: proto)
return d
d.addCallback(_bind)
return d
ldaptor-0.0.43/ldaptor/generate_password.py 0000644 0001750 0001750 00000003461 10344535643 017113 0 ustar jan jan from twisted.internet import process, protocol, defer
from twisted.python import failure
class PwgenException(Exception):
pass
class ReadPassword(protocol.ProcessProtocol):
def __init__(self, deferred, count=1):
self.deferred=deferred
self.count=count
self.stdout=''
self.stderr=''
def outReceived(self, data):
self.stdout=self.stdout+data
def errReceived(self, data):
self.stderr=self.stderr+data
def processEnded(self, reason):
if self.stderr:
self.deferred.errback(failure.Failure(
PwgenException(reason, self.stderr)))
elif self.stdout:
lines=[x for x in self.stdout.split('\n') if x]
if len(lines)!=self.count:
self.deferred.errback(failure.Failure(
PwgenException(reason, 'Wrong number of lines received.')))
self.deferred.callback(lines)
else:
self.deferred.errback(failure.Failure(PwgenException(reason, '')))
def generate(reactor, n=1):
assert n>0
d=defer.Deferred()
proto=ReadPassword(d, n)
process.Process(reactor, 'pwgen', ('pwgen', '-cn1', '-N', '%d'%n), {}, None, proto)
return d
if __name__=='__main__':
from twisted.internet import reactor
import sys
def say(passwords):
for p in passwords:
sys.stdout.write('%s\n' % p)
return passwords
def err(fail):
fail.trap(PwgenException)
sys.stderr.write('pwgen: %s\n' % fail.getErrorMessage())
# Could get more passwords in one fork, but this stresses it more
# on purpose.
l=[]
for i in range(5):
d=generate(reactor, 5)
d.addCallbacks(say, err)
l.append(d)
dl=defer.DeferredList(l)
dl.addBoth(lambda dummy: reactor.stop())
reactor.run()
ldaptor-0.0.43/ldaptor/entry.py 0000644 0001750 0001750 00000013734 10347777536 014560 0 ustar jan jan import sets, random, sha, base64
from zope.interface import implements
from twisted.internet import defer
from twisted.python.util import InsensitiveDict
from ldaptor import interfaces, attributeset, delta
from ldaptor.protocols.ldap import distinguishedname, ldif, ldaperrors
def sshaDigest(passphrase, salt=None):
if salt is None:
salt = ''
for i in range(8):
salt += chr(random.randint(0, 255))
s = sha.sha()
s.update(passphrase)
s.update(salt)
encoded = base64.encodestring(s.digest()+salt).rstrip()
crypt = '{SSHA}' + encoded
return crypt
class BaseLDAPEntry(object):
implements(interfaces.ILDAPEntry)
dn = None
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):
return self._attributes[key]
def get(self, key, default=None):
return self._attributes.get(key, default)
def has_key(self, key):
return key in self._attributes
def __contains__(self, key):
return self.has_key(key)
def keys(self):
return self._attributes.keys()
def items(self):
return self._attributes.items()
def __str__(self):
a=[]
objectClasses = list(self.get('objectClass', []))
objectClasses.sort()
a.append(('objectClass', objectClasses))
l=list(self.items())
l.sort()
for key, values in l:
if key.lower() != 'objectclass':
vs = list(values)
vs.sort()
a.append((key, vs))
return ldif.asLDIF(self.dn, a)
def __eq__(self, other):
if not isinstance(other, BaseLDAPEntry):
return 0
if self.dn != other.dn:
return 0
my=self.keys()
my.sort()
its=other.keys()
its.sort()
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 __nonzero__(self):
return True
def __repr__(self):
x={}
for key in self.keys():
x[key]=self[key]
keys=self.keys()
keys.sort()
a=[]
for key in keys:
a.append('%s: %s' % (repr(key), repr(list(self[key]))))
attributes=', '.join(a)
return '%s(%s, {%s})' % (
self.__class__.__name__,
repr(str(self.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 = sets.Set(self.keys())
otherKeys = sets.Set(other.keys())
addedKeys = list(otherKeys - myKeys)
addedKeys.sort() # for reproducability only
for added in addedKeys:
r.append(delta.Add(added, other[added]))
deletedKeys = list(myKeys - otherKeys)
deletedKeys.sort() # for reproducability only
for deleted in deletedKeys:
r.append(delta.Delete(deleted, self[deleted]))
sharedKeys = list(myKeys & otherKeys)
sharedKeys.sort() # for reproducability only
for shared in sharedKeys:
addedValues = list(other[shared] - self[shared])
if addedValues:
addedValues.sort() # for reproducability only
r.append(delta.Add(shared, addedValues))
deletedValues = list(self[shared] - other[shared])
if deletedValues:
deletedValues.sort() # 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):
for digest in self.get('userPassword', ()):
if digest.startswith('{SSHA}'):
raw = base64.decodestring(digest[len('{SSHA}'):])
salt = raw[20:]
got = sshaDigest(password, salt)
if got == digest:
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):
return hash(self.dn)
class EditableLDAPEntry(BaseLDAPEntry):
implements(interfaces.IEditableLDAPEntry)
def __setitem__(self, key, value):
new=self.buildAttributeSet(key, value)
self._attributes[key] = new
def __delitem__(self, key):
del self._attributes[key]
def undo(self):
raise NotImplementedError
def commit(self):
raise NotImplementedError
def move(self, newDN):
raise NotImplementedError
def delete(self):
raise NotImplementedError
def setPassword(self, newPasswd, salt=None):
crypt = sshaDigest(newPasswd, salt)
self['userPassword'] = [crypt]
ldaptor-0.0.43/ldaptor/md4.py 0000644 0001750 0001750 00000021301 10344535643 014054 0 ustar jan jan """Pure-Python MD4 digest algorithm implementation."""
# http://www.geocities.com/rozmanov/python/
"""
From: "Dmitry Rozmanov"
To: "Tommi Virtanen"
Subject: Re: About your md4.py
Hi.
Year, I am thinking of this, but could not find time for this. Thanks for
the link.
But why?
Consider it as a GPL for now if it is important.
Regards.
---Dmitry.
----- Original Message -----
From: "Tommi Virtanen"
To: "Dmitry Rozmanov"
Sent: Tuesday, August 27, 2002 9:17 PM
Subject: About your md4.py
> Hi. Could you consider adding a license
> in your U32.py and md4.py files? Here's
> a quick reference:
>
> http://zooko.com/license_quick_ref.html
>
> --
> :(){ :|:&};:
"""
"""
From: "Dmitry Rozmanov"
To: "Tommi Virtanen"
Subject: Re: About your md4.py
Ok. Let it be LGPL. Use libs, soon I will modify them and post to the site.
Regards.
---Dmitry.
----- Original Message -----
From: "Tommi Virtanen"
To: "Dmitry Rozmanov"
Sent: Wednesday, August 28, 2002 9:21 AM
Subject: Re: About your md4.py
> On Wed, Aug 28, 2002 at 02:56:25AM +0400, Dmitry Rozmanov wrote:
> > Year, I am thinking of this, but could not find time for
> > this. Thanks for the link.
> >
> > But why?
> >
> > Consider it as a GPL for now if it is important.
>
> Please include that information in the files themselves;
> it would really help. Otherwise, all I have is this
> email to point to.
>
> Oh, and please reconsider the actual license. For example,
> I have an LGPL'ed library I need md4 in. If you choose GPL,
> my library couldn't use your md4.py.
>
> --
> :(){ :|:&};:
"""
# MD4 validation data
md4_test= [
('', 0x31d6cfe0d16ae931b73c59d7e0c089c0L),
("a", 0xbde52cb31de33e46245e05fbdbd6fb24L),
("abc", 0xa448017aaf21d8525fc10ae87aa6729dL),
("message digest", 0xd9130a8164549fe818874806e1c7014bL),
("abcdefghijklmnopqrstuvwxyz", 0xd79e1c308aa5bbcdeea8ed63df412da9L),
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
0x043f8582f241db351ce627e153e7f0e4L),
("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
0xe33b4ddc9c38f2199c3e7b164fcc0536L),
]
from U32 import U32
class MD4Type:
A = None
B = None
C = None
D = None
count, len1, len2 = None, None, None
buf = []
def __init__(self, data=""):
self.A = U32(0x67452301L)
self.B = U32(0xefcdab89L)
self.C = U32(0x98badcfeL)
self.D = U32(0x10325476L)
self.count, self.len1, self.len2 = U32(0L), U32(0L), U32(0L)
self.buf = [0x00] * 64
self.update(data)
def copy(self):
dest = new()
dest.len1 = self.len1
dest.len2 = self.len2
dest.A = self.A
dest.B = self.B
dest.C = self.C
dest.D = self.D
dest.count = self.count
for i in range(self.count):
dest.buf[i] = self.buf[i]
return dest
def update(self, str):
buf = []
for i in str: buf.append(ord(i))
ilen = U32(len(buf))
#print (ilen)
if (long(self.len1 + (ilen << 3)) < long(self.len1)):
self.len2 = self.len2 + U32(1)
self.len1 = self.len1 + (ilen << 3)
self.len2 = self.len2 + (ilen >> 29)
# print int(self.len1), int(self.len2)
#print (self.len1), (self.len2)
L = U32(0)
bufpos = 0
while (long(ilen) > 0):
if (64 - long(self.count)) < long(ilen): L = U32(64 - long(self.count))
else: L = ilen
for i in range(int(L)): self.buf[i + int(self.count)] = buf[i + bufpos]
self.count = self.count + L
ilen = ilen - L
bufpos = bufpos + int(L)
#print self.count, L, ilen
if (long(self.count) == 64L):
self.count = U32(0L)
X = []
i = 0
for j in range(16):
X.append(U32(self.buf[i]) + (U32(self.buf[i+1]) << 8) + \
(U32(self.buf[i+2]) << 16) + (U32(self.buf[i+3]) << 24))
i = i + 4
A = self.A
B = self.B
C = self.C
D = self.D
A = f1(A,B,C,D, 0, 3, X)
D = f1(D,A,B,C, 1, 7, X)
C = f1(C,D,A,B, 2,11, X)
B = f1(B,C,D,A, 3,19, X)
A = f1(A,B,C,D, 4, 3, X)
D = f1(D,A,B,C, 5, 7, X)
C = f1(C,D,A,B, 6,11, X)
B = f1(B,C,D,A, 7,19, X)
A = f1(A,B,C,D, 8, 3, X)
D = f1(D,A,B,C, 9, 7, X)
C = f1(C,D,A,B,10,11, X)
B = f1(B,C,D,A,11,19, X)
A = f1(A,B,C,D,12, 3, X)
D = f1(D,A,B,C,13, 7, X)
C = f1(C,D,A,B,14,11, X)
B = f1(B,C,D,A,15,19, X)
A = f2(A,B,C,D, 0, 3, X)
D = f2(D,A,B,C, 4, 5, X)
C = f2(C,D,A,B, 8, 9, X)
B = f2(B,C,D,A,12,13, X)
A = f2(A,B,C,D, 1, 3, X)
D = f2(D,A,B,C, 5, 5, X)
C = f2(C,D,A,B, 9, 9, X)
B = f2(B,C,D,A,13,13, X)
A = f2(A,B,C,D, 2, 3, X)
D = f2(D,A,B,C, 6, 5, X)
C = f2(C,D,A,B,10, 9, X)
B = f2(B,C,D,A,14,13, X)
A = f2(A,B,C,D, 3, 3, X)
D = f2(D,A,B,C, 7, 5, X)
C = f2(C,D,A,B,11, 9, X)
B = f2(B,C,D,A,15,13, X)
A = f3(A,B,C,D, 0, 3, X)
D = f3(D,A,B,C, 8, 9, X)
C = f3(C,D,A,B, 4,11, X)
B = f3(B,C,D,A,12,15, X)
A = f3(A,B,C,D, 2, 3, X)
D = f3(D,A,B,C,10, 9, X)
C = f3(C,D,A,B, 6,11, X)
B = f3(B,C,D,A,14,15, X)
A = f3(A,B,C,D, 1, 3, X)
D = f3(D,A,B,C, 9, 9, X)
C = f3(C,D,A,B, 5,11, X)
B = f3(B,C,D,A,13,15, X)
A = f3(A,B,C,D, 3, 3, X)
D = f3(D,A,B,C,11, 9, X)
C = f3(C,D,A,B, 7,11, X)
B = f3(B,C,D,A,15,15, X)
self.A = self.A + A
self.B = self.B + B
self.C = self.C + C
self.D = self.D + D
#print self
def digest(self):
res = [0x00] * 16
s = [0x00] * 8
padding = [0x00] * 64
padding[0] = 0x80
padlen, oldlen1, oldlen2 = U32(0), U32(0), U32(0)
temp = self.copy()
oldlen1 = temp.len1
oldlen2 = temp.len2
if (56 <= long(self.count)): padlen = U32(56 - long(self.count) + 64)
else: padlen = U32(56 - long(self.count))
#print int(padlen)
temp.update(int_array2str(padding[:int(padlen)]))
#print temp
s[0]= (oldlen1) & U32(0xFF)
s[1]=((oldlen1) >> 8) & U32(0xFF)
s[2]=((oldlen1) >> 16) & U32(0xFF)
s[3]=((oldlen1) >> 24) & U32(0xFF)
s[4]= (oldlen2) & U32(0xFF)
s[5]=((oldlen2) >> 8) & U32(0xFF)
s[6]=((oldlen2) >> 16) & U32(0xFF)
s[7]=((oldlen2) >> 24) & U32(0xFF)
temp.update(int_array2str(s))
#print temp
res[ 0]= temp.A & U32(0xFF)
res[ 1]=(temp.A >> 8) & U32(0xFF)
res[ 2]=(temp.A >> 16) & U32(0xFF)
res[ 3]=(temp.A >> 24) & U32(0xFF)
res[ 4]= temp.B & U32(0xFF)
res[ 5]=(temp.B >> 8) & U32(0xFF)
res[ 6]=(temp.B >> 16) & U32(0xFF)
res[ 7]=(temp.B >> 24) & U32(0xFF)
res[ 8]= temp.C & U32(0xFF)
res[ 9]=(temp.C >> 8) & U32(0xFF)
res[10]=(temp.C >> 16) & U32(0xFF)
res[11]=(temp.C >> 24) & U32(0xFF)
res[12]= temp.D & U32(0xFF)
res[13]=(temp.D >> 8) & U32(0xFF)
res[14]=(temp.D >> 16) & U32(0xFF)
res[15]=(temp.D >> 24) & U32(0xFF)
return int_array2str(res)
def hexdigest(self):
d=self.digest()
return ''.join(map(lambda c: '%02x'%ord(c), d))
def F(x, y, z): return (((x) & (y)) | ((~x) & (z)))
def G(x, y, z): return (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
def H(x, y, z): return ((x) ^ (y) ^ (z))
def ROL(x, n): return (((x) << n) | ((x) >> (32-n)))
def f1(a, b, c, d, k, s, X): return ROL(a + F(b, c, d) + X[k], s)
def f2(a, b, c, d, k, s, X): return ROL(a + G(b, c, d) + X[k] + U32(0x5a827999L), s)
def f3(a, b, c, d, k, s, X): return ROL(a + H(b, c, d) + X[k] + U32(0x6ed9eba1L), s)
def int_array2str(array):
str = ''
for i in array:
str = str + chr(i)
return str
def md4(data=''):
return MD4Type(data)
def new(data=''):
return MD4Type(data)
ldaptor-0.0.43/ldaptor/numberalloc.py 0000644 0001750 0001750 00000003101 10344535643 015671 0 ustar jan jan """Find an available uidNumber/gidNumber/other similar number."""
from ldaptor.protocols import pureldap
class freeNumberGuesser:
def __init__(self, makeAGuess, min=None, max=None):
self.makeAGuess=makeAGuess
self.min=min
if self.min is None:
self.min=0
self.max=max
def startGuessing(self):
d=self.makeAGuess(self.min)
d.addCallback(self._nextGuess, self.min)
return d
def _nextGuess(self, found, lastGuess):
if found:
self.min=lastGuess
else:
self.max=lastGuess
if self.max==self.min \
or self.max==self.min+1:
return self.max
max=self.max
if max is None:
max=self.min+1000
guess=(max+self.min)/2
d=self.makeAGuess(guess)
d.addCallback(self._nextGuess, guess)
return d
class ldapGuesser:
def __init__(self, ldapObject, numberType):
self.numberType=numberType
self.ldapObject=ldapObject
def guess(self, num):
d=self.ldapObject.search(
filterObject=pureldap.LDAPFilter_equalityMatch(
attributeDesc=pureldap.LDAPAttributeDescription(value=self.numberType),
assertionValue=pureldap.LDAPAssertionValue(value=str(num))),
sizeLimit=1)
d.addCallback(lambda results: len(results))
return d
def getFreeNumber(ldapObject, numberType, min=None, max=None):
g=freeNumberGuesser(ldapGuesser(ldapObject, numberType).guess,
min=min, max=max)
return g.startGuessing()
ldaptor-0.0.43/ldaptor/schema.py 0000644 0001750 0001750 00000047724 10344535643 014651 0 ustar jan jan def extractWord(text):
if not text:
return None
l = text.split(None, 1)
word = l[0]
try:
text = l[1]
except IndexError:
text = ''
return word, text
def peekWord(text):
if not text:
return None
return text.split(None, 1)[0]
class ASN1ParserThingie:
def _to_list(self, text):
"""Split text into $-separated list."""
r=[]
for x in text.split("$"):
x = x.strip()
assert x
r.append(x)
return tuple(r)
def _strings_to_list(self, text):
"""Split ''-quoted strings into list."""
r=[]
while text:
text = text.lstrip()
if not text:
break
assert text[0]=="'", "Text %s must start with a single quote."%repr(text)
text=text[1:]
end=text.index("'")
r.append(text[:end])
text=text[end+1:]
return tuple(r)
def _str_list(self, l):
s = ' '.join([self._str(x) for x in l])
if len(l) > 1:
s = '( %s )' % s
return s
def _list(self, l):
s = ' $ '.join([x for x in l])
if len(l) > 1:
s = '( %s )' % s
return s
def _str(self, s):
return "'%s'" % s
class ObjectClassDescription(ASN1ParserThingie):
"""
ASN Syntax::
d = "0" / "1" / "2" / "3" / "4" /
"5" / "6" / "7" / "8" / "9"
numericstring = 1*d
numericoid = numericstring *( "." numericstring )
space = 1*" "
whsp = [ space ]
descr = keystring
qdescr = whsp "'" descr "'" whsp
qdescrlist = [ qdescr *( qdescr ) ]
; object descriptors used as schema element names
qdescrs = qdescr / ( whsp "(" qdescrlist ")" whsp )
dstring = 1*utf8
qdstring = whsp "'" dstring "'" whsp
descr = keystring
oid = descr / numericoid
woid = whsp oid whsp
; set of oids of either form
oids = woid / ( "(" oidlist ")" )
ObjectClassDescription = "(" whsp
numericoid whsp ; ObjectClass identifier
[ "NAME" qdescrs ]
[ "DESC" qdstring ]
[ "OBSOLETE" whsp ]
[ "SUP" oids ] ; Superior ObjectClasses
[ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ]
; default structural
[ "MUST" oids ] ; AttributeTypes
[ "MAY" oids ] ; AttributeTypes
whsp ")"
"""
def __init__(self, text):
self.oid=None
self.name=None
self.desc=None
self.obsolete=0
self.sup=[]
self.type=None
self.must=[]
self.may=[]
if text is not None:
self._parse(text)
def _parse(self, text):
assert text[0]=='(', "Text %s must be in parentheses."%repr(text)
assert text[-1]==')', "Text %s must be in parentheses."%repr(text)
text=text[1:-1]
text = text.lstrip()
# oid
self.oid, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "NAME":
text=text[len("NAME "):]
text = text.lstrip()
if text[0]=="'":
text=text[1:]
end=text.index("'")
self.name=(text[:end],)
text=text[end+1:]
elif text[0]=="(":
text=text[1:]
text = text.lstrip()
end=text.index(")")
self.name=self._strings_to_list(text[:end])
text=text[end+1:]
else:
raise "TODO"
text = text.lstrip()
if peekWord(text) == "DESC":
text=text[len("DESC "):]
text = text.lstrip()
assert text[0]=="'"
text=text[1:]
end=text.index("'")
self.desc=text[:end]
text=text[end+1:]
text = text.lstrip()
if peekWord(text) == "OBSOLETE":
self.obsolete=1
text=text[len("OBSOLETE "):]
text = text.lstrip()
if peekWord(text) == "SUP":
text=text[len("SUP "):]
text = text.lstrip()
if text[0]=="(":
text=text[1:]
text = text.lstrip()
end=text.index(")")
self.sup=self._to_list(text[:end])
text=text[end+1:]
else:
s, text = extractWord(text)
self.sup=[s]
text = text.lstrip()
if peekWord(text) == "ABSTRACT":
assert self.type is None
self.type="ABSTRACT"
text=text[len("ABSTRACT "):]
text = text.lstrip()
if peekWord(text) == "STRUCTURAL":
assert self.type is None
self.type="STRUCTURAL"
text=text[len("STRUCTURAL "):]
text = text.lstrip()
if peekWord(text) == "AUXILIARY":
assert self.type is None
self.type="AUXILIARY"
text=text[len("AUXILIARY "):]
text = text.lstrip()
if peekWord(text) == "MUST":
text=text[len("MUST "):]
text = text.lstrip()
if text[0]=="(":
text=text[1:]
text = text.lstrip()
end=text.index(")")
self.must.extend(self._to_list(text[:end]))
text=text[end+1:]
else:
s, text = extractWord(text)
self.must.append(s)
text = text.lstrip()
if peekWord(text) == "MAY":
text=text[len("MAY "):]
text = text.lstrip()
if text[0]=="(":
text=text[1:]
text = text.lstrip()
end=text.index(")")
self.may.extend(self._to_list(text[:end]))
text=text[end+1:]
else:
s, text = extractWord(text)
self.may.append(s)
text = text.lstrip()
assert text=="", "Text was not empty: %s"%repr(text)
if not self.type:
self.type="STRUCTURAL"
assert self.oid
for c in self.oid:
assert c in "0123456789."
assert self.name is None or self.name
assert self.type in ("ABSTRACT", "STRUCTURAL", "AUXILIARY")
def __repr__(self):
nice = {}
for k,v in self.__dict__.items():
nice[k]=repr(v)
return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
+(" oid=%(oid)s name=%(name)s desc=%(desc)s"
+" obsolete=%(obsolete)s sup=%(sup)s type=%(type)s"
+" must=%(must)s may=%(may)s>")%nice)
def __str__(self):
r=[]
if self.name is not None:
r.append('NAME %s' % self._str_list(self.name))
if self.desc is not None:
r.append('DESC %s' % self._str(self.desc))
if self.obsolete:
r.append('OBSOLETE')
if self.sup:
r.append('SUP %s' % self._list(self.sup))
r.append('%s' % self.type)
if self.must:
r.append('MUST %s' % self._list(self.must))
if self.may:
r.append('MAY %s' % self._list(self.may))
return ('( %s ' % self.oid
+ '\n '.join(r)
+ ' )')
def __lt__(self, other):
if not isinstance(other, ObjectClassDescription):
return NotImplemented
if self.name is not None and other.name is not None:
return self.name[0].upper() < other.name[0].upper()
else:
return self.oid < other.oid
def __gt__(self, other):
if not isinstance(other, ObjectClassDescription):
return NotImplemented
if self.name is not None and other.name is not None:
return self.name[0].upper() > other.name[0].upper()
else:
return self.oid > other.oid
def __le__(self, other):
return self == other or self < other
def __ge__(self, other):
return self == other or self > other
def __eq__(self, other):
if not isinstance(other, ObjectClassDescription):
return NotImplemented
return (self.oid == other.oid
and self.name == other.name
and self.desc == other.desc
and self.obsolete == other.obsolete
and self.sup == other.sup
and self.type == other.type
and self.must == other.must
and self.may == other.may)
def __ne__(self, other):
return not (self == other)
class AttributeTypeDescription(ASN1ParserThingie):
"""
ASN Syntax::
AttributeTypeDescription = "(" whsp
numericoid whsp ; AttributeType identifier
[ "NAME" qdescrs ] ; name used in AttributeType
[ "DESC" qdstring ] ; description
[ "OBSOLETE" whsp ]
[ "SUP" woid ] ; derived from this other AttributeType
[ "EQUALITY" woid ; Matching Rule name
[ "ORDERING" woid ; Matching Rule name
[ "SUBSTR" woid ] ; Matching Rule name
[ "SYNTAX" whsp noidlen whsp ] ; see section 4.3
[ "SINGLE-VALUE" whsp ] ; default multi-valued
[ "COLLECTIVE" whsp ] ; default not collective
[ "NO-USER-MODIFICATION" whsp ]; default user modifiable
[ "USAGE" whsp AttributeUsage ]; default userApplications
whsp ")"
AttributeUsage =
"userApplications" /
"directoryOperation" /
"distributedOperation" / ; DSA-shared
"dSAOperation" ; DSA-specific, value depends on server
noidlen = numericoid [ "{" len "}" ]
len = numericstring
"""
def __init__(self, text):
self.oid=None
self.name=None
self.desc=None
self.obsolete=0
self.sup=None
self.equality=None
self.ordering=None
self.substr=None
self.syntax=None
self.single_value=None
self.collective=None
self.no_user_modification=None
self.usage=None
if text is not None:
self._parse(text)
def _parse(self, text):
assert text[0]=='(', "Text %s must be in parentheses."%repr(text)
assert text[-1]==')', "Text %s must be in parentheses."%repr(text)
text=text[1:-1]
text = text.lstrip()
# oid
self.oid, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "NAME":
text=text[len("NAME "):]
text = text.lstrip()
if text[0]=="'":
text=text[1:]
end=text.index("'")
self.name=(text[:end],)
text=text[end+1:]
elif text[0]=="(":
text=text[1:]
text = text.lstrip()
end=text.index(")")
self.name=self._strings_to_list(text[:end])
text=text[end+1:]
else:
raise "TODO"
text = text.lstrip()
if peekWord(text) == "DESC":
text=text[len("DESC "):]
text = text.lstrip()
assert text[0]=="'"
text=text[1:]
end=text.index("'")
self.desc=text[:end]
text=text[end+1:]
text = text.lstrip()
if peekWord(text) == "OBSOLETE":
self.obsolete=1
text=text[len("OBSOLETE "):]
text = text.lstrip()
if peekWord(text) == "SUP":
text=text[len("SUP "):]
text = text.lstrip()
self.sup, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "EQUALITY":
text=text[len("EQUALITY "):]
text = text.lstrip()
self.equality, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "ORDERING":
text=text[len("ORDERING "):]
text = text.lstrip()
self.ordering, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "SUBSTR":
text=text[len("SUBSTR "):]
text = text.lstrip()
self.substr, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "SYNTAX":
text=text[len("SYNTAX "):]
text = text.lstrip()
self.syntax, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "SINGLE-VALUE":
assert self.single_value is None
self.single_value=1
text=text[len("SINGLE-VALUE "):]
text = text.lstrip()
if peekWord(text) == "COLLECTIVE":
assert self.collective is None
self.collective=1
text=text[len("COLLECTIVE "):]
text = text.lstrip()
if peekWord(text) == "NO-USER-MODIFICATION":
assert self.no_user_modification is None
self.no_user_modification=1
text=text[len("NO-USER-MODIFICATION "):]
text = text.lstrip()
if peekWord(text) == "USAGE":
assert self.usage is None
text=text[len("USAGE "):]
text = text.lstrip()
self.usage, text = extractWord(text)
text = text.lstrip()
assert text=="", "Text was not empty: %s"%repr(text)
if self.single_value is None:
self.single_value=0
if self.collective is None:
self.collective=0
if self.no_user_modification is None:
self.no_user_modification=0
assert self.oid
for c in self.oid:
assert c in "0123456789."
assert self.name is None or self.name
assert self.usage is None or self.usage in (
"userApplications",
"directoryOperation",
"distributedOperation",
"dSAOperation",
)
def __repr__(self):
nice = {}
for k,v in self.__dict__.items():
nice[k]=repr(v)
return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
+(" oid=%(oid)s name=%(name)s desc=%(desc)s"
+" obsolete=%(obsolete)s sup=%(sup)s"
+" equality=%(equality)s ordering=%(ordering)s"
+" substr=%(substr)s syntax=%(syntax)s"
+" single_value=%(single_value)s"
+" collective=%(collective)s"
+" no_user_modification=%(no_user_modification)s"
+" usage=%(usage)s>")%nice)
def __str__(self):
r=[]
if self.name is not None:
r.append('NAME %s' % self._str_list(self.name))
if self.desc is not None:
r.append('DESC %s' % self._str(self.desc))
if self.obsolete:
r.append('OBSOLETE')
if self.sup is not None:
r.append('SUP %s' % self.sup)
if self.equality is not None:
r.append('EQUALITY %s' % self.equality)
if self.ordering is not None:
r.append('ORDERING %s' % self.ordering)
if self.substr is not None:
r.append('SUBSTR %s' % self.substr)
if self.syntax is not None:
r.append('SYNTAX %s' % self.syntax)
if self.single_value:
r.append('SINGLE-VALUE')
if self.collective:
r.append('COLLECTIVE')
if self.no_user_modification:
r.append('NO-USER-MODIFICATION')
if self.usage is not None:
r.append('USAGE %s' % self.usage)
return ('( %s ' % self.oid
+ '\n '.join(r)
+ ' )')
class SyntaxDescription(ASN1ParserThingie):
"""
ASN Syntax::
SyntaxDescription = "(" whsp
numericoid whsp
[ "DESC" qdstring ]
whsp ")"
"""
def __init__(self, text):
self.oid=None
self.desc=None
assert text[0]=='('
assert text[-1]==')'
text=text[1:-1]
text = text.lstrip()
# oid
self.oid, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "DESC":
text=text[len("DESC "):]
text = text.lstrip()
assert text[0]=="'"
text=text[1:]
end=text.index("'")
self.desc=text[:end]
text=text[end+1:]
text = text.lstrip()
if peekWord(text) == "X-BINARY-TRANSFER-REQUIRED":
text=text[len("X-BINARY-TRANSFER-REQUIRED "):]
text = text.lstrip()
assert text[0]=="'"
text=text[1:]
end=text.index("'")
self.desc=text[:end]
text=text[end+1:]
text = text.lstrip()
if peekWord(text) == "X-NOT-HUMAN-READABLE":
text=text[len("X-NOT-HUMAN-READABLE "):]
text = text.lstrip()
assert text[0]=="'"
text=text[1:]
end=text.index("'")
self.desc=text[:end]
text=text[end+1:]
text = text.lstrip()
assert text=="", "Text was not empty: %s"%repr(text)
assert self.oid
for c in self.oid:
assert c in "0123456789."
def __repr__(self):
nice = {}
for k,v in self.__dict__.items():
nice[k]=repr(v)
return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
+(" oid=%(oid)s desc=%(desc)s>")%nice)
class MatchingRuleDescription(ASN1ParserThingie):
"""
ASN Syntax::
MatchingRuleDescription = "(" whsp
numericoid whsp ; MatchingRule identifier
[ "NAME" qdescrs ]
[ "DESC" qdstring ]
[ "OBSOLETE" whsp ]
"SYNTAX" numericoid
whsp ")"
"""
def __init__(self, text):
self.oid=None
self.name=None
self.desc=None
self.obsolete=None
self.syntax=None
assert text[0]=='('
assert text[-1]==')'
text=text[1:-1]
text = text.lstrip()
# oid
self.oid, text = extractWord(text)
text = text.lstrip()
if peekWord(text) == "NAME":
text=text[len("NAME "):]
text = text.lstrip()
if text[0]=="'":
text=text[1:]
end=text.index("'")
self.name=(text[:end],)
text=text[end+1:]
elif text[0]=="(":
text=text[1:]
text = text.lstrip()
end=text.index(")")
self.name=self._strings_to_list(text[:end])
text=text[end+1:]
else:
raise "TODO"
text = text.lstrip()
if peekWord(text) == "DESC":
text=text[len("DESC "):]
text = text.lstrip()
assert text[0]=="'"
text=text[1:]
end=text.index("'")
self.desc=text[:end]
text=text[end+1:]
text = text.lstrip()
if peekWord(text) == "OBSOLETE":
self.obsolete=1
text=text[len("OBSOLETE "):]
text = text.lstrip()
if peekWord(text) == "SYNTAX":
text=text[len("SYNTAX "):]
text = text.lstrip()
self.syntax, text = extractWord(text)
text = text.lstrip()
assert text=="", "Text was not empty: %s"%repr(text)
if self.obsolete is None:
self.obsolete=0
assert self.oid
for c in self.oid:
assert c in "0123456789."
assert self.syntax
def __repr__(self):
nice = {}
for k,v in self.__dict__.items():
nice[k]=repr(v)
return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
+(" oid=%(oid)s desc=%(desc)s>")%nice)
ldaptor-0.0.43/ldaptor/ldiftree.py 0000644 0001750 0001750 00000027626 10347777536 015222 0 ustar jan jan """
Manage LDAP data as a tree of LDIF files.
"""
import os, errno, sets
from zope.interface import implements
from twisted.internet import defer, error
from twisted.python import failure
from ldaptor import entry, interfaces, attributeset, entryhelpers
from ldaptor.protocols.ldap import ldifprotocol, distinguishedname, ldaperrors
from twisted.mail.maildir import _generateMaildirName as tempName
class LDIFTreeEntryContainsMultipleEntries(Exception):
"""LDIFTree entry contains multiple LDIF entries."""
class LDIFTreeEntryContainsNoEntries(Exception):
"""LDIFTree entry does not contain a valid LDIF entry."""
class LDIFTreeNoSuchObject(Exception):
# TODO combine with standard LDAP errors
"""LDIFTree does not contain such entry."""
class LDAPCannotRemoveRootError(ldaperrors.LDAPNamingViolation):
"""Cannot remove root of LDAP tree"""
# TODO share with ldaptor.inmemory?
class StoreParsedLDIF(ldifprotocol.LDIF):
def __init__(self):
self.done = False
self.seen = []
def gotEntry(self, obj):
self.seen.append(obj)
def connectionLost(self, reason):
self.done = True
def get(path, dn):
return defer.maybeDeferred(_get, path, dn)
def _get(path, dn):
dn = distinguishedname.DistinguishedName(dn)
l = list(dn.split())
assert len(l) >= 1
l.reverse()
parser = StoreParsedLDIF()
entry = os.path.join(path,
*['%s.dir'%rdn for rdn in l[:-1]])
entry = os.path.join(entry, '%s.ldif'%l[-1])
f = file(entry)
while 1:
data = f.read(8192)
if not data:
break
parser.dataReceived(data)
parser.connectionLost(failure.Failure(error.ConnectionDone))
assert parser.done
entries = parser.seen
if len(entries) == 0:
raise LDIFTreeEntryContainsNoEntries
elif len(entries) > 1:
raise LDIFTreeEntryContainsMultipleEntries, entries
else:
return entries[0]
def _putEntry(fileName, entry):
"""fileName is without extension."""
tmp = fileName + '.' + tempName() + '.tmp'
f = file(tmp, 'w')
f.write(str(entry))
f.close()
os.rename(tmp, fileName+'.ldif')
# TODO atomicity
def _put(path, entry):
l = list(entry.dn.split())
assert len(l) >= 1
l.reverse()
entryRDN = l.pop()
if l:
grandParent = os.path.join(path,
*['%s.dir'%rdn for rdn in l[:-1]])
parentEntry = os.path.join(grandParent, '%s.ldif' % l[-1])
parentDir = os.path.join(grandParent, '%s.dir' % l[-1])
if not os.path.exists(parentDir):
if not os.path.exists(parentEntry):
raise LDIFTreeNoSuchObject, entry.dn.up()
try:
os.mkdir(parentDir)
except OSError, e:
if e.errno == errno.EEXIST:
# we lost a race to create the directory, safe to ignore
pass
else:
raise
else:
parentDir = path
return _putEntry(os.path.join(parentDir, '%s'%entryRDN), entry)
def put(path, entry):
return defer.execute(_put, path, entry)
class LDIFTreeEntry(entry.EditableLDAPEntry,
entryhelpers.DiffTreeMixin,
entryhelpers.SubtreeFromChildrenMixin,
entryhelpers.MatchMixin,
entryhelpers.SearchByTreeWalkingMixin,
):
implements(interfaces.IConnectedLDAPEntry)
def __init__(self, path, dn=None, *a, **kw):
if dn is None:
dn = ''
entry.BaseLDAPEntry.__init__(self, dn, *a, **kw)
self.path = path
if dn != '': #TODO DistinguishedName.__nonzero__
self._load()
def _load(self):
assert self.path.endswith('.dir')
entryPath = '%s.ldif' % self.path[:-len('.dir')]
parser = StoreParsedLDIF()
try:
f = file(entryPath)
except IOError, e:
if e.errno == errno.ENOENT:
return
else:
raise
while 1:
data = f.read(8192)
if not data:
break
parser.dataReceived(data)
parser.connectionLost(failure.Failure(error.ConnectionDone))
assert parser.done
entries = parser.seen
if len(entries) == 0:
raise LDIFTreeEntryContainsNoEntries
elif len(entries) > 1:
raise LDIFTreeEntryContainsMultipleEntries, entries
else:
# TODO ugliness and all of its friends
for k,v in entries[0].items():
self._attributes[k] = attributeset.LDAPAttributeSet(k, v)
def parent(self):
# TODO add __nonzero__ to DistinguishedName
if self.dn == '':
# root
return None
else:
parentPath, _ = os.path.split(self.path)
return self.__class__(parentPath, self.dn.up())
def _sync_children(self):
children = []
try:
filenames = os.listdir(self.path)
except OSError, e:
if e.errno == errno.ENOENT:
pass
else:
raise
else:
seen = sets.Set()
for fn in filenames:
base, ext = os.path.splitext(fn)
if ext not in ['.dir', '.ldif']:
continue
if base in seen:
continue
seen.add(base)
dn = distinguishedname.DistinguishedName(
listOfRDNs=((distinguishedname.RelativeDistinguishedName(base),)
+ self.dn.split()))
e = self.__class__(os.path.join(self.path, base + '.dir'), dn)
children.append(e)
return children
def _children(self, callback=None):
children = self._sync_children()
if callback is None:
return children
else:
for c in children:
callback(c)
return None
def children(self, callback=None):
return defer.maybeDeferred(self._children, callback=callback)
def lookup(self, dn):
dn = distinguishedname.DistinguishedName(dn)
if not self.dn.contains(dn):
return defer.fail(ldaperrors.LDAPNoSuchObject(dn))
if dn == self.dn:
return defer.succeed(self)
it = dn.split()
me = self.dn.split()
assert len(it) > len(me)
assert ((len(me)==0) or (it[-len(me):] == me))
rdn = it[-len(me)-1]
path = os.path.join(self.path, '%s.dir' % rdn)
entry = os.path.join(self.path, '%s.ldif' % rdn)
if not os.path.isdir(path) and not os.path.isfile(entry):
return defer.fail(ldaperrors.LDAPNoSuchObject(dn))
else:
childDN = distinguishedname.DistinguishedName(listOfRDNs=(rdn,)+me)
c = self.__class__(path, childDN)
return c.lookup(dn)
def _addChild(self, rdn, attributes):
rdn = distinguishedname.RelativeDistinguishedName(rdn)
for c in self._sync_children():
if c.dn.split()[0] == rdn:
raise ldaperrors.LDAPEntryAlreadyExists, c.dn
dn = distinguishedname.DistinguishedName(listOfRDNs=
(rdn,)
+self.dn.split())
e = entry.BaseLDAPEntry(dn, attributes)
if not os.path.exists(self.path):
os.mkdir(self.path)
fileName = os.path.join(self.path, '%s' % rdn)
tmp = fileName + '.' + tempName() + '.tmp'
f = file(tmp, 'w')
f.write(str(e))
f.close()
os.rename(tmp, fileName+'.ldif')
# TODO atomicity
dirName = os.path.join(self.path, '%s.dir' % rdn)
e = self.__class__(dirName, dn)
return e
def addChild(self, rdn, attributes):
d = self._addChild(rdn, attributes)
return d
def _delete(self):
if self.dn == '': ##TODO DistinguishedName __nonzero__
raise LDAPCannotRemoveRootError
if self._sync_children():
raise ldaperrors.LDAPNotAllowedOnNonLeaf(
'Cannot remove entry with children: %s' % self.dn)
assert self.path.endswith('.dir')
entryPath = '%s.ldif' % self.path[:-len('.dir')]
os.remove(entryPath)
return self
def delete(self):
return defer.maybeDeferred(self._delete)
def _deleteChild(self, rdn):
if not isinstance(rdn, distinguishedname.RelativeDistinguishedName):
rdn = distinguishedname.RelativeDistinguishedName(stringValue=rdn)
for c in self._sync_children():
if c.dn.split()[0] == rdn:
return c.delete()
raise ldaperrors.LDAPNoSuchObject, rdn
def deleteChild(self, rdn):
return defer.maybeDeferred(self._deleteChild, rdn)
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__,
self.path,
str(self.dn))
def __cmp__(self, other):
if not isinstance(other, LDIFTreeEntry):
return NotImplemented
return cmp(self.dn, other.dn)
def commit(self):
assert self.path.endswith('.dir')
entryPath = self.path[:-len('.dir')]
return defer.maybeDeferred(_putEntry, entryPath, self)
def move(self, newDN):
return defer.maybeDeferred(self._move, newDN)
def _move(self, newDN):
if not isinstance(newDN, distinguishedname.DistinguishedName):
newDN = distinguishedname.DistinguishedName(stringValue=newDN)
if newDN.up() != self.dn.up():
# climb up the tree to root
rootDN = self.dn
rootPath = self.path
while rootDN != '':
rootDN = rootDN.up()
rootPath = os.path.dirname(rootPath)
root = self.__class__(path=rootPath, dn=rootDN)
d = defer.maybeDeferred(root.lookup, newDN.up())
else:
d = defer.succeed(None)
d.addCallback(self._move2, newDN)
return d
def _move2(self, newParent, newDN):
# remove old RDN attributes
for attr in self.dn.split()[0].split():
self[attr.attributeType].remove(attr.value)
# add new RDN attributes
for attr in newDN.split()[0].split():
# TODO what if the key does not exist?
self[attr.attributeType].add(attr.value)
newRDN = newDN.split()[0]
srcdir = os.path.dirname(self.path)
if newParent is None:
dstdir = srcdir
else:
dstdir = newParent.path
newpath = os.path.join(dstdir, '%s.dir' % newRDN)
try:
os.rename(self.path, newpath)
except OSError, e:
if e.errno == errno.ENOENT:
pass
else:
raise
basename, ext = os.path.splitext(self.path)
assert ext == '.dir'
os.rename('%s.ldif' % basename,
os.path.join(dstdir, '%s.ldif' % newRDN))
self.dn = newDN
self.path = newpath
return self.commit()
if __name__ == '__main__':
"""
Demonstration LDAP server; serves an LDIFTree from given directory
over LDAP on port 10389.
"""
from twisted.internet import reactor, protocol
from twisted.python import log
import sys
log.startLogging(sys.stderr)
from twisted.python import components
from ldaptor.protocols.ldap import ldapserver
path = sys.argv[1]
db = LDIFTreeEntry(path)
class LDAPServerFactory(protocol.ServerFactory):
def __init__(self, root):
self.root = root
class MyLDAPServer(ldapserver.LDAPServer):
debug = True
components.registerAdapter(lambda x: x.root,
LDAPServerFactory,
interfaces.IConnectedLDAPEntry)
factory = LDAPServerFactory(db)
factory.protocol = MyLDAPServer
reactor.listenTCP(10389, factory)
reactor.run()
ldaptor-0.0.43/ldaptor/usage.py 0000644 0001750 0001750 00000006072 10344535643 014504 0 ustar jan jan from twisted.python import usage, reflect
from ldaptor.protocols import pureldap
from ldaptor.protocols.ldap import distinguishedname
class Options(usage.Options):
optParameters = ()
def postOptions(self):
postOpt = {}
reflect.addMethodNamesToDict(self.__class__, postOpt, "postOptions_")
for name in postOpt.keys():
method = getattr(self, 'postOptions_'+name)
method()
class Options_service_location:
def opt_service_location(self, value):
"""Service location, in the form BASEDN:HOST[:PORT]"""
if not self.opts.has_key('service-location'):
self.opts['service-location']={}
base, location = value.split(':', 1)
try:
dn = distinguishedname.DistinguishedName(base)
except distinguishedname.InvalidRelativeDistinguishedName, e:
raise usage.UsageError, str(e)
if not location:
raise usage.UsageError, "service-location must specify host"
if ':' in location:
host, port = location.split(':', 1)
else:
host, port = location, None
if not host:
host = None
if not port:
port = None
self.opts['service-location'][dn] = (host, port)
def postOptions_service_location(self):
if not self.opts.has_key('service-location'):
self.opts['service-location']={}
class Options_base_optional:
optParameters = (
('base', None, None,
"LDAP base dn"),
)
class Options_base(Options_base_optional):
def postOptions_base(self):
# check that some things are given
if self.opts['base'] is None:
raise usage.UsageError, "%s must be given" % 'base'
class Options_scope:
optParameters = (
('scope', None, 'sub',
"LDAP search scope (one of base, one, sub)"),
)
def postOptions_scope(self):
synonyms = {
'base': 'baseObject',
'single': 'singleLevel',
'subtree': 'wholeSubtree',
'sub': 'wholeSubtree',
}
scope = self.opts['scope']
scope=synonyms.get(scope, scope)
try:
scope=getattr(pureldap, 'LDAP_SCOPE_'+scope)
except AttributeError:
raise usage.UsageError, "bad scope: %s" % scope
self.opts['scope'] = scope
class Options_bind:
optParameters = (
('binddn', None, None,
"use Distinguished Name to bind to the directory"),
('bind-auth-fd', None, None,
"read bind password from filedescriptor"),
)
def postOptions_bind_auth_fd_numeric(self):
val=self.opts['bind-auth-fd']
if val is not None:
try:
val = int(val)
except ValueError:
raise usage.UsageError, "%s value must be numeric" % 'bind-auth-fd'
self.opts['bind-auth-fd'] = val
class Options_bind_mandatory(Options_bind):
def postOptions_bind_mandatory(self):
if not self.opts['binddn']:
raise usage.UsageError, "%s must be given" % 'binddn'
ldaptor-0.0.43/ldaptor/apps/ 0000755 0001750 0001750 00000000000 10403234311 013744 5 ustar jan jan ldaptor-0.0.43/ldaptor/apps/__init__.py 0000644 0001750 0001750 00000000000 07516345760 016071 0 ustar jan jan ldaptor-0.0.43/ldaptor/apps/webui/ 0000755 0001750 0001750 00000000000 10403234314 015062 5 ustar jan jan ldaptor-0.0.43/ldaptor/apps/webui/change_password.py 0000644 0001750 0001750 00000036306 10402650176 020622 0 ustar jan jan from zope.interface import implements
from twisted.internet import reactor
from twisted.internet import defer
from webut.skin import iskin
from ldaptor.protocols import pureldap
from ldaptor.protocols.ldap import ldapsyntax, distinguishedname
from ldaptor import generate_password, interfaces
from ldaptor.apps.webui.uriquote import uriUnquote
from ldaptor import weave
from ldaptor.apps.webui.i18n import _
from ldaptor.apps.webui import i18n
import os
from nevow import rend, inevow, loaders, url, tags
from formless import annotate, webform, iformless, configurable
def getEntry(ctx, dn):
user = ctx.locate(inevow.ISession).getLoggedInRoot().loggedIn
e=ldapsyntax.LDAPEntry(client=user.client, dn=dn)
return e
def getEntryWithAttributes(ctx, dn, *attributes):
e = getEntry(ctx, dn)
d = e.fetch(*attributes)
return d
def getServiceName(ctx, dn):
d = getEntryWithAttributes(ctx, dn, 'cn')
def _cb(e):
for cn in e.get('cn', []):
return cn
raise RuntimeError, \
_("Service password entry has no attribute cn: %r") % e
d.addCallback(_cb)
return d
def checkPasswordTypos(newPassword, again):
if newPassword != again:
raise annotate.ValidateError(
{},
formErrorMessage=_('Passwords do not match.'))
class RemoveServicePassword(configurable.Configurable):
def __init__(self, dn):
super(RemoveServicePassword, self).__init__(None)
self.dn = dn
def getBindingNames(self, ctx):
return ['remove']
def bind_remove(self, ctx):
return annotate.MethodBinding(
'remove',
annotate.Method(arguments=[
annotate.Argument('ctx', annotate.Context()),
],
label=_('Remove')),
action=_('Remove'))
def remove(self, ctx):
e = getEntry(ctx, self.dn)
d = getServiceName(ctx, self.dn)
def _delete(name, e):
d = e.delete()
d.addCallback(lambda _: name)
return d
d.addCallback(_delete, e)
def _report(name):
return _('Removed service %r') % name
d.addCallback(_report)
return d
class SetServicePassword(configurable.Configurable):
def __init__(self, dn):
super(SetServicePassword, self).__init__(None)
self.dn = dn
def getBindingNames(self, ctx):
return ['setServicePassword']
def bind_setServicePassword(self, ctx):
return annotate.MethodBinding(
'setServicePassword',
annotate.Method(arguments=[
annotate.Argument('ctx', annotate.Context()),
annotate.Argument('newPassword', annotate.PasswordEntry(required=True,
label=_('New password'))),
annotate.Argument('again', annotate.PasswordEntry(required=True,
label=_('Again'))),
],
label=_('Set password')),
action=_('Set password'))
def _isPasswordAcceptable(self, ctx, newPassword, again):
return checkPasswordTypos(newPassword, again)
def setServicePassword(self, ctx, newPassword, again):
d = defer.maybeDeferred(self._isPasswordAcceptable, ctx, newPassword, again)
def _setPassword(ctx, dn, newPassword):
e = getEntry(ctx, dn)
d=defer.maybeDeferred(e.setPassword, newPasswd=newPassword)
return d
d.addCallback(lambda _: _setPassword(ctx, self.dn, newPassword))
def _getName(_, ctx):
d = getServiceName(ctx, self.dn)
return d
d.addCallback(_getName, ctx)
def _report(name):
return _('Set password for service %r') % name
d.addCallback(_report)
return d
class SetRandomServicePassword(configurable.Configurable):
def __init__(self, dn):
super(SetRandomServicePassword, self).__init__(None)
self.dn = dn
def getBindingNames(self, ctx):
return ['generateRandom']
def bind_generateRandom(self, ctx):
return annotate.MethodBinding(
'generateRandom',
annotate.Method(arguments=[
annotate.Argument('ctx', annotate.Context()),
],
label=_('Generate random')),
action=_('Generate random'))
def generateRandom(self, ctx):
d=generate_password.generate(reactor)
def _first(passwords):
assert len(passwords)==1
return passwords[0]
d.addCallback(_first)
def _setPass(newPassword, ctx):
e = getEntry(ctx, self.dn)
d = e.setPassword(newPassword)
def _getName(_, ctx):
d = getServiceName(ctx, self.dn)
return d
d.addCallback(_getName, ctx)
def _report(name, newPassword):
return _('Service %r password set to %s') % (name, newPassword)
d.addCallback(_report, newPassword)
return d
d.addCallback(_setPass, ctx)
return d
class AddService(configurable.Configurable):
def __init__(self, dn):
super(AddService, self).__init__(None)
self.dn = dn
def getBindingNames(self, ctx):
return ['add']
def bind_add(self, ctx):
return annotate.MethodBinding(
'add',
annotate.Method(arguments=[
annotate.Argument('ctx', annotate.Context()),
annotate.Argument('serviceName', annotate.String(required=True,
label=_('Service name'))),
annotate.Argument('newPassword', annotate.PasswordEntry(required=False,
label=_('New password'),
description=_("Leave empty to generate random password."))),
annotate.Argument('again', annotate.PasswordEntry(required=False,
label=_('Again'))),
],
label=_('Add')),
action=_('Add'))
def add(self, ctx, serviceName, newPassword, again):
if newPassword or again:
checkPasswordTypos(newPassword, again)
if not newPassword:
return self._generate(ctx, serviceName)
else:
return self._add(ctx, newPassword, serviceName)
return d
def _cbSetPassword(self, ctx, newPassword, serviceName):
e = getEntry(ctx, self.dn)
rdn = distinguishedname.RelativeDistinguishedName(
attributeTypesAndValues=[
distinguishedname.LDAPAttributeTypeAndValue(
attributeType='cn', value=serviceName),
distinguishedname.LDAPAttributeTypeAndValue(
attributeType='owner', value=str(self.dn))
])
d = e.addChild(rdn, {
'objectClass': ['serviceSecurityObject'],
'cn': [serviceName],
'owner': [str(self.dn)],
'userPassword': ['{crypt}!'],
})
def _setPass(e, newPassword):
d = e.setPassword(newPassword)
return d
d.addCallback(_setPass, newPassword)
return d
def _generate(self, ctx, serviceName):
d=generate_password.generate(reactor)
def _first(passwords):
assert len(passwords)==1
return passwords[0]
d.addCallback(_first)
def _cb(newPassword, serviceName):
d = self._cbSetPassword(ctx, newPassword, serviceName)
d.addCallback(lambda dummy: _('Added service %r with password %s') % (serviceName, newPassword))
return d
d.addCallback(_cb, serviceName)
return d
def _add(self, ctx, newPassword, serviceName):
d = self._cbSetPassword(ctx, newPassword, serviceName)
def _report(dummy, name):
return _('Added service %r') % name
d.addCallback(_report, serviceName)
return d
class ServicePasswordChangeMixin(object):
def __init__(self, dn):
super(ServicePasswordChangeMixin, self).__init__()
self.dn = dn
def listServicePasswordActions(self):
l = [(int(pri), name)
for x, pri, name in [name.split('_', 2) for name in dir(self)
if name.startswith('servicePasswordAction_')]]
l.sort()
for pri, name in l:
yield name
def getServicePasswordAction(self, name):
for attrName in dir(self):
if not attrName.startswith('servicePasswordAction_'):
continue
x, pri, actionName = attrName.split('_', 2)
if actionName == name:
return getattr(self, attrName)
return None
def render_servicePasswords(self, ctx, data):
docFactory = loaders.xmlfile(
'change_service_passwords.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
r = inevow.IQ(docFactory).onePattern('main')
return r
def render_hideIfNot(self, ctx, data):
if data:
return ctx.tag
else:
return tags.invisible()
def data_servicePasswords(self, ctx, data):
user = ctx.locate(inevow.ISession).getLoggedInRoot().loggedIn
config = interfaces.ILDAPConfig(ctx)
e=ldapsyntax.LDAPEntry(client=user.client, dn=config.getBaseDN())
d = e.search(filterObject=pureldap.LDAPFilter_and([
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('objectClass'),
assertionValue=pureldap.LDAPAssertionValue('serviceSecurityObject')),
pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('owner'),
assertionValue=pureldap.LDAPAssertionValue(str(self.dn))),
pureldap.LDAPFilter_present('cn'),
]),
attributes=['cn'])
return d
def render_form_service(self, ctx, data):
# TODO error messages for one password change form display in
# all of them.
e = inevow.IData(ctx)
for name in self.listServicePasswordActions():
yield webform.renderForms('service_%s_%s' % (name, e.dn))[ctx.tag()]
def locateConfigurable(self, ctx, name):
try:
return super(ServicePasswordChangeMixin, self).locateConfigurable(ctx, name)
except AttributeError:
if name.startswith('service_'):
pass
else:
raise
rest = name[len('service_'):]
l = rest.split('_', 1)
if len(l) != 2:
raise AttributeError, name
c = self.getServicePasswordAction(l[0])
if c is None:
raise AttributeError, name
return iformless.IConfigurable(c(l[1]))
render_zebra = weave.zebra()
render_i18n = i18n.render()
class ConfirmChange(ServicePasswordChangeMixin, rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Password Change Page')
addSlash = True
docFactory = loaders.xmlfile(
'change_password.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def getBindingNames(self, ctx):
return ['setPassword', 'generateRandom']
def bind_setPassword(self, ctx):
return annotate.MethodBinding(
'setPassword',
annotate.Method(arguments=[
annotate.Argument('ctx', annotate.Context()),
annotate.Argument('newPassword', annotate.PasswordEntry(required=True,
label=_('New password'))),
annotate.Argument('again', annotate.PasswordEntry(required=True,
label=_('Again'))),
],
label=_('Set password')),
action=_('Set password'))
def bind_generateRandom(self, ctx):
return annotate.MethodBinding(
'generateRandom',
annotate.Method(arguments=[
annotate.Argument('ctx', annotate.Context()),
],
label=_('Generate random')),
action=_('Generate random'))
servicePasswordAction_10_remove = RemoveServicePassword
servicePasswordAction_20_set = SetServicePassword
servicePasswordAction_30_random = SetRandomServicePassword
def _setPassword(self, ctx, password):
e = getEntry(ctx, self.dn)
d=defer.maybeDeferred(e.setPassword, newPasswd=password)
return d
def setPassword(self, ctx, newPassword, again):
d = defer.maybeDeferred(checkPasswordTypos, newPassword, again)
d.addCallback(lambda dummy: self._setPassword(ctx, newPassword))
d.addCallback(lambda dummy: _('Password set.'))
def eb(fail):
return _("Failed: %s") % fail.getErrorMessage()
d.addErrback(eb)
return d
def generateRandom(self, ctx):
d=generate_password.generate(reactor)
def _first(passwords):
assert len(passwords)==1
return passwords[0]
d.addCallback(_first)
def _status(newPassword, ctx):
d = self._setPassword(ctx, newPassword)
d.addCallback(lambda dummy: _('Password set to %s') % newPassword)
return d
d.addCallback(_status, ctx)
def eb(fail):
return _("Failed: %s") % fail.getErrorMessage()
d.addErrback(eb)
return d
def data_status(self, ctx, data):
try:
return ctx.locate(inevow.IStatusMessage)
except KeyError:
return ''
def data_dn(self, ctx, data):
return self.dn
def render_form(self, ctx, data):
return webform.renderForms()
def render_passthrough(self, ctx, data):
return ctx.tag.clear()[data]
def data_header(self, ctx, data):
u=url.URL.fromContext(ctx)
u=u.parentdir().parentdir().clear()
l=[]
l.append(tags.a(href=u.sibling("search"))[_("Search")])
l.append(tags.a(href=u.sibling("add"))[_("add new entry")])
l.append(tags.a(href=u.sibling("edit").child(str(self.dn)))[_("edit")])
l.append(tags.a(href=u.sibling("delete").child(str(self.dn)))[_("delete")])
return l
def render_add(self, ctx, data):
return webform.renderForms('add')
def configurable_add(self, ctx):
return AddService(self.dn)
render_i18n = i18n.render()
def render_data(self, ctx, data):
return ctx.tag.clear()[data]
class GetDN(rend.Page):
addSlash = True
def child_(self, ctx):
entry = inevow.ISession(ctx).getLoggedInRoot().loggedIn
u = inevow.IRequest(ctx).URLPath()
return u.child(str(entry.dn))
def childFactory(self, ctx, name):
unquoted=uriUnquote(name)
try:
dn = distinguishedname.DistinguishedName(stringValue=unquoted)
except distinguishedname.InvalidRelativeDistinguishedName, e:
# TODO There's no way to throw a FormException at this stage.
return None
r=ConfirmChange(dn=dn)
return r
def getResource():
return GetDN()
ldaptor-0.0.43/ldaptor/apps/webui/login.py 0000644 0001750 0001750 00000002403 10402650176 016552 0 ustar jan jan from zope.interface import implements
import os
from nevow import rend, loaders, guard, inevow, url
from webut.skin import iskin
from ldaptor.apps.webui import i18n
from ldaptor.apps.webui.i18n import _
def getActionURL(current, history):
action = current
if len(history) == 1:
action = action.here()
else:
for element in history[1:]:
action = action.parentdir()
action = action.child(guard.LOGIN_AVATAR)
for element in history:
action = action.child(element)
return action
class LoginPage(rend.Page):
"""The resource that is returned when you are not logged in"""
implements(iskin.ISkinnable)
title = _('Login')
docFactory = loaders.xmlfile(
'login.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def __init__(self, history):
self.history = history
super(LoginPage, self).__init__()
def locateChild(self, request, segments):
return LoginPage(self.history + list(segments)), []
def render_form(self, context, data):
current = url.URL.fromContext(context)
action = getActionURL(current, self.history)
context.fillSlots('action-url', str(action))
return context.tag
render_i18n = i18n.render()
ldaptor-0.0.43/ldaptor/apps/webui/edit-really.xhtml 0000644 0001750 0001750 00000001673 10402650176 020371 0 ustar jan jan
Title Goes Here
Ldaptor Edit Page
[foo|]
ldaptor-0.0.43/ldaptor/apps/webui/edit.py 0000644 0001750 0001750 00000043642 10402650176 016401 0 ustar jan jan from zope.interface import implements
from webut.skin import iskin
from ldaptor.protocols.ldap import ldapsyntax
from ldaptor.protocols.ldap import fetchschema
from ldaptor.protocols.ldap import distinguishedname
from ldaptor.apps.webui.uriquote import uriQuote, uriUnquote
from ldaptor.apps.webui.i18n import _
from ldaptor.apps.webui import i18n
import os
from nevow import rend, loaders, inevow, url, tags
from formless import iformless, configurable, annotate, webform
from twisted.internet import defer
from twisted.python import log
class EditStatus(object):
def __init__(self, entry, changes):
super(EditStatus, self).__init__()
self.entry = entry
self.changes = changes
multiLineAttributeTypes = {
'description'.upper(): 1,
}
def isAttributeTypeMultiLine(attributeType):
for name in attributeType.name:
if multiLineAttributeTypes.has_key(name.upper()):
assert not attributeType.single_value
return multiLineAttributeTypes[name.upper()]
return 0
class EditForm(configurable.Configurable):
nonEditableAttributes = {
'objectClass': 1,
}
def __init__(self, entry, attributeTypes, objectClasses):
super(EditForm, self).__init__(None)
self.entry=entry
self.attributeTypes=attributeTypes
self.objectClasses=objectClasses
def getBindingNames(self, ctx):
return ['edit']
def bind_edit(self, ctx):
formFields=self._getFormFields()
return annotate.MethodBinding(
'edit',
annotate.Method(arguments=formFields,
label=_('Edit')),
action=_('Edit'))
def _one_formfield(self, attr, values, required, result):
if not self.nonEditableAttributes.get(attr):
attrtype = self._get_attrtype(attr)
if attrtype.uiHint_multiline:
if attrtype.single_value:
assert len(values)==1
for val in values:
result.append(annotate.Argument(
'edit_'+attr,
annotate.Text(label=attr,
description=attrtype.desc or '',
default=val,
required=required,
)))
result.append(annotate.Argument(
'old_'+attr,
annotate.String(label=attr,
description=attrtype.desc or '',
default=val,
required=required,
hidden=True,
)))
else:
assert len(values)==1 # TODO handle multivalued multiline attributetypes
for val in values:
result.append(annotate.Argument(
'edit_'+attr,
annotate.Text(label=attr,
description=attrtype.desc or '',
default=val,
required=required,
)))
result.append(annotate.Argument(
'old_'+attr,
annotate.String(label=attr,
description=attrtype.desc or '',
default=val,
required=required,
hidden=True,
)))
else:
if attrtype.single_value:
assert len(values)==1
for val in values:
result.append(annotate.Argument(
'edit_'+attr,
annotate.String(label=attr,
description=attrtype.desc or '',
default=val,
required=required,
)))
result.append(annotate.Argument(
'old_'+attr,
annotate.String(label=attr,
description=attrtype.desc or '',
default=val,
required=required,
hidden=True,
)))
else:
# TODO maybe use a string field+button to add entries,
# multiselection list+button to remove entries?
values=map(str, values)
result.append(annotate.Argument(
'edit_'+attr,
annotate.Text(label=attr,
description=attrtype.desc or '',
default="\n".join(values),
required=required,
)))
if values:
result.append(annotate.Argument(
'old_'+attr,
annotate.String(label=attr,
description=attrtype.desc or '',
default="\n".join(values),
required=required,
hidden=True,
)))
def _getFormFields(self):
r=[]
r.append(annotate.Argument('context',
annotate.Context()))
assert self.entry
process = {}
for k in self.entry.keys():
process[k.upper()]=k
# TODO sort objectclasses somehow?
objectClasses = list(self.entry[process["OBJECTCLASS"]])
objectClassesSeen = {}
while objectClasses:
objclassName = objectClasses.pop()
if objectClassesSeen.has_key(objclassName):
continue
objectClassesSeen[objclassName]=1
objclass = None
for o in self.objectClasses:
for name in o.name:
if objclassName.upper()==name.upper():
objclass = o
assert objclass, "objectClass %s must have schema"%objclassName
objectClasses.extend(objclass.sup or [])
for attr_alias in objclass.must:
found_one=0
real_attr = self._get_attrtype(str(attr_alias))
for attr in real_attr.name:
if process.has_key(attr.upper()):
found_one=1
if process[attr.upper()] is not None:
self._one_formfield(attr,
self.entry[process[attr.upper()]],
required=True,
result=r)
for name in real_attr.name:
process[name.upper()]=None
if not found_one:
log.msg("Object doesn't have required attribute %s:\n%s"%(attr, self.entry))
self._one_formfield(real_attr.name[0],
[],
required=True,
result=r)
for attr_alias in objclass.may:
found_one=0
real_attr = self._get_attrtype(str(attr_alias))
for attr in real_attr.name:
if process.has_key(attr.upper()):
found_one=1
if process[attr.upper()] is not None:
self._one_formfield(attr,
self.entry[process[attr.upper()]],
required=False,
result=r)
if not found_one:
# a MAY attributetype not currently present in
# object, but user is of course free to add it.
attr=str(real_attr.name[0])
self._one_formfield(attr,
('',),
required=False,
result=r)
for name in real_attr.name:
process[name.upper()]=None
assert [v is None for k,v in process.items()], "All attributes must be in objectClasses MUST or MAY: %s"%process
return r
def _get_attrtype(self, name):
for a in self.attributeTypes:
for cur in a.name:
if name.upper() == cur.upper():
a.uiHint_multiline=isAttributeTypeMultiLine(a)
return a
raise RuntimeError, "attribute type %s not known"%name
def _textarea_to_list(self, t):
return filter(lambda x: x, [x.strip() for x in t.split("\n")])
def _prune_changes(self, old, new):
"""Prune non-changes when old and new state is known."""
if old is None:
old = []
o={}
n={}
for x in old:
n[x]=n.get(x, 0)+1
for x in new:
o[x]=o.get(x, 0)+1
for k in o.keys():
while o[k]>0:
try:
old.remove(k)
except ValueError:
break
o[k]-=1
for k in n.keys():
while n[k]>0:
try:
new.remove(k)
except ValueError:
break
n[k]-=1
return old, new
def edit(self, context, **kw):
entry = context.locate(inevow.ISession).getLoggedInRoot().loggedIn
user = entry.dn
d = defer.succeed(None)
changes = []
for k,v in kw.items():
if v is None:
v = ''
if k[:len("edit_")]=="edit_":
old=kw.get("old_"+k[len("edit_"):])
attrtype = self._get_attrtype(k[len("edit_"):])
assert attrtype
if attrtype.single_value or attrtype.uiHint_multiline:
v=v.replace('\r\n', '\n')
v=v.strip()
v=[v]
if v == ['']:
v = []
if old is not None:
old=old.replace('\r\n', '\n')
old=old.strip()
old=[old]
else:
v=self._textarea_to_list(v)
if old is not None:
old=self._textarea_to_list(old)
o, v = self._prune_changes(old, v)
if ((old is None and v)
or (old is not None
and (o or v))):
attr=k[len("edit_"):]
changes.append((attr, old, v))
#TODO
if not changes:
return EditStatus(self.entry, 'No changes!')
changes_desc=tags.ul()
newRDN = None
for rdn in self.entry.dn.split()[0].split():
for attr,old,new in changes:
if (rdn.attributeType == attr
and old is not None
and rdn.value in old):
# Need to change the rdn
if newRDN is None:
newRDN = list(self.entry.dn.split()[0].split())
newRDN.remove(rdn)
# Try to find a replacement RDN. Possibilities are
# new values from the edit form and old values
# currently in LDAP.
possible = list(new)
possible.extend(self.entry.get(rdn.attributeType, []))
for o in old:
# Values to be removed are not acceptable as
# new RDN.
try:
possible.remove(o)
except ValueError:
pass
if not possible:
raise ldapsyntax.CannotRemoveRDNError \
(rdn.attributeType,
rdn.value)
newRDN.append(distinguishedname.LDAPAttributeTypeAndValue(attributeType=attr,
value=possible[0]))
old.remove(rdn.value)
try:
new.remove(possible[0])
except ValueError:
pass
if newRDN is not None:
newRDN = distinguishedname.RelativeDistinguishedName(newRDN)
changes_desc[tags.li[
_("changing %s: changing RDN to say %s") \
%(repr(attr), newRDN)]]
newDN = distinguishedname.DistinguishedName(
(newRDN,)+self.entry.dn.split()[1:]
)
def _move(_):
return self.entry.move(newDN)
d.addCallback(_move)
def _redirect(r, ctx, newDN):
request = inevow.IRequest(ctx)
u = url.URL.fromContext(ctx).curdir()
u = u.child(uriQuote(newDN))
request.setComponent(iformless.IRedirectAfterPost, u)
return r
d.addCallback(_redirect, context, newDN)
for attr,old,new in changes:
if new:
if self.entry.has_key(attr):
self.entry[attr].update(new)
else:
self.entry[attr]=new
if old:
for x in old:
if x=='':
continue
self.entry[attr].remove(x)
if old or new:
l=tags.ul()
changes_desc[tags.li[_("changing %s") % attr], l]
if old:
l[tags.li[_("remove "), ', '.join(map(repr, old))]]
if new:
l[tags.li[_("add "), ', '.join(map(repr, new))]]
d.addCallback(lambda _: self.entry.commit())
d.addCallback(lambda e: EditStatus(e, changes_desc))
return d
class ReallyEditPage(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Edit Page')
addSlash = True
docFactory = loaders.xmlfile(
'edit-really.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def __init__(self,
entry,
attributeTypes,
objectClasses):
super(ReallyEditPage, self).__init__()
self.entry = entry
self.attributeTypes = attributeTypes
self.objectClasses = objectClasses
def data_header(self, ctx, data):
u=url.URL.fromContext(ctx)
u=u.parentdir().parentdir().clear()
l=[]
l.append(tags.a(href=u.sibling("search"))[_("Search")])
l.append(tags.a(href=u.sibling("add"))[_("add new entry")])
return l
def configurable_(self, context):
a = EditForm(self.entry,
self.attributeTypes,
self.objectClasses)
return a
def render_form(self, context, data):
return webform.renderForms()
def render_passthrough(self, context, data):
return context.tag.clear()[data]
def render_status(self, context, data):
try:
obj = context.locate(inevow.IHand)
except KeyError:
return context.tag.clear()
if not isinstance(obj, EditStatus):
return context.tag.clear()[obj]
u=url.URL.fromContext(context)
u=u.parentdir().parentdir().clear()
return context.tag.clear()[
_("Edited "),
tags.a(href=u.parentdir()
.child(obj.entry.dn)
.child("search"))[obj.entry.dn],
_(" successfully. "),
# TODO share implementation with entryLinks
'[',
tags.a(href=u.sibling('move').child(uriQuote(obj.entry.dn)))[_('move')],
'|',
tags.a(href=u.sibling('delete').child(uriQuote(obj.entry.dn)))[_('delete')],
'|',
tags.a(href=u.sibling('change_password').child(uriQuote(obj.entry.dn)))[_('change password')],
']',
tags.p[obj.changes],
]
render_i18n = i18n.render()
class EditPage(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Edit Page')
addSlash = True
docFactory = loaders.xmlfile(
'edit.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def render_url(self, ctx, data):
u = url.URL.fromContext(ctx)
return ctx.tag(href=u.parentdir().child('search'))
def childFactory(self, context, name):
dn = uriUnquote(name)
userEntry = inevow.ISession(context).getLoggedInRoot().loggedIn
e = ldapsyntax.LDAPEntryWithClient(dn=dn,
client=userEntry.client)
d = e.fetch()
def _getSchema(entry):
d = fetchschema.fetch(entry.client, entry.dn)
def cb((attributeTypes, objectClasses), entry):
return (entry, attributeTypes, objectClasses)
d.addCallback(cb, entry)
return d
d.addCallback(_getSchema)
def _createEditPage((entry, attributeTypes, objectClasses)):
return ReallyEditPage(entry, attributeTypes, objectClasses)
d.addCallback(_createEditPage)
return d
render_i18n = i18n.render()
ldaptor-0.0.43/ldaptor/apps/webui/skin-default.html 0000644 0001750 0001750 00000000613 10402650176 020345 0 ustar jan jan
ldaptor-0.0.43/ldaptor/apps/webui/search.xhtml 0000644 0001750 0001750 00000011271 10402650176 017416 0 ustar jan jan
Title Goes Here
ldaptor-0.0.43/ldaptor/apps/webui/basedn.xhtml 0000644 0001750 0001750 00000001162 10402650176 017403 0 ustar jan jan
Title Goes Here
Base DN
ldaptor-0.0.43/ldaptor/apps/webui/delete-nodn.xhtml 0000644 0001750 0001750 00000001345 10402650176 020350 0 ustar jan jan
Title Goes Here
Ldaptor Delete Page
Missing DN to delete.You need to use thesearch page.
ldaptor-0.0.43/ldaptor/apps/webui/iwebui.py 0000644 0001750 0001750 00000000214 10277134704 016730 0 ustar jan jan from twisted.python import components
class ICurrentDN(components.Interface):
"""Marker interface for current DN for Ldaptor-webui."""
ldaptor-0.0.43/ldaptor/apps/webui/defskin.py 0000644 0001750 0001750 00000003240 10402650176 017065 0 ustar jan jan import os
from zope.interface import implements
from webut.skin import iskin
from nevow import rend, loaders, tags, util, inevow, static
from formless import webform
class DefaultSkin(rend.Page):
implements(iskin.ISkin)
docFactory = loaders.xmlfile(
util.resource_filename('ldaptor.apps.webui', 'skin-default.html'))
stylesheets = [
'form.css',
'ldaptor.css',
]
def locateChild(self, ctx, segments):
if segments[0] == 'form.css':
return webform.defaultCSS, segments[1:]
if segments[0] == 'ldaptor.css':
dirname = os.path.abspath(os.path.dirname(__file__))
return (static.File(os.path.join(dirname, 'ldaptor.css')),
segments[1:])
else:
return None, ()
def render_title(self, ctx, data):
return ctx.tag.clear()[self.original.resource.title]
def render_head(self, ctx, data):
def links(l, path=None):
for filename in l:
href = filename
if path is not None:
href = path.child(href)
yield tags.link(rel="stylesheet",
type="text/css",
href=href)
ctx.tag.clear()
stylesheets = getattr(self, 'stylesheets', None)
if stylesheets is not None:
ctx.tag[links(stylesheets, path=self.original.pathToFiles)]
stylesheets = getattr(self.original.resource, 'stylesheets', None)
if stylesheets is not None:
ctx.tag[links(stylesheets)]
return ctx.tag
def render_content(self, ctx, data):
return self.original.content
ldaptor-0.0.43/ldaptor/apps/webui/delete.xhtml 0000644 0001750 0001750 00000002667 10402650176 017424 0 ustar jan jan
Title Goes Here
Ldaptor Delete Page
[foo|]
Status message goes here.
Remove ?
None
:
ldaptor-0.0.43/ldaptor/apps/webui/add.py 0000644 0001750 0001750 00000050445 10402650176 016203 0 ustar jan jan from zope.interface import implements
from twisted.internet import defer
from twisted.python import plugin
from webut.skin import iskin
from ldaptor.protocols.ldap import ldapsyntax, distinguishedname
from ldaptor.protocols.ldap import fetchschema
from ldaptor import numberalloc, interfaces
from ldaptor.apps.webui import iwebui
from ldaptor.apps.webui.uriquote import uriQuote, uriUnquote
from ldaptor.apps.webui.i18n import _
from ldaptor.apps.webui import i18n
import os
from nevow import rend, inevow, loaders, url, tags
from formless import annotate, webform, iformless, configurable
def mapNameToObjectClass(objectClasses, name):
name = name.upper()
objclass = None
for oc in objectClasses:
for ocName in oc.name:
if ocName.upper()==name:
objclass = oc
return objclass
def mapNameToAttributeType(attributeTypes, name):
name = name.upper()
attrtype = None
for at in attributeTypes:
for atName in at.name:
if atName.upper()==name:
attrtype = at
return attrtype
class UnknownAttributeType(Exception):
"""LDAP Attribute type not known"""
def __init__(self, name):
Exception.__init__(self)
self.name = name
def __str__(self):
return self.__doc__ + ': ' + repr(self.name)
class AddOCForm(configurable.Configurable):
def __init__(self, objectClasses):
super(AddOCForm, self).__init__(None)
structural = []
auxiliary = []
for oc in objectClasses:
if oc.type == 'STRUCTURAL':
structural.append(oc)
elif oc.type == 'AUXILIARY':
auxiliary.append(oc)
structural.sort()
auxiliary.sort()
class KludgeNevowChoice(object):
"""
A kludge that allows using Choice with both Nevow 0.3 and
newer.
"""
def __init__(self, oc):
self.name = oc.name
self.desc = oc.desc
def __str__(self):
"""
For Choice in Nevow 0.4 and newer. Nevow 0.3 will use
integer indexes. Actual stringification for display
purposes happens in strObjectClass.
"""
return self.name[0]
formFields = [
annotate.Argument('ctx',
annotate.Context()),
annotate.Argument('request',
annotate.Request()),
annotate.Argument('structuralObjectClass',
annotate.Choice(label=_('Object type to create'),
choices=[KludgeNevowChoice(x) for x in structural],
stringify=strObjectClass)),
]
for oc in auxiliary:
formFields.append(annotate.Argument(
'auxiliary_%s' % oc.name[0],
annotate.Boolean(label=oc.name[0],
description=oc.desc or '')))
self.formFields = formFields
def getBindingNames(self, ctx):
return ['add']
def bind_add(self, ctx):
return annotate.MethodBinding(
'add',
annotate.Method(arguments=self.formFields,
label=_('Add')),
action=_('Add'))
def add(self, ctx, request, structuralObjectClass, **kw):
assert structuralObjectClass is not None
structuralObjectClass = str(structuralObjectClass)
auxiliaryObjectClasses = []
for k,v in kw.items():
assert k.startswith('auxiliary_')
if k.startswith('auxiliary_'):
k = k[len('auxiliary_'):]
if v:
auxiliaryObjectClasses.append(k)
u = url.URL.fromContext(ctx)
u = u.child('manual').child('+'.join([structuralObjectClass]
+ auxiliaryObjectClasses))
return u
class AddForm(configurable.Configurable):
def __init__(self, chosenObjectClasses, attributeTypes, objectClasses):
super(AddForm, self).__init__(None)
self.chosenObjectClasses=chosenObjectClasses
self.nonUserEditableAttributeType_objectClass=[
oc.name[0] for oc in self.chosenObjectClasses]
self.attributeTypes=attributeTypes
self.objectClasses=objectClasses
self.formFields=self._getFormFields()
def _nonUserEditableAttributeType_getFreeNumber(self, attributeType, context):
cfg = context.locate(interfaces.ILDAPConfig)
entry = context.locate(inevow.ISession).getLoggedInRoot().loggedIn
client = entry.client
o=ldapsyntax.LDAPEntry(client=client,
dn=cfg.getBaseDN())
d=numberalloc.getFreeNumber(ldapObject=o,
numberType=attributeType,
min=1000)
d.addCallback(lambda x, a=attributeType: (a, [str(x)]))
return d
nonUserEditableAttributeType_uidNumber=_nonUserEditableAttributeType_getFreeNumber
nonUserEditableAttributeType_gidNumber=_nonUserEditableAttributeType_getFreeNumber
def _get_attrtype(self, name):
for a in self.attributeTypes:
for cur in a.name:
if name.upper() == cur.upper():
a.uiHint_multiline=0 #TODO
return a
raise UnknownAttributeType, name
def _one_formfield(self, attr, result, must=False):
attrtype = self._get_attrtype(attr)
name=attr
if must:
name=name+"*"
if attrtype.uiHint_multiline:
if attrtype.single_value:
typed = annotate.Text(label=name,
description=attrtype.desc or '',
required=must)
else:
typed = annotate.Text(label=name,
description=attrtype.desc or '',
required=must)
else:
if attrtype.single_value:
typed = annotate.String(label=name,
description=attrtype.desc or '',
required=must)
else:
# TODO maybe use a string field+button to add entries,
# multiselection list+button to remove entries?
typed = annotate.Text(label=name,
description=attrtype.desc or '',
required=must)
result.append(annotate.Argument('add_'+attr, typed))
def _getFormFields(self):
r=[]
r.append(annotate.Argument('context',
annotate.Context()))
process = {}
# TODO sort objectclasses somehow?
objectClasses = list(self.chosenObjectClasses)
objectClassesSeen = {}
self.nonUserEditableAttributes = []
while objectClasses:
objectClass = objectClasses.pop()
objclassName = objectClass.name[0]
if objectClassesSeen.has_key(objclassName):
continue
objectClassesSeen[objclassName]=1
for ocName in objectClass.sup or []:
objclass = mapNameToObjectClass(self.objectClasses, ocName)
assert objclass, "Objectclass %s must have schema" %objclassName
objectClasses.append(objclass)
for attr_alias in objectClass.must:
real_attr = self._get_attrtype(str(attr_alias))
if hasattr(self, 'nonUserEditableAttributeType_'+real_attr.name[0]):
self.nonUserEditableAttributes.append(real_attr.name[0])
else:
for attr in real_attr.name:
if not process.has_key(attr.upper()):
process[attr.upper()]=0
if not process[attr.upper()]:
self._one_formfield(attr, result=r, must=True)
for name in real_attr.name:
process[name.upper()]=1
for attr_alias in objectClass.may:
real_attr = self._get_attrtype(str(attr_alias))
if hasattr(self, 'nonUserEditableAttributeType_'+real_attr.name[0]):
self.nonUserEditableAttributes.append(real_attr.name[0])
else:
for attr in real_attr.name:
if not process.has_key(attr.upper()):
process[attr.upper()]=0
if not process[attr.upper()]:
self._one_formfield(attr, result=r)
for name in real_attr.name:
process[name.upper()]=1
assert [v==1 for k,v in process.items()], "TODO: %s"%process
return r
def getBindingNames(self, ctx):
return ['add']
def bind_add(self, ctx):
return annotate.MethodBinding(
'add',
annotate.Method(arguments=self.formFields,
label=_('Add')),
action=_('Add'))
def _textarea_to_list(self, t):
return filter(lambda x: x, [x.strip() for x in t.split("\n")])
def _getDNAttr(self):
attr_alias = self.chosenObjectClasses[0].must[0]
attrType = mapNameToAttributeType(self.attributeTypes, attr_alias)
assert attrType is not None
dn_attribute = attrType.name[0]
return dn_attribute
def add(self, context, **kw):
cfg = context.locate(interfaces.ILDAPConfig)
dnAttr = self._getDNAttr()
assert kw.has_key('add_'+dnAttr), 'Must have attribute dn %s points to.' % dnAttr
assert kw['add_'+dnAttr], 'Attribute %s must have value.' % 'add_'+dnAttr
# TODO ugly
rdn=distinguishedname.RelativeDistinguishedName(
attributeTypesAndValues=[
distinguishedname.LDAPAttributeTypeAndValue(attributeType=dnAttr,
value=kw['add_'+dnAttr]),
])
#TODO verify
changes = []
for k,v in kw.items():
if hasattr(self, "nonUserEditableAttributeType_"+k):
raise "Can't set attribute %s when adding." % k
elif k[:len("add_")]=="add_":
if not v:
continue
attrtype = self._get_attrtype(k[len("add_"):])
assert attrtype
if attrtype.single_value or attrtype.uiHint_multiline:
v=[v]
else:
v=self._textarea_to_list(v)
if v and [1 for x in v if x]:
attr=k[len("add_"):]
changes.append(defer.succeed((attr, v)))
#TODO
for attributeType in self.nonUserEditableAttributes:
thing=getattr(self, 'nonUserEditableAttributeType_'+attributeType)
if callable(thing):
changes.append(thing(attributeType, context))
else:
changes.append(defer.succeed((attributeType, thing)))
dl=defer.DeferredList(changes, fireOnOneErrback=1)
#dl.addErrback(lambda x: x[0]) # throw away index
def _pruneSuccessFlags(l):
r=[]
for succeeded,result in l:
assert succeeded
r.append(result)
return r
dl.addCallback(_pruneSuccessFlags)
dl.addCallback(self._process2, context, rdn, kw)
return dl
def _process2(self, changes, context, rdn, kw):
cfg = context.locate(interfaces.ILDAPConfig)
user = context.locate(inevow.ISession).getLoggedInRoot().loggedIn
if not changes:
return _("No changes!") #TODO
changes_desc=""
mod={}
for attr,new in changes:
if new:
if attr not in mod:
mod[attr]=[]
mod[attr].extend(new)
changes_desc=changes_desc+" adding %s: %s"%(repr(attr), ', '.join(map(repr, new)))
if not mod:
return _("No changes (2)!") #TODO
e = ldapsyntax.LDAPEntryWithClient(client=user.client,
dn=iwebui.ICurrentDN(context))
d = e.addChild(rdn, mod)
#d.addCallback(lambda e: "Added %s successfully." % e.dn)
d.addErrback(lambda reason: _("Failed: %s.") % reason.getErrorMessage())
return d
class ReallyAddPage(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Add Page')
addSlash = True
docFactory = loaders.xmlfile(
'add-really.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def data_header(self, ctx, data):
u=url.URL.fromContext(ctx)
u=u.parentdir().parentdir().parentdir().clear()
l=[]
l.append(tags.a(href=u.sibling("search"))[_("Search")])
l.append(tags.a(href=u.sibling("add"))[_("add new entry")])
return l
def render_form(self, context, data):
return webform.renderForms()
def render_passthrough(self, context, data):
return context.tag.clear()[data]
def render_status(self, context, data):
try:
obj = context.locate(inevow.IHand)
except KeyError:
return context.tag.clear()
e = interfaces.ILDAPEntry(obj, None)
if e is None:
return context.tag.clear()[obj]
u=url.URL.fromContext(context)
u=u.parentdir().parentdir().parentdir().clear()
return context.tag.clear()[
_("Added "),
tags.a(href=u.parentdir().child(e.dn).child("search"))[e.dn],
_(" successfully. "),
# TODO share implementation with entryLinks
'[',
tags.a(href=u.sibling('edit').child(uriQuote(e.dn)))[_('edit')],
'|',
tags.a(href=u.sibling('move').child(uriQuote(e.dn)))[_('move')],
'|',
tags.a(href=u.sibling('delete').child(uriQuote(e.dn)))[_('delete')],
'|',
tags.a(href=u.sibling('change_password').child(uriQuote(e.dn)))[_('change password')],
']',
]
render_i18n = i18n.render()
class SmartObjectAddPage(ReallyAddPage):
def __init__(self, smartObject):
super(SmartObjectAddPage, self).__init__()
self.smartObject = smartObject
def configurable_(self, context):
return self.smartObject
def render_overview(self, ctx, data):
return tags.invisible()
class ManualAddPage(ReallyAddPage):
def __init__(self,
structuralObjectClass,
auxiliaryObjectClasses,
attributeTypes,
objectClasses):
super(ManualAddPage, self).__init__()
self.structuralObjectClass = structuralObjectClass
self.auxiliaryObjectClasses = auxiliaryObjectClasses
self.attributeTypes = attributeTypes
self.objectClasses = objectClasses
def configurable_(self, context):
a = AddForm(chosenObjectClasses=[self.structuralObjectClass]
+ self.auxiliaryObjectClasses,
attributeTypes=self.attributeTypes,
objectClasses=self.objectClasses)
return a
def render_overview(self, ctx, data):
if self.auxiliaryObjectClasses:
return ctx.tag.clear()[
_('Using objectclasses %s and %s.') % (
self.structuralObjectClass.name[0],
', '.join([oc.name[0] for oc in self.auxiliaryObjectClasses]),
)]
else:
return ctx.tag.clear()[
_('Using objectclass %s.') % (
self.structuralObjectClass.name[0],
)]
def strObjectClass(oc):
if oc.desc is not None:
return '%s: %s' % (oc.name[0], oc.desc)
else:
return '%s' % (oc.name[0],)
class ChooseSmartObject(object):
def __init__(self, pluginNames):
self.plugins = list(pluginNames)
self.plugins.sort()
def getBindingNames(self, ctx):
return ['add']
def bind_add(self, ctx):
return annotate.MethodBinding(
'add',
annotate.Method(arguments=[
annotate.Argument('context', annotate.Context()),
annotate.Argument('smartObjectClass', annotate.Choice(choicesAttribute='plugins')),
],
label=_('Add')),
action=_('Add'))
def add(self, context, smartObjectClass):
request = context.locate(inevow.IRequest)
u = url.URL.fromContext(context)
return u.child('smart').child(smartObjectClass)
class AddPage(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Add Page')
addSlash = True
docFactory = loaders.xmlfile(
'add.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def __init__(self, attributeTypes, objectClasses):
super(AddPage, self).__init__()
self.attributeTypes = attributeTypes
self.objectClasses = objectClasses
def listPlugins(self):
for plug in plugin.getPlugIns('ldaptor.apps.webui.smartObject'):
yield plug.name
def havePlugins(self):
for plug in plugin.getPlugIns('ldaptor.apps.webui.smartObject'):
return True
return False
def getPlugin(self, name):
for plug in plugin.getPlugIns('ldaptor.apps.webui.smartObject'):
if plug.name == name:
return plug
raise KeyError, name
def data_header(self, ctx, data):
u=url.URL.fromContext(ctx)
u=u.parentdir().clear()
l=[]
l.append(tags.a(href=u.sibling("search"))[_("Search")])
return l
def configurable_objectClass(self, context):
return AddOCForm(self.objectClasses)
def render_objectClassForm(self, context, data):
return webform.renderForms('objectClass')
def configurable_smartObject(self, context):
return ChooseSmartObject(self.listPlugins())
def render_smartObjectForm(self, context, data):
if self.havePlugins():
return webform.renderForms('smartObject')
else:
return context.tag.clear()
def render_passthrough(self, context, data):
return context.tag.clear()[data]
def locateChild(self, request, segments):
ret = super(AddPage, self).locateChild(request, segments)
if ret != rend.NotFound:
return ret
if segments[0] == 'manual':
if not segments[1:]:
return rend.NotFound
path=segments[1]
unquoted=uriUnquote(path)
objectClasses = unquoted.split('+')
assert len(objectClasses) >= 1
structName=objectClasses[0]
structuralObjectClass = mapNameToObjectClass(self.objectClasses,
structName)
assert structuralObjectClass is not None, \
"objectClass %s must have schema"%structName
auxiliaryObjectClasses = []
for auxName in objectClasses[1:]:
oc = mapNameToObjectClass(self.objectClasses, auxName)
assert oc is not None, "objectClass %s must have schema"%oc
auxiliaryObjectClasses.append(oc)
r = ManualAddPage(structuralObjectClass=structuralObjectClass,
auxiliaryObjectClasses=auxiliaryObjectClasses,
attributeTypes=self.attributeTypes,
objectClasses=self.objectClasses)
return r, segments[2:]
elif segments[0] == 'smart':
if not segments[1:]:
return rend.NotFound
name = segments[1]
if not name:
return rend.NotFound
plug = self.getPlugin(name)
module = plug.load()
add = module.add()
r = SmartObjectAddPage(add)
return r, segments[2:]
else:
return rend.NotFound
render_i18n = i18n.render()
def getResource(baseObject, request):
entry = request.getSession().getLoggedInRoot().loggedIn
client = entry.client
d = fetchschema.fetch(client, baseObject)
def cbAddPage(schema):
attributeTypes, objectClasses = schema
return AddPage(attributeTypes, objectClasses)
d.addCallback(cbAddPage)
return d
ldaptor-0.0.43/ldaptor/apps/webui/__init__.py 0000644 0001750 0001750 00000000060 07516345760 017212 0 ustar jan jan """
The HTML/HTTP user interface to Ldaptor
"""
ldaptor-0.0.43/ldaptor/apps/webui/mass_change_password-really.xhtml 0000644 0001750 0001750 00000003577 10402650176 023643 0 ustar jan jan
Title Goes Here
Ldaptor Mass Password Change Page
[foo|]
ldaptor-0.0.43/ldaptor/apps/webui/add.xhtml 0000644 0001750 0001750 00000001660 10402650176 016702 0 ustar jan jan
Title Goes Here
Ldaptor Add Page
[foo|]
ldaptor-0.0.43/ldaptor/apps/webui/change_service_passwords.xhtml 0000644 0001750 0001750 00000004510 10207114505 023213 0 ustar jan jan
Current service passwords
Service
Actions
Service name here
ldaptor-0.0.43/ldaptor/apps/webui/login.xhtml 0000644 0001750 0001750 00000002040 10402650176 017253 0 ustar jan jan
Title Goes Here
ldaptor-0.0.43/ldaptor/apps/webui/mass_change_password.xhtml 0000644 0001750 0001750 00000001364 10402650176 022345 0 ustar jan jan
Title Goes Here
Ldaptor Mass Password Change Page
Missing filter to use.You need to use thesearch page.
ldaptor-0.0.43/ldaptor/apps/webui/main.py 0000644 0001750 0001750 00000003161 10402650176 016370 0 ustar jan jan from zope.interface import implements
from twisted.cred import portal, checkers, credentials
from nevow import guard, inevow
from webut.skin import skin
from ldaptor.config import LDAPConfig
from ldaptor.apps.webui import gadget, defskin
from ldaptor.checkers import LDAPBindingChecker
class TODOGetRidOfMeRealm:
implements(portal.IRealm)
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def requestAvatar(self, avatarId, mind, *interfaces):
if inevow.IResource not in interfaces:
raise NotImplementedError, "no interface"
if avatarId is checkers.ANONYMOUS:
resource = gadget.LdaptorWebUIGadget(None, *self.args, **self.kwargs)
resource.realm = self
return (inevow.IResource,
resource,
lambda: None)
else:
resource = gadget.LdaptorWebUIGadget(avatarId, *self.args, **self.kwargs)
resource.realm = self
return (inevow.IResource,
resource,
lambda: None)
def getResource(cfg=None, skinFactory=None):
"""Get a resource for the Ldaptor-webui app."""
if cfg is None:
cfg = LDAPConfig()
checker = LDAPBindingChecker(cfg)
realm = TODOGetRidOfMeRealm(config=cfg)
porta = portal.Portal(realm)
porta.registerChecker(checkers.AllowAnonymousAccess(), credentials.IAnonymous)
porta.registerChecker(checker)
mainResource = guard.SessionWrapper(porta)
if skinFactory is None:
skinFactory = defskin.DefaultSkin
return skin.Skinner(skinFactory, mainResource)
ldaptor-0.0.43/ldaptor/apps/webui/mass_change_password.py 0000644 0001750 0001750 00000012426 10402650176 021642 0 ustar jan jan from zope.interface import implements
from twisted.internet import defer
from webut.skin import iskin
from ldaptor.protocols.ldap import ldapsyntax
from ldaptor import generate_password
from ldaptor.apps.webui.uriquote import uriUnquote
from twisted.internet import reactor
from ldaptor.apps.webui.i18n import _
from ldaptor.apps.webui import i18n
import os
from nevow import rend, inevow, loaders, url, tags
from formless import annotate, webform, configurable
class MassPasswordChangeStatus(object):
def __init__(self, deferlist):
super(MassPasswordChangeStatus, self).__init__()
self.deferlist = deferlist
class MassPasswordChangeForm(configurable.Configurable):
def __init__(self, ldapObjects):
super(MassPasswordChangeForm, self).__init__(None)
self.ldapObjects = {}
for o in ldapObjects:
assert o.dn not in self.ldapObjects
self.ldapObjects[o.dn] = o
self.formFields=self._getFormFields()
def _getFormFields(self):
r=[]
r.append(annotate.Argument('request',
annotate.Request()))
for dn, e in self.ldapObjects.items():
r.append(annotate.Argument('dn_%s' % dn,
annotate.Boolean(label=dn,
description=e)))
return r
def getBindingNames(self, ctx):
return ['generate']
def bind_generate(self, ctx):
return annotate.MethodBinding(
'generatePasswords',
annotate.Method(arguments=self.formFields,
label=_('Generate passwords')),
action=_('Generate passwords'))
def generatePasswords(self, request, **kw):
entries = []
for k,v in kw.items():
if not k.startswith('dn_'):
continue
k = k[len('dn_'):]
if not v:
continue
assert k in self.ldapObjects
entries.append(self.ldapObjects[k])
if not entries:
return _('No passwords to change.')
d=generate_password.generate(reactor, len(entries))
def _gotPasswords(passwords, entries):
assert len(passwords)==len(entries)
l=[]
for entry, pwd in zip(entries, passwords):
d=entry.setPassword(newPasswd=pwd)
def _cb(entry, pwd):
return (entry, pwd)
d.addCallback(_cb, pwd)
l.append(d)
return defer.DeferredList(l,
consumeErrors=True)
d.addCallback(_gotPasswords, entries)
d.addCallback(MassPasswordChangeStatus)
return d
class ReallyMassPasswordChangePage(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Mass Password Change Page')
addSlash = True
docFactory = loaders.xmlfile(
'mass_change_password-really.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def __init__(self, entries):
super(ReallyMassPasswordChangePage, self).__init__()
self.entries = entries
def data_header(self, ctx, data):
u=url.URL.fromContext(ctx)
u=u.parentdir().parentdir().clear()
l=[]
l.append(tags.a(href=u.sibling("search"))[_("Search")])
l.append(tags.a(href=u.sibling("add"))[_("add new entry")])
return l
def configurable_(self, context):
request = context.locate(inevow.IRequest)
return MassPasswordChangeForm(self.entries)
def render_form(self, context, data):
return webform.renderForms()[context.tag]
def render_passthrough(self, context, data):
return context.tag.clear()[data]
def render_status(self, context, data):
try:
obj = context.locate(inevow.IHand)
except KeyError:
return context.tag.clear()
if not isinstance(obj, MassPasswordChangeStatus):
return context.tag.clear()[obj]
dl = tags.dl(compact="compact")
context.tag.clear()[dl]
for success, x in obj.deferlist:
if success:
entry, pwd = x
dl[tags.dt[entry.dn],
tags.dd[pwd]]
else:
context.tag[_('Failed: '), x.getErrorMessage()]
return context.tag
render_i18n = i18n.render()
class MassPasswordChangePage(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Mass Password Change Page')
addSlash = True
docFactory = loaders.xmlfile(
'mass_change_password.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def __init__(self, baseObject):
super(MassPasswordChangePage, self).__init__()
self.baseObject = baseObject
def render_url(self, context, data):
u = url.URL.fromContext(context)
return context.tag(href=u.parentdir().child('search'))
def childFactory(self, context, name):
entry = inevow.ISession(context).getLoggedInRoot().loggedIn
filt = uriUnquote(name)
e=ldapsyntax.LDAPEntry(client=entry.client,
dn=self.baseObject)
d=e.search(filterText=filt, sizeLimit=20)
d.addCallback(ReallyMassPasswordChangePage)
return d
render_i18n = i18n.render()
ldaptor-0.0.43/ldaptor/apps/webui/move.xhtml 0000644 0001750 0001750 00000001341 10402650176 017114 0 ustar jan jan
Title Goes Here
Ldaptor Move Page
Missing DN to move.You need to use thesearch page.
ldaptor-0.0.43/ldaptor/apps/webui/add-really.xhtml 0000644 0001750 0001750 00000002033 10402650176 020163 0 ustar jan jan
Title Goes Here
Ldaptor Add Page
[foo|]
Overview of what is happening might be here.
ldaptor-0.0.43/ldaptor/apps/webui/delete.py 0000644 0001750 0001750 00000010752 10402650176 016712 0 ustar jan jan from zope.interface import implements
from webut.skin import iskin
from ldaptor.protocols.ldap import ldapsyntax, distinguishedname
from ldaptor.apps.webui.uriquote import uriUnquote
from ldaptor.apps.webui.i18n import _
from ldaptor.apps.webui import i18n, iwebui
from ldaptor import weave
import os
from nevow import rend, inevow, loaders, url, tags
from formless import annotate, webform, iformless
class ErrorWrapper:
def __init__(self, value):
self.value = value
class ConfirmDelete(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Delete Page')
docFactory = loaders.xmlfile(
'delete.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def __init__(self, dn):
super(ConfirmDelete, self).__init__()
self.dn = dn
def getBindingNames(self, ctx):
return ['delete']
def bind_delete(self, ctx):
return annotate.MethodBinding(
'delete',
annotate.Method(arguments=[
annotate.Argument('ctx', annotate.Context()),
],
label=_('Confirm delete')),
action=_('Delete'))
def delete(self, ctx):
request = inevow.IRequest(ctx)
user = request.getSession().getLoggedInRoot().loggedIn
e=ldapsyntax.LDAPEntry(client=user.client,
dn=self.dn)
d=e.delete()
def cb(dummy):
basedn = iwebui.ICurrentDN(ctx)
while (basedn != ''
and self.dn.contains(basedn)):
basedn = basedn.up()
u=url.URL.fromContext(ctx)
u=u.parentdir().parentdir()
if basedn != '':
u=u.child(basedn).child('search')
request.setComponent(iformless.IRedirectAfterPost, u)
return _("Deleted %s.") % self.dn
def eb(fail):
return _("Failed: %s.") % fail.getErrorMessage()
d.addCallbacks(cb, eb)
return d
def data_status(self, ctx, data):
try:
return ctx.locate(inevow.IStatusMessage)
except KeyError:
return None
def render_if(self, context, data):
r=context.tag.allPatterns(str(bool(data)))
return context.tag.clear()[r]
def data_entry(self, context, data):
user = context.locate(inevow.ISession).getLoggedInRoot().loggedIn
assert user
entry = ldapsyntax.LDAPEntry(client=user.client, dn=self.dn)
d = entry.fetch()
d.addErrback(ErrorWrapper)
return d
def render_error_or_pass(self, context, data):
if isinstance(data, ErrorWrapper):
return context.tag.clear() \
[ tags.strong(style="color: red;") \
[ _('An error occurred: '),
data.value.getErrorMessage(),
]
]
else:
return context.tag
def data_dn(self, context, data):
return self.dn
def render_form(self, context, data):
return webform.renderForms()
def render_passthrough(self, context, data):
return context.tag.clear()[data]
def data_header(self, ctx, data):
u=url.URL.fromContext(ctx).up().clear()
l=[]
l.append(tags.a(href=u.sibling("search"))[_("Search")])
l.append(tags.a(href=u.sibling("add"))[_("add new entry")])
l.append(tags.a(href=u.sibling("edit").child(str(self.dn)))[_("edit")])
return l
def render_keyvalue(self, context, data):
return weave.keyvalue(context, data)
def render_keyvalue_item(self, context, data):
return weave.keyvalue_item(context, data)
render_i18n = i18n.render()
class GetDN(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Delete Page')
addSlash = True
docFactory = loaders.xmlfile(
'delete-nodn.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def render_url(self, context, data):
u = url.URL.fromContext(context)
return context.tag(href=u.parentdir().child('search'))
def childFactory(self, context, name):
unquoted=uriUnquote(name)
try:
dn = distinguishedname.DistinguishedName(stringValue=unquoted)
except distinguishedname.InvalidRelativeDistinguishedName, e:
# TODO There's no way to throw a FormException at this stage.
return None
r=ConfirmDelete(dn=dn)
return r
render_i18n = i18n.render()
def getResource():
return GetDN()
ldaptor-0.0.43/ldaptor/apps/webui/uriquote.py 0000644 0001750 0001750 00000000306 10344535643 017325 0 ustar jan jan import urllib
def uriQuote(uri):
uri=str(uri)
for c in '%;/?:@&+$':
uri=uri.replace(c, '%%%02x'%ord(c))
return uri
def uriUnquote(q):
q=str(q)
return urllib.unquote(q)
ldaptor-0.0.43/ldaptor/apps/webui/move.py 0000644 0001750 0001750 00000002367 10402650176 016421 0 ustar jan jan from zope.interface import implements
import os
from webut.skin import iskin
from ldaptor.protocols.ldap import ldapsyntax
from ldaptor.apps.webui.uriquote import uriUnquote
from nevow import rend, loaders, url, inevow
from ldaptor.apps.webui.i18n import _
from ldaptor.apps.webui import i18n
from ldaptor.apps.webui.search import IMove
class MovePage(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Move Page')
addSlash = True
docFactory = loaders.xmlfile(
'move.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def render_url(self, ctx, data):
u = url.URL.fromContext(ctx)
return ctx.tag(href=u.parentdir().child('search'))
def childFactory(self, context, name):
dn = uriUnquote(name)
session = inevow.ISession(context)
userEntry = session.getLoggedInRoot().loggedIn
move = session.getComponent(IMove)
if move is None:
move = []
session.setComponent(IMove, move)
e = ldapsyntax.LDAPEntryWithClient(dn=dn,
client=userEntry.client)
move.append(e)
u = url.URL.fromContext(context).sibling('search')
return u
render_i18n = i18n.render()
ldaptor-0.0.43/ldaptor/apps/webui/config.py 0000644 0001750 0001750 00000001334 10344407651 016714 0 ustar jan jan from ldaptor import config
def _getSearchFields():
cfg = config.loadConfig()
if not cfg.has_section('webui'):
return
for raw in cfg.options('webui'):
if not raw:
continue
l=raw.split(None, 2)
if l[0].lower() == 'search-field':
pri, name = l[1:]
pri = int(pri)
yield (pri, name, raw)
def getSearchFieldByName(name, vars):
for pri, n, raw in _getSearchFields():
if n == name:
cfg = config.loadConfig()
val = cfg.get('webui', raw, raw=None, vars=vars)
return val
return None
def getSearchFieldNames():
l = list(_getSearchFields())
l.sort()
return [name for pri,name,raw in l]
ldaptor-0.0.43/ldaptor/apps/webui/ldaptor.css 0000644 0001750 0001750 00000002101 10402650176 017242 0 ustar jan jan #moveEntries
{
width: 70%;
border: 1px solid gray;
position: relative;
}
#moveEntries li
{
height: 1.5em;
}
#moveEntries .moveForms
{
display: inline;
margin-right: 0;
position: absolute;
right: 1em;
}
#moveEntries .moveForms form
{
display: inline;
}
#moveEntries .moveForms form input
{
font-size: 0.7em;
}
#ldaptorPage-mass-change-password .freeform-label { float: none; width: auto; }
#ldaptorPage-mass-change-password .freeform-description { font-size: 80%; }
input:focus {
border-color: black;
}
fieldset,
.emulate-fieldset {
border-style: groove; border-width: 2px; border-color: #F7F7F8;
padding: 0.5em;
}
.zebra-even {
background-color: #edf3fe;
}
.zebra-odd {
background-color: #ffffff;
}
.ldaptor-service-passwords form {
padding: 0.5em;
}
.ldaptor-service-passwords table.emulate-fieldset {
width: 100%;
}
.ldaptor-service-passwords table.emulate-fieldset thead tr th {
text-align: left;
padding-left: 0.5em;
padding-right: 0.5em;
}
.ldaptor-service-passwords table.emulate-fieldset .ldaptor-svcpass-name {
padding: 0.5em;
}
ldaptor-0.0.43/ldaptor/apps/webui/gadget.py 0000644 0001750 0001750 00000011456 10402650176 016705 0 ustar jan jan from zope.interface import implements
from webut.skin import iskin
from ldaptor.apps.webui import login, search, edit, add, delete, mass_change_password, change_password, move, iwebui
from ldaptor.protocols.ldap import distinguishedname
from ldaptor.apps.webui.uriquote import uriUnquote
from ldaptor import interfaces
from ldaptor.apps.webui.i18n import _
from ldaptor.apps.webui import i18n
from nevow import rend, loaders, url, static, inevow
from formless import annotate, webform, iformless
import os
class LdaptorWebUIGadget2(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Web Interface')
addSlash = True
def __init__(self, baseObject):
super(LdaptorWebUIGadget2, self).__init__()
self.baseObject = baseObject
def child_(self, context):
return inevow.IRequest(context).URLPath().child('search')
def child_search(self, context):
return search.getSearchPage()
def child_edit(self, context):
if not inevow.ISession(context).getLoggedInRoot().loggedIn:
return login.LoginPage([str(self.baseObject), 'edit'])
return edit.EditPage()
def child_move(self, context):
if not inevow.ISession(context).getLoggedInRoot().loggedIn:
return login.LoginPage([str(self.baseObject), 'move'])
return move.MovePage()
def child_add(self, context):
if not inevow.ISession(context).getLoggedInRoot().loggedIn:
return login.LoginPage([str(self.baseObject), 'add'])
return add.getResource(baseObject=self.baseObject,
request=inevow.IRequest(context))
def child_delete(self, context):
if not inevow.ISession(context).getLoggedInRoot().loggedIn:
return login.LoginPage([str(self.baseObject), 'delete'])
return delete.getResource()
def child_mass_change_password(self, context):
if not inevow.ISession(context).getLoggedInRoot().loggedIn:
return login.LoginPage([str(self.baseObject), 'mass_change_password'])
return mass_change_password.MassPasswordChangePage(
baseObject=self.baseObject)
def child_change_password(self, context):
if not inevow.ISession(context).getLoggedInRoot().loggedIn:
return login.LoginPage([str(self.baseObject), 'change_password'])
return change_password.getResource()
class LDAPDN(annotate.String):
def coerce(self, *a, **kw):
val = super(LDAPDN, self).coerce(*a, **kw)
try:
dn = distinguishedname.DistinguishedName(stringValue=val)
except distinguishedname.InvalidRelativeDistinguishedName, e:
raise annotate.InputError, \
"%r is not a valid LDAP DN: %s" % (val, e)
return dn
class LdaptorWebUIGadget(rend.Page):
implements(iskin.ISkinnable)
title = _('Ldaptor Web Interface')
addSlash = True
docFactory = loaders.xmlfile(
'basedn.xhtml',
templateDir=os.path.split(os.path.abspath(__file__))[0])
def __init__(self, loggedIn, config):
super(LdaptorWebUIGadget, self).__init__()
self.loggedIn = loggedIn
self.config = config
def getBindingNames(self, ctx):
return ['go']
def bind_go(self, ctx):
return annotate.MethodBinding(
'go',
annotate.Method(arguments=[
annotate.Argument('ctx', annotate.Context()),
annotate.Argument('baseDN', LDAPDN(
label=_('Base DN'),
description=_("The top-level LDAP DN you want"
" to browse, e.g. dc=example,dc=com"))),
],
label=_('Go')),
action=_('Go'))
def go(self, ctx, baseDN):
u = url.URL.fromContext(ctx)
u = u.child(str(baseDN))
return u
def render_form(self, context, data):
return webform.renderForms()
def locateChild(self, ctx, segments):
ret = super(LdaptorWebUIGadget, self).locateChild(ctx, segments)
if ret != rend.NotFound:
return ret
path = segments[0]
unquoted=uriUnquote(path)
try:
dn = distinguishedname.DistinguishedName(stringValue=unquoted)
except distinguishedname.InvalidRelativeDistinguishedName, e:
# TODO There's no way to throw a FormException at this stage.
u = url.URL.fromContext(ctx)
# TODO protect against guard bug, see
# http://divmod.org/users/roundup.twistd/nevow/issue74
u = u.child('')
# TODO freeform_post!configurableName!methodName
u.add('basedn', path)
return u, []
r=LdaptorWebUIGadget2(baseObject=dn)
ctx.remember(self.config, interfaces.ILDAPConfig)
ctx.remember(dn, iwebui.ICurrentDN)
return r, segments[1:]
render_i18n = i18n.render()
ldaptor-0.0.43/ldaptor/apps/webui/i18n.py 0000644 0001750 0001750 00000000276 10345073240 016224 0 ustar jan jan from nevow.inevow import ILanguages
from nevow.i18n import I18NConfig
from nevow import i18n
_ = i18n.Translator(domain='ldaptor-webui')
def render():
return i18n.render(translator=_)
ldaptor-0.0.43/ldaptor/apps/webui/edit.xhtml 0000644 0001750 0001750 00000001341 10402650176 017073 0 ustar jan jan
Title Goes Here
Ldaptor Edit Page
Missing DN to edit.You need to use thesearch page.
ldaptor-0.0.43/ldaptor/apps/webui/change_password.xhtml 0000644 0001750 0001750 00000002406 10402650176 021320 0 ustar jan jan
Title Goes Here