Contact Us
Python BlogDjango BlogBig DataSearch for Kubernetes AWS BlogCloud Services



A More Flexible and Intuitive Python-Based LDAP Library

August 30, 2016

While working on a project recently, I stumbled across a new(ish) LDAP Library for Python. I've never had a problem with the old one, but started looking into the new library out of curiosity. This new library is easier to work with, and I encourage anyone using LDAP to give it a try.

Pure Python

This new library is ldap3. It serves the same purpose as the more well known Python-LDAP library, which was an interface to the C LDAP library, from OpenLDAP. Ldap3 is just straight Python, which means all it really needs is Python to run. There's no compiling, no need to have OpenLDAP installed, or anything like that.

Way Better Search Results

Searching is no more or less difficult with ldap3, but dealing with search results is a hundred times better than the old library. It's so much more flexible and more intuitive. Here’s an example showing both libraries:

import ldap
import ldap3
from pprint import pprint

server_uri = 'ldap://'
search_base = 'ou=users,dc=example,dc=com'
search_filter = '(uid=rob)'
attrs = ['*']

# Using Python-LDAP
connection = ldap.initialize(server_uri)
results = connection.search_s(

# [('uid=rob,ou=users,dc=example,dc=com',
# {'cn': ['Rob McBroom'],
# 'displayName': ['Rob McBroom'],
# 'gidNumber': ['99999'],
# 'givenName': ['Rob'],
# 'homeDirectory': ['/home/rob'],
# 'homePhone': ['800-555-1212'],
# 'host': ['*'],
# 'loginShell': ['/bin/zsh'],
# 'mail': [''],
# 'objectClass': ['top', 'inetOrgPerson', 'hostObject', 'posixAccount'],
# 'sn': ['McBroom'],
# 'uid': ['rob'],
# 'uidNumber': ['99999']})]

# Using ldap3
server = ldap3.Server(server_uri)
with ldap3.Connection(server, auto_bind=True) as conn:, search_filter, attributes=attrs)

# [DN: uid=rob,ou=users,dc=example,dc=com
# cn: Rob McBroom
# displayName: Rob McBroom
# gidNumber: 99999
# givenName: Rob
# homeDirectory: /home/rob
# homePhone: 800-555-1212
# host: *
# loginShell: /bin/zsh
# mail:
# objectClass: top
# inetOrgPerson
# hostObject
# posixAccount
# sn: McBroom
# uid: rob
# uidNumber: 99999
# ]

Note what we can do with these results.

>>> rob = conn.entries[0]
# property access
>>> rob.loginShell
loginShell: /bin/zsh
# dictionary access
>>> rob['loginShell']
loginShell: /bin/zsh
# dictionary access is not picky
>>> rob['loginshell']
loginShell: /bin/zsh
>>> rob['login shell']
loginShell: /bin/zsh
>>> rob['Login Shell']
loginShell: /bin/zsh
# obtain an attribute's value
>>> rob.loginShell.value

Getting the same value from Python-LDAP would be like this:

>>> rob = results[0]
>>> rob[1]['loginShell'][0]


Adding Entries Made Easier

Updating existing entries isn't that different between the two libraries, but adding entries is much easier with ldap3. You just need to construct a Python dictionary that looks like the entry you want to end up with.

A More Open Library

The traditional Python-LDAP doesn't have Python 3 support, and isn't as easy to contribute to. The maintainer still keeps it in a CVS repository that only they have access to, so anyone who wants to contribute has to email them about the changes, which may or may not be implemented. The new LDAP library works with Python 2 and Python 3 without needing to do anything special. It’s on GitHub so everyone can see it and can open issues, pull requests, etc.

Switch or Stick with the Old?

For all the great things that come with ldap3, you may want to stick with the old library if you have an existing very large code base that uses it. Also, things that were working in the traditional library may not work in the new library (e.g. Kerberos and certificate authentication, failover between multiple servers, etc.): I haven't had a chance to test them all yet.

Have you used the new ldap3 library? Have you noticed any issues you're working on? Feel free to reach out to me!

Tell us about the goals you’re trying to accomplish.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.