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 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
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 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
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(), ''))
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, ''))
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 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 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)
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))
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 Exception( "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
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)))
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())))
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, ''))