| Filename | Latest commit message | Latest commit date |
|---|---|---|
| bootstrap | ||
| introduction | ||
| .gitignore | ||
| docker-compose.yaml | ||
| README.md | ||
An Introduction to LDAP (Hands-On)
A practical, CLI-first introduction to LDAP built around a Docker sandbox.
Every command in these lessons is meant to be copy-pasted against the server
running from the docker-compose.yaml. All output shown was
captured from this exact setup, so what you see should match what you get.
Who this is for
You've heard of LDAP and you want to actually understand it by poking at a sandbox server with command-line tools. No prior LDAP knowledge assumed.
The lessons
Work through them in order. Each builds on the last.
| # | File | What you'll learn |
|---|---|---|
| 1 | 01-concepts.md | What LDAP is: the tree, entries, DNs, attributes, object classes |
| 2 | 02-connecting-and-binding.md | Connecting, binding (logging in), anonymous vs authenticated, the Root DSE |
| 3 | 03-searching.md | ldapsearch in depth: base, scope, filters, attribute selection |
| 4 | 04-entries-and-schema.md | Object classes, MUST/MAY attributes, browsing the schema |
| 5 | 05-modifying.md | LDIF, ldapadd, ldapmodify, ldapdelete, ldapmodrdn |
| 6 | 06-groups-and-membership.md | Groups, members, and the memberOf reverse-lookup overlay |
| 7 | 07-passwords-and-access-control.md | Passwords, ldappasswd, hashing, and why ACLs hid things from you |
| 8 | 08-cheatsheet.md | A one-page reference for everything above |
The lab environment
This sandbox runs vegardit/openldap
plus phpLDAPadmin (a web UI at http://localhost:8080, handy for visualising
the tree — but we'll live in the terminal).
Connection details
| Thing | Value |
|---|---|
| Host / URI | ldap://localhost:389 |
| Base DN (the "root" of our tree) | dc=example,dc=com |
| Admin bind DN (full read/write) | uid=admin,dc=example,dc=com |
| Admin password | adminpassword |
| Regular employee | uid=alice,ou=Users,dc=example,dc=com / alicepassword |
| Regular employee | uid=bob,ou=Users,dc=example,dc=com / bobpassword |
| Service account | uid=svc-ldap-bind,ou=TechnicalAccounts,ou=Users,dc=example,dc=com |
| External contractor | uid=ext-max,ou=External,ou=Users,dc=example,dc=com / ext-maxpassword |
Note on the admin DN: many tutorials use
cn=admin,.... This image usesuid=admin,dc=example,dc=cominstead. If a command fails withInvalid credentials (49), check you used the right bind DN.
The directory tree (what's seeded)
dc=example,dc=com
├── ou=Users 52 employees (alice, bob + 50 more)
│ ├── uid=alice uid=bob uid=charlie … uid=zoe
│ ├── ou=Internal (empty — reserved for future use)
│ ├── ou=External ext-max, ext-sara, ext-john (contractors)
│ └── ou=TechnicalAccounts svc-ldap-bind, svc-backup, svc-monitoring,
│ svc-mail, svc-jenkins
├── ou=Groups 14 groups
│ ├── cn=developers engineering team (14 members)
│ ├── cn=engineering same membership as developers
│ ├── cn=hr / cn=finance / cn=marketing / cn=sales / cn=legal
│ ├── cn=operations / cn=it-support
│ ├── cn=managers 10 department heads + executives
│ ├── cn=sysadmins 5 technical staff with elevated access
│ ├── cn=vpn-users 23 staff with VPN access
│ ├── cn=all-employees all 52 regular employees
│ └── cn=ldap-readonly svc-ldap-bind + svc-monitoring
└── ou=Policies
├── cn=DefaultPasswordPolicy created by the image (8-char min, 3 failures)
└── cn=StrictPasswordPolicy from seed.ldif (12-char min, 90-day expiry,
5-password history)
Everything under ou=Users, ou=Groups, and cn=StrictPasswordPolicy comes
from bootstrap/seed.ldif. The OU skeleton and DefaultPasswordPolicy are
created by the image itself.
Do you have the client tools?
These lessons use the OpenLDAP command-line clients: ldapsearch, ldapadd,
ldapmodify, ldapdelete, ldapwhoami, ldappasswd. Check:
ldapsearch -VV
If you get "command not found", either install them
(sudo apt install ldap-utils on Debian/Ubuntu) or run every command
inside the container by prefixing it with docker exec ldap-server, e.g.:
docker exec ldap-server ldapsearch -x -H ldap://localhost \
-D "uid=admin,dc=example,dc=com" -w adminpassword \
-b "dc=example,dc=com" -LLL
Typing less: shell shortcuts (optional but recommended)
You'll repeat the same connection flags constantly. Export them once per terminal session so you can shorten commands in the lessons:
export LDAPURI="ldap://localhost:389"
export LDAPBINDDN="uid=admin,dc=example,dc=com"
export LDAPBASE="dc=example,dc=com"
# Then a full search becomes just:
ldapsearch -x -w adminpassword -LLL "(uid=alice)"
ldapsearch and friends read LDAPURI, LDAPBINDDN, and LDAPBASE from the
environment automatically. The lessons show the full commands (no env vars)
so they always work, but feel free to use the shortcuts.
Resetting the lab
Lessons 5+ change the directory (adding/deleting entries). Because this sandbox uses no persistent volumes, you can wipe everything back to the seeded state at any time:
docker compose down && docker compose up -d
Give it ~10 seconds to re-seed, then carry on.
Ready? Start with 01-concepts.md.