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