Python connects to LDAP using python-ldap (binds to C library) or ldap3 (pure Python, easier to install). Both support all LDAP operations. ldap3 is recommended for new projects.
| Item | Syntax / Value | Description |
|---|---|---|
| ldap3.Server | Server('ldap.example.com', port=389, use_ssl=False) | Define LDAP server |
| ldap3.Connection | Connection(server, user=dn, password=pw, auto_bind=True) | Create connection and bind |
| conn.search | conn.search(base_dn, filter, attributes=['*']) | Search directory |
| conn.entries | conn.entries | List of Entry objects from last search |
| entry.attribute | entry.cn.value / entry.mail.values | Access attribute value(s) |
| conn.add | conn.add(dn, object_class, attributes={}) | Add new entry |
| conn.modify | conn.modify(dn, {'attr': [(MODIFY_REPLACE, ['val'])]}) | Modify entry |
| conn.delete | conn.delete(dn) | Delete entry |
| conn.modify_dn | conn.modify_dn(dn, new_rdn) | Rename or move entry |
| MODIFY_ADD | ldap3.MODIFY_ADD | Add attribute value |
| MODIFY_REPLACE | ldap3.MODIFY_REPLACE | Replace attribute value(s) |
| MODIFY_DELETE | ldap3.MODIFY_DELETE | Delete attribute value(s) |
| SUBTREE | ldap3.SUBTREE | Search scope: subtree |
| LEVEL | ldap3.LEVEL | Search scope: one level (direct children) |
| BASE | ldap3.BASE | Search scope: base entry only |
| ALL_ATTRIBUTES | ldap3.ALL_ATTRIBUTES | Return all user attributes |
| ALL_OPERATIONAL_ATTRIBUTES | ldap3.ALL_OPERATIONAL_ATTRIBUTES | Return operational attributes |
| conn.result | conn.result | Result dict from last operation |
| conn.response | conn.response | Raw response from last search |
| paged_search | conn.extend.standard.paged_search(...) | Handle large result sets with pagination |
| start_tls | conn.start_tls() | Upgrade to TLS after connecting |
| ldap3.SAFE_SYNC | Connection(..., client_strategy=SAFE_SYNC) | Thread-safe strategy |
| Authenticate | conn.bind() with user credentials | Verify username/password against LDAP |
# pip install ldap3
from ldap3 import Server, Connection, ALL, MODIFY_REPLACE, MODIFY_ADD, MODIFY_DELETE, SUBTREE
LDAP_HOST = "ldap://localhost"
BASE_DN = "dc=mywebuniversity,dc=com"
ADMIN_DN = "cn=admin,dc=mywebuniversity,dc=com"
ADMIN_PW = "admin_password"
USERS_OU = f"ou=users,{BASE_DN}"
GROUPS_OU = f"ou=groups,{BASE_DN}"
# ── 1. Connect ────────────────────────────────────────────────
server = Server(LDAP_HOST, get_info=ALL)
conn = Connection(server, user=ADMIN_DN, password=ADMIN_PW, auto_bind=True)
print("Connected:", conn.bound)
print("Server info:", server.info.vendor_name if server.info else "OpenLDAP")
# ── 2. Search users ───────────────────────────────────────────
print("\n=== All Users ===")
conn.search(
search_base = USERS_OU,
search_filter = "(objectClass=inetOrgPerson)",
attributes = ["uid", "cn", "mail", "title", "departmentNumber"]
)
for entry in conn.entries:
dept = entry.departmentNumber.value if entry.departmentNumber else "N/A"
title = entry.title.value if entry.title else "N/A"
print(f" {str(entry.uid):12} {str(entry.cn):20} {str(entry.mail):30} {title}")
# ── 3. Find specific user ─────────────────────────────────────
conn.search(USERS_OU, "(uid=alice)", attributes=["*"])
if conn.entries:
alice = conn.entries[0]
print(f"\nAlice's DN: {alice.entry_dn}")
print(f"Email: {alice.mail.value}")
# ── 4. Authenticate user (check password) ─────────────────────
def authenticate_user(username, password):
user_dn = f"uid={username},{USERS_OU}"
try:
test_conn = Connection(server, user=user_dn, password=password, auto_bind=True)
test_conn.unbind()
return True
except Exception:
return False
print("\nAuth alice/correct:", authenticate_user("alice", "correct_password"))
print("Auth alice/wrong: ", authenticate_user("alice", "wrong_password"))
# ── 5. Add new user ───────────────────────────────────────────
new_user_dn = f"uid=eve,{USERS_OU}"
conn.add(new_user_dn,
object_class = ["top","person","organizationalPerson","inetOrgPerson","posixAccount"],
attributes = {
"uid": "eve",
"cn": "Eve Martinez",
"sn": "Martinez",
"givenName": "Eve",
"mail": "eve@mywebuniversity.com",
"title": "Data Scientist",
"uidNumber": "10005",
"gidNumber": "5000",
"homeDirectory":"/home/eve",
"loginShell": "/bin/bash",
}
)
print("\nAdd result:", conn.result["description"])
# ── 6. Modify entry ───────────────────────────────────────────
conn.modify(new_user_dn, {
"telephoneNumber": [(MODIFY_ADD, ["+1-555-0105"])],
"title": [(MODIFY_REPLACE, ["Senior Data Scientist"])],
})
print("Modify result:", conn.result["description"])
# ── 7. Add to group ───────────────────────────────────────────
group_dn = f"cn=developers,{GROUPS_OU}"
conn.modify(group_dn, {
"member": [(MODIFY_ADD, [new_user_dn])]
})
print("Add to group:", conn.result["description"])
# ── 8. Delete user ────────────────────────────────────────────
# Remove from group first
conn.modify(group_dn, {"member": [(MODIFY_DELETE, [new_user_dn])]})
conn.delete(new_user_dn)
print("Delete result:", conn.result["description"])
conn.unbind()
print("\nDisconnected.")
# python3 ldap_demo.py (requires running OpenLDAP server)