Complete reference for LDAP — OpenLDAP, Active Directory, LDIF format, ldapsearch CLI tools, Python ldap3, and authentication integration.
Part of The Direct Path to Linux Ubuntu — free for all.
Install client tools: sudo apt install ldap-utils. Python: pip install ldap3.
Most-used ldapsearch commands and filter syntax.
# ── ldapsearch quick reference ──────────────────────────────── # Basic search (anonymous) ldapsearch -x -H ldap://localhost -b "dc=example,dc=com" "(objectClass=*)" # Authenticated search — clean LDIF output ldapsearch -LLL -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=users,dc=example,dc=com" "(objectClass=inetOrgPerson)" cn uid mail # Find specific user ldapsearch -LLL -x -H ldap://localhost -b "dc=example,dc=com" "(uid=alice)" "*" # Search filters (uid=alice) # exact match (mail=*@example.com) # wildcard (&(objectClass=person)(uid=alice)) # AND (|(uid=alice)(uid=bob)) # OR (!(uid=admin)) # NOT (&(objectClass=posixAccount)(uidNumber>=10000)) # numeric compare # Active Directory filters (&(objectCategory=person)(objectClass=user)) # all users (&(objectClass=user)(sAMAccountName=alice)) # specific user (&(objectClass=user)(mail=alice@example.com)) # by email (&(objectClass=user)(memberOf=CN=Admins,OU=Groups,...)) # group member (&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) # enabled # Add, modify, delete ldapadd -x -H ldap://localhost -D "cn=admin,dc=ex,dc=com" -W -f add.ldif ldapmodify -x -H ldap://localhost -D "cn=admin,dc=ex,dc=com" -W -f mod.ldif ldapdelete -x -H ldap://localhost -D "cn=admin,dc=ex,dc=com" -W "uid=bob,ou=users,dc=ex,dc=com" # Change password ldappasswd -x -H ldap://localhost -D "cn=admin,dc=ex,dc=com" -W -S "uid=alice,ou=users,dc=example,dc=com" # Test authentication ldapwhoami -x -H ldap://localhost -D "uid=alice,ou=users,dc=ex,dc=com" -W
Complete LDIF file to add OUs, users, and groups.
# add_structure.ldif — run: ldapadd -x -H ldap://localhost -D "cn=admin,dc=mwu,dc=com" -W -f add_structure.ldif
version: 1
# Organizational Units
dn: ou=users,dc=mywebuniversity,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: users
dn: ou=groups,dc=mywebuniversity,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: groups
# User: Alice
dn: uid=alice,ou=users,dc=mywebuniversity,dc=com
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: alice
cn: Alice Smith
sn: Smith
givenName: Alice
displayName: Alice Smith
mail: alice@mywebuniversity.com
title: Senior Developer
departmentNumber: Engineering
uidNumber: 10001
gidNumber: 5000
homeDirectory: /home/alice
loginShell: /bin/bash
userPassword: {SSHA}your_hashed_password_here
# Generate password hash:
# slappasswd -s mypassword
# Group: developers
dn: cn=developers,ou=groups,dc=mywebuniversity,dc=com
changetype: add
objectClass: top
objectClass: groupOfNames
objectClass: posixGroup
cn: developers
gidNumber: 5001
member: uid=alice,ou=users,dc=mywebuniversity,dc=com
description: Software developersAuthenticate users against LDAP/Active Directory.
# pip install ldap3
from ldap3 import Server, Connection
from functools import lru_cache
import hashlib
LDAP_URI = "ldap://localhost"
BASE_DN = "dc=mywebuniversity,dc=com"
USERS_OU = f"ou=users,{BASE_DN}"
BIND_DN = f"cn=admin,{BASE_DN}"
BIND_PASS = "admin_password"
def authenticate(username: str, password: str) -> dict | None:
'''
Authenticate user against LDAP.
Returns user info dict on success, None on failure.
Pattern: bind as service account, find user DN, then bind as user
'''
server = Server(LDAP_URI)
# Step 1: Bind as service account to find user
with Connection(server, user=BIND_DN, password=BIND_PASS, auto_bind=True) as conn:
conn.search(USERS_OU,
f"(&(objectClass=inetOrgPerson)(uid={username}))",
attributes=["dn","cn","mail","title","departmentNumber","memberOf"])
if not conn.entries:
return None # user not found
user_entry = conn.entries[0]
user_dn = user_entry.entry_dn
# Step 2: Bind as the user to verify password
try:
with Connection(server, user=user_dn, password=password, auto_bind=True) as user_conn:
return {
"dn": user_dn,
"username": username,
"name": str(user_entry.cn),
"email": str(user_entry.mail),
"title": str(user_entry.title) if user_entry.title else None,
"department": str(user_entry.departmentNumber) if user_entry.departmentNumber else None,
"groups": [dn.split(",")[0].replace("cn=","")
for dn in (user_entry.memberOf.values or [])],
}
except Exception:
return None # wrong password
def is_in_group(username: str, group_name: str) -> bool:
server = Server(LDAP_URI)
with Connection(server, user=BIND_DN, password=BIND_PASS, auto_bind=True) as conn:
group_dn = f"cn={group_name},ou=groups,{BASE_DN}"
conn.search(USERS_OU,
f"(&(objectClass=inetOrgPerson)(uid={username})(memberOf={group_dn}))",
attributes=["uid"])
return len(conn.entries) > 0
# Usage
user = authenticate("alice", "alice_password")
if user:
print(f"Authenticated: {user['name']} ({user['email']})")
print(f"Department: {user['department']}")
print(f"Groups: {user['groups']}")
print(f"Is developer: {is_in_group('alice', 'developers')}")
else:
print("Authentication failed")
# python3 auth_demo.pyPull LDAP users into PostgreSQL with Python.
# pip install ldap3 psycopg2-binary
import sqlite3 # using SQLite for demo
from ldap3 import Server, Connection, SUBTREE
LDAP_URI = "ldap://localhost"
BASE_DN = "dc=mywebuniversity,dc=com"
BIND_DN = f"cn=admin,{BASE_DN}"
BIND_PASS = "admin_password"
USERS_OU = f"ou=users,{BASE_DN}"
def sync_users_to_db():
# LDAP connection
server = Server(LDAP_URI)
ldap = Connection(server, user=BIND_DN, password=BIND_PASS, auto_bind=True)
# Search all users
ldap.search(USERS_OU,
"(objectClass=inetOrgPerson)",
search_scope=SUBTREE,
attributes=["uid","cn","sn","givenName","mail","title",
"departmentNumber","telephoneNumber","memberOf"])
ldap_users = [
{
"uid": str(e.uid),
"cn": str(e.cn),
"email": str(e.mail) if e.mail else None,
"title": str(e.title) if e.title else None,
"department": str(e.departmentNumber) if e.departmentNumber else None,
"phone": str(e.telephoneNumber) if e.telephoneNumber else None,
"groups": ",".join(dn.split(",")[0].replace("cn=","")
for dn in (e.memberOf.values or [])),
}
for e in ldap.entries
]
ldap.unbind()
print(f"Found {len(ldap_users)} LDAP users")
# SQLite sync
conn = sqlite3.connect(":memory:")
conn.execute('''
CREATE TABLE IF NOT EXISTS users (
uid TEXT PRIMARY KEY,
cn TEXT,
email TEXT,
title TEXT,
department TEXT,
phone TEXT,
groups TEXT,
synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
synced = 0
for u in ldap_users:
conn.execute('''
INSERT INTO users (uid,cn,email,title,department,phone,groups)
VALUES (:uid,:cn,:email,:title,:department,:phone,:groups)
ON CONFLICT(uid) DO UPDATE SET
cn=excluded.cn, email=excluded.email,
title=excluded.title, department=excluded.department,
phone=excluded.phone, groups=excluded.groups,
synced_at=CURRENT_TIMESTAMP
''', u)
synced += 1
conn.commit()
# Report
print(f"Synced {synced} users")
for row in conn.execute("SELECT uid, cn, department FROM users ORDER BY department, uid"):
print(f" {row[0]:12} {row[1]:25} {row[2] or 'N/A'}")
conn.close()
sync_users_to_db()
# python3 ldap_sync.pyComplete OpenLDAP setup on Ubuntu from scratch.
#!/bin/bash
# OpenLDAP complete setup on Ubuntu 22.04/24.04
# Run as root or with sudo
DOMAIN="mywebuniversity.com"
BASE_DN="dc=mywebuniversity,dc=com"
ADMIN_PW="AdminSecurePass123!" # Change this!
# ── 1. Install ────────────────────────────────────────────────
apt update
apt install -y slapd ldap-utils
# ── 2. Configure ─────────────────────────────────────────────
DEBIAN_FRONTEND=noninteractive dpkg-reconfigure slapd <<EOF
no
${DOMAIN}
MyWebUniversity
${ADMIN_PW}
${ADMIN_PW}
MDB
no
yes
EOF
# ── 3. Add schemas ────────────────────────────────────────────
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/nis.ldif
# ── 4. Create base OUs ────────────────────────────────────────
cat > /tmp/base.ldif << LDIF
dn: ou=users,${BASE_DN}
changetype: add
objectClass: organizationalUnit
ou: users
dn: ou=groups,${BASE_DN}
changetype: add
objectClass: organizationalUnit
ou: groups
LDIF
ldapadd -x -H ldap://localhost -D "cn=admin,${BASE_DN}" -w "${ADMIN_PW}" -f /tmp/base.ldif
# ── 5. Add test user ──────────────────────────────────────────
HASH=$(slappasswd -s "UserPass123!")
cat > /tmp/user.ldif << LDIF
dn: uid=alice,ou=users,${BASE_DN}
changetype: add
objectClass: inetOrgPerson
objectClass: posixAccount
uid: alice
cn: Alice Smith
sn: Smith
givenName: Alice
mail: alice@${DOMAIN}
uidNumber: 10001
gidNumber: 5000
homeDirectory: /home/alice
loginShell: /bin/bash
userPassword: ${HASH}
LDIF
ldapadd -x -H ldap://localhost -D "cn=admin,${BASE_DN}" -w "${ADMIN_PW}" -f /tmp/user.ldif
# ── 6. Test ───────────────────────────────────────────────────
echo "=== All users ==="
ldapsearch -LLL -x -H ldap://localhost -D "cn=admin,${BASE_DN}" -w "${ADMIN_PW}" -b "ou=users,${BASE_DN}" "(objectClass=inetOrgPerson)" uid cn mail
echo "=== Test alice authentication ==="
ldapwhoami -x -H ldap://localhost -D "uid=alice,ou=users,${BASE_DN}" -w "UserPass123!"
echo "OpenLDAP setup complete!"
echo "Base DN: ${BASE_DN}"
echo "Admin DN: cn=admin,${BASE_DN}"
# bash setup_ldap.sh