LDAP Integration in Python — Core Concepts
What LDAP does
LDAP (Lightweight Directory Access Protocol) is a protocol for reading and writing data in a directory service. Think of it as a specialized database optimized for frequent reads and infrequent writes — perfect for storing organizational data like user accounts, group memberships, and access permissions.
Active Directory, the identity backbone of most enterprises, speaks LDAP. So do OpenLDAP, FreeIPA, and 389 Directory Server. If your Python app needs to authenticate against a corporate directory, you’re almost certainly talking LDAP.
The directory tree (DIT)
LDAP organizes data in a tree structure called the Directory Information Tree. Every entry has a Distinguished Name (DN) — a unique path from the entry to the root:
dc=example,dc=com (root)
├── ou=People (organizational unit)
│ ├── uid=jsmith (user entry)
│ └── uid=mjones (user entry)
└── ou=Groups
├── cn=engineering (group entry)
└── cn=marketing (group entry)
A user’s full DN might be uid=jsmith,ou=People,dc=example,dc=com. The DN is how you reference specific entries in the tree.
Core operations
Bind — authenticate to the LDAP server. Simple bind sends a DN and password. This is also how you verify user credentials: try to bind as the user, and if it succeeds, the password is correct.
Search — find entries matching criteria. You specify a base DN (where to start), a scope (how deep to search), and a filter (what to match).
Modify — change attributes on an existing entry. Add, remove, or replace values.
Add/Delete — create or remove entire entries.
Python integration with ldap3
The ldap3 library is pure Python (no C dependencies), supports Python 3, and handles connection pooling, TLS, and paged results.
from ldap3 import Server, Connection, ALL, SUBTREE
# Connect to the directory
server = Server("ldap://ldap.example.com", get_info=ALL)
conn = Connection(server, user="cn=admin,dc=example,dc=com",
password="admin_password", auto_bind=True)
# Search for a user
conn.search(
search_base="ou=People,dc=example,dc=com",
search_filter="(uid=jsmith)",
search_scope=SUBTREE,
attributes=["cn", "mail", "memberOf"],
)
for entry in conn.entries:
print(entry.cn, entry.mail)
Authenticating users (bind check)
The standard pattern for user authentication: first search for the user’s DN using a service account, then attempt to bind with the user’s credentials.
def authenticate(username, password):
# Step 1: Find the user's DN
conn.search("ou=People,dc=example,dc=com",
f"(uid={username})", attributes=["dn"])
if not conn.entries:
return False
user_dn = conn.entries[0].entry_dn
# Step 2: Try binding as the user
user_conn = Connection(server, user=user_dn, password=password)
return user_conn.bind()
Search filters
LDAP filters use a prefix notation with operators:
(uid=jsmith)— exact match(cn=John*)— wildcard(&(objectClass=person)(department=Engineering))— AND(|(mail=*@example.com)(mail=*@corp.com))— OR(!(accountDisabled=TRUE))— NOT
Common misconception
“LDAP is outdated and replaced by modern identity providers.” LDAP isn’t going anywhere. Active Directory — the world’s largest identity system — is fundamentally an LDAP directory. Modern IdPs like Okta and Azure AD still sync from or proxy to LDAP backends. If you work in enterprise software, you’ll encounter LDAP.
The one thing to remember: LDAP integration in Python means connecting to a directory tree, searching for user entries by their attributes, and verifying credentials through bind operations — all handled cleanly by the ldap3 library.
See Also
- Python Api Key Management Why apps use special passwords called API keys, and how to keep them safe — explained with a library card analogy
- Python Attribute Based Access Control How apps make fine-grained permission decisions based on who you are, what you're accessing, and the circumstances — explained with an airport analogy
- Python Audit Logging Learn Audit Logging with a clear mental model so your Python code is easier to trust and maintain.
- Python Bandit Security Scanning Why Bandit Security Scanning helps Python teams catch painful mistakes early without slowing daily development.
- Python Clickjacking Prevention How invisible website layers trick you into clicking the wrong thing, and how Python apps stop it