"""LDAP protocol proxy server"""
from twisted.internet import reactor, defer
from ldaptor.protocols.ldap import ldapserver, ldapconnector, ldapclient
from ldaptor.protocols import pureldap
[docs]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:
self.client.send_multiResponse(request, self._gotResponse, reply)
# TODO handle errbacks from the deferred above
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
[docs] 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)
[docs] 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
[docs] def handleUnknown(self, request, controls, reply):
d = defer.succeed(request)
d.addCallback(self._handleUnknown, controls, reply)
return d
[docs] 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()