Welcome

Welcome on my blog
I'll try to contribute my -modest- knowledge to the community.
Here you'll find samples of python twisted code but also some network configurations.

Hoping you'll find it usefull.

gracefully
cat 'tonthon\'s brain' > /dev/null
Tonthon

Tuesday, February 8, 2011

Ldaptor : ldap with twisted, client side

Introduction

Ldaptor is an ldap library build on top of python and twisted, it provides :

  • LDAP client logic

  • Separately-accessible LDAP and BER protocol message generation/parsing

  • ASCII-format LDAP filter generation and parsing

  • LDIF format data generation

  • Samba password changing logic



Here we will use the client-side tools to retrieve datas from our ldap server.
We will use the ldap server written there :
ldaptor : ldap with twisted, server-side


Quick overview

  • The connector
    A connector is used to wrap the ldap client, this connector looks up DNS SRV records.

    >>> from ldaptor.protocols.ldap.ldapconnector import LDAPClientCreator
    >>> from ldaptor.protocols.ldap.ldapclient import LDAPClient
    >>> from twisted.internet import reactor
    >>> clientBuilder = LDAPClientCreator(reactor, LDAPClient)
    >>> print clientBuilder
    <ldaptor.protocols.ldap.ldapconnector.LDAPClientCreator instance at 0xb753830c>
    >>>

    You can then build clients for different ldap servers.

  • The DN object

    >>> from ldaptor.protocols.ldap.distinguishedname import DistinguishedName as DN
    >>> dn = DN('dc=example,dc=com')
    >>> print dn
    dc=example,dc=com
    >>> print dn.getDomainName()
    'example.com'
    >>>

  • Bind to a remote server
    You then build a client for that given DN

    >>> binded_client = clientBuilder.connectAnonymously(dn, overrides={dn:('localhost', 8080)})
    >>> print binded_client
    <Deferred at 0xa44268c>
    >>>

    The connectAnonymously method connect to the remote host and binds automatically.
    Note : Here we override the remote's adress to avoid DNS lookup.

    To make authenticated bindings :

    >>> userdn = DN('uid=esteban,ou=people,dc=example,dc=fr')
    >>> client = clientBuilder.connect(dn, {dn:('localhost', 8080)})
    >>> client.addCallback(lambda client:LDAPEntry(client=client,
    dn=userdn).bind(password))
    >>>

    We first connect to the remote and then build an ldapentry with our userdn which we bind with the given password.


Here is a full example retrieving datas from the previous-described server.
Put all this stuff into a file you call client.py, run the server and launch a `python client.py`

#!/usr/bin/python
#-*-coding:utf-8-*-
"""
Simple Ldaptor client
"""
import sys

from twisted.python import log
from twisted.internet import reactor

from ldaptor.protocols.ldap.distinguishedname import DistinguishedName as DN
from ldaptor.ldapfilter import parseFilter
from ldaptor.protocols.ldap.ldapsyntax import LDAPEntry
from ldaptor.protocols.ldap.ldapconnector import LDAPClientCreator
from ldaptor.protocols.ldap.ldapclient import LDAPClient


class Client:
"""
Simple Ldap client to retrieve user's informations
"""
def __init__(self, dn, host, port):
dn = DN(dn)
self.config = dict(base=dn,
server={dn:(host, port)})
self.clientBuilder = LDAPClientCreator(reactor, LDAPClient)
def bind(self):
"""
returns a deferred anonymous connection
"""
return self.clientBuilder.connectAnonymously(
self.config['base'],
self.config['server'])
@staticmethod
def _unbindAndReturn(result, client):
"""
Unbind the binded client
"""
client.unbind()
return result
def buildBase(self, client):
"""
return the base ldap entry the search will
be run from
"""
return LDAPEntry(client=client, dn=self.config['base'])
def _search(self, client, login):
"""
Launch our search
"""
ldapFilter = parseFilter('(uid=%s)' % login)
base = self.buildBase(client)
return base.search(filterObject=ldapFilter).addBoth(
self._unbindAndReturn, client)
@staticmethod
def _formatRes(results, attributes):
"""
Format results to get only the attributes we wanted to keep
"""
for result in results:
yield dict([(attr, list(result.get(attr)))
for attr in attributes])
def getUser(self, login, attributes):
"""
Public method used to retrieve ldap user's infos
"""
deferred = self.bind()
deferred.addCallback(self._search, login)
deferred.addCallback(self._formatRes, attributes)
return deferred

def main():
log.startLogging(sys.stderr)
def printRes(results):
for res in results:
log.msg(res)
client = Client('dc=fr', '127.0.0.1', 8080)
datas = client.getUser('yoen', ('mail','sn'))
datas.addCallback(printRes)
reactor.callLater(3, reactor.stop)
reactor.run()

if __name__ == '__main__':
main()

No comments:

Post a Comment