[Twisted-Python] advice on asynchronous LDAP?
jean-marc pouchoulon
jean-marc.pouchoulon at ac-montpellier.fr
Tue Nov 14 00:10:08 MST 2006
Shimon Rura wrote:
> Hi folks,
>
Hello
> I'm a newbie writing a twisted server that needs to access an LDAP
> server. I started by using python-ldap, which worked fine and is well
> documented, but doesn't seem to have support for a callback mechanism
> that would make it appropriate for a twisted app. So I switched to
> ldaptor, which fits the twisted model, but doesn't seem to have much
> documentation.
I tried to use it but it worked only with twisted 1.3
>
> I'm looking for advice from people who have some familiarity with
> writing twisted apps that include an LDAP client. Ideally, I'd like
> to find either:
>
> (1) a way to use the standard python-ldap library in a multitasking
> twisted server (i.e. without busy wait; polling at timed intervals is
> a possibility but also seems bad), or
The way I found was to use python ldap and deferToThread.
This is not really in the "asynchronous spirit of twisted " but it works.
Here an example I used to make a small sendmail X map lookup:
from twisted.application import internet, service
from twisted.internet import protocol,reactor, defer, threads
from twisted.internet.protocol import Protocol
from twisted.protocols import basic
import ldap
class MapProtocol(Protocol):
def dataReceived(self, Mel):
d = threads.deferToThread(self.factory._lire_annuaire_ldap,Mel)
d.addCallback(self._cb)
d.addErrback(self._eb)
def _cb(self, result):
self.transport.write(result)
def _eb(self, error):
print error
self.transport.loseConnection()
class MapFactory(protocol.ServerFactory):
protocol = MapProtocol
def __init__(self, servers,who, cred, mydomains, dictstatus):
# directory
self.ldapservers = ldapservers
self.who = who
self.cred = cred
self.mydomains = mydomains
self.NOTFOUND = dictstatus['NOTFOUND']
self.TEMP = dictstatus['PERM']
def _lire_annuaire_ldap(self,mel):
""" lookup directory server retourne RHS """
def _bind2ldap(servers,who="",cred=""):
""" Trouve une serveur ldap dispo dans la liste qui lui est passé """
status = False
for server in servers:
urildap = "ldap://" + server
l = ldap.initialize(urildap)
l.protocol_version=ldap.VERSION3
try:
resultbind = l.simple_bind_s(who,cred)
status = True
break
except ldap.LDAPError,e :
continue
return(status,l)
uid = ''
mailhost = ''
aretourner = self.NOTFOUND
statusldap = False # directory server est disponible ?
# Nom de la map
# si on en a plusieurs dans le futur
nommap = mel.split()[0].split(':')[1]
# map LHS
mel = mel.split()[1][:-1]
# our domain or not ?
try:
mydomain = mel.split('@')[1]
except IndexError,e:
mydomain = 'mydomain'
if mydomain in self.mydomains:
statusldap, maconn = _bind2ldap(self.ldapservers,self.who,self.cred)
if statusldap:
marequete = '(|(mail=' + mel + ')(mailalternateaddress=' + mel +')(mailequivalentaddress=' + mel
+ '))'
result_data = maconn.search_s("dc=...", ldap.SCOPE_SUBTREE, marequete , ['uid', 'mailhost']
)
if len(result_data) > 0:
try:
uid = ''.join(result_data[0][1]['uid'])
except KeyError:
print 'error clef:%s' % mel
uid = mel.split("@")[0]
mailhost = ''.join(result_data[0][1]['mailhost'])
status = 'OK '
reponse = status + '<' + uid + '@' + mailhost + '>'
aretourner = str(len(reponse)) + ":" + reponse + ','
else:
aretourner = self.NOTFOUND
else:
aretourner = self.PERM
else:
aretourner = self.NOTFOUND
return (aretourner)
# Status de lookup "fixe"
dictstatus = {'NOTFOUND' : '8:NOTFOUND,', 'PERM' : '4:PERM,'}
# servers/user/pass necessaire au bind
#
server = ["ldap1","ldap2"]
binddn = ""
passwd = ""
mydomains = ["mydomain"]
application = service.Application('mapsmx', uid=663, gid=663)
factory = MapFactory(server,binddn,passwd,mydomains,dictstatus)
internet.TCPServer(8090, factory).setServiceParent(
service.IServiceCollection(application))
HTH
jmp
More information about the Twisted-Python
mailing list