4. OpenLDAP Configuration
This lab uses standard LDAP (port 389) without encryption to simplify the setup and focus on the SSO integration concepts.
In a real-life production system, you should always use Secure LDAP (LDAPS) to encrypt authentication traffic and protect user credentials.
In this section, you will configure OpenLDAP as the user directory for Concert SSO. You will create
- user accounts representing different Concert personas, and
- groups for role-based access control.
4.1: Understanding LDAP Directory Structure
LDAP (Lightweight Directory Access Protocol) organizes data in a hierarchical tree structure, similar to a file system. Each entry in the directory has a Distinguished Name (DN) that uniquely identifies it.
4.1.1: Directory Information Tree (DIT)
For this lab, we will create the following structure:
dc=example,dc=com (Base DN)
├── ou=users (Organizational Unit for users)
│ ├── uid=alice
│ ├── uid=bob
│ └── uid=charlie
└── ou=groups (Organizational Unit for groups)
├── cn=corporate_it_staff
├── cn=hr_staff
└── cn=sales_staff
For the above LDAP structure, let's imagine that:
• Alice belongs to Corporate IT organization.
• Bob is a techie user in HR organization.
• Charlie is a techie user in Sales organization.
4.1.2: LDAP Terminology
- DN (Distinguished Name): Unique identifier for an entry (e.g.,
uid=alice,ou=users,dc=example,dc=com) - RDN (Relative Distinguished Name): The leftmost component of a DN (e.g.,
uid=alice) - dc (Domain Component): Part of the base DN representing domain structure
- ou (Organizational Unit): Logical grouping of related directory entries for organizing entries
- uid (User ID): Unique identifier for a user
- cn (Common Name): Name attribute, often used for groups
4.1.3: OpenLDAP in this lab
OpenLDAP is automatically installed by the Lab Automation in bluebox.ibmdte.local virtual machine when
a lab reservation is made. By default, the OpenLDAP service is stopped.
4.2: Verify Organizational Units
First, we will verify two organizational units were already created: one for users and one for groups.
4.2.1: Create OUs LDIF File
- Connect to the OpenLDAP host:
ssh jammer@bluebox
- Start OpenLDAP service (if the service is not running):
sudo systemctl start slapd
- Verify OUs Creation:
# Search for the organizational units
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret -b "dc=example,dc=com" "(ou=*)" dn
You should see both ou=users,dc=example,dc=com and ou=groups,dc=example,dc=com in the output.
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: (ou=*)
# requesting: dn
#
# users, example.com
dn: ou=users,dc=example,dc=com
# groups, example.com
dn: ou=groups,dc=example,dc=com
# search result
search: 2
result: 0 Success
# numResponses: 3
# numEntries: 2
Next, we will create user accounts and groups on the LDAP. Please leave the OpenLDAP host session open for the next steps.
4.3: Create Concert User Accounts
Now, we will create three user accounts representing different Concert personas:
- Alice
- Bob
- Charlie
4.3.1: Understanding User Attributes
Each user entry will include:
- uid: Username (alice, bob, charlie)
- cn: Common name (full name)
- sn: Surname (last name)
- mail: Email address
- userPassword: Hashed password
- objectClass: inetOrgPerson (standard LDAP person object)
4.3.2: Create Users LDIF File
Let's create an LDIF file to add the users with a command that generates hashes automatically.
- On the OpenLDAP host, perform the following step:
cd /opt/openldap/ldap-config
- Create the
create-users.ldiffile with the following content:
cat > create-users.ldif << EOF
# Alice - Concert Admin
dn: uid=alice,ou=users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: alice
cn: Alice Admin
sn: Admin
mail: alice@example.com
userPassword: $(slappasswd -s "Alice@123")
description: Alice Concert Admin
# Bob - Concert User
dn: uid=bob,ou=users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: bob
cn: Bob User
sn: User
mail: bob@example.com
userPassword: $(slappasswd -s "Bob@123")
description: Bob Concert User
# Charlie - Concert User
dn: uid=charlie,ou=users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: charlie
cn: Charlie User
sn: User
mail: charlie@example.com
userPassword: $(slappasswd -s "Charlie@123")
description: Charlie Concert User
EOF
The create-users.ldif file contains slappasswd commands to generate hashed passwords for a supplied string for each user.
4.3.3: Add Users to LDAP
Do LDAP add to add users:
# Add the user accounts
ldapadd -x -D "cn=admin,dc=example,dc=com" -w secret -f create-users.ldif
Expected output:
adding new entry "uid=alice,ou=users,dc=example,dc=com"
adding new entry "uid=bob,ou=users,dc=example,dc=com"
adding new entry "uid=charlie,ou=users,dc=example,dc=com"
4.3.4: Verify Users Creation
Do LDAP search to verify users were created:
# List all users
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret \
-b "ou=users,dc=example,dc=com" "(uid=*)" uid cn mail
You should see all three users with their attributes.
# extended LDIF
#
# LDAPv3
# base <ou=users,dc=example,dc=com> with scope subtree
# filter: (uid=*)
# requesting: uid cn mail
#
# bob, users, example.com
dn: uid=bob,ou=users,dc=example,dc=com
uid: bob
cn: Bob User
mail: bob@example.com
# alice, users, example.com
dn: uid=alice,ou=users,dc=example,dc=com
uid: alice
cn: Alice Admin
mail: alice@example.com
# charlie, users, example.com
dn: uid=charlie,ou=users,dc=example,dc=com
uid: charlie
cn: Charlie User
mail: charlie@example.com
# search result
search: 2
result: 0 Success
# numResponses: 4
# numEntries: 3
4.3.5: Test User Authentication
Use ldapwhoami command to verify that users can authenticate with their passwords:
# Test Alice's authentication
ldapwhoami -x -D "uid=alice,ou=users,dc=example,dc=com" -w Alice@123
# Test Bob's authentication
ldapwhoami -x -D "uid=bob,ou=users,dc=example,dc=com" -w Bob@123
# Test Charlie's authentication
ldapwhoami -x -D "uid=charlie,ou=users,dc=example,dc=com" -w Charlie@123
Each command should return the user's DN, confirming successful authentication.
[jammer@bluebox ldap-config]$ ldapwhoami -x -D "uid=alice,ou=users,dc=example,dc=com" -w Alice@123
dn:uid=alice,ou=users,dc=example,dc=com
[jammer@bluebox ldap-config]$ ldapwhoami -x -D "uid=bob,ou=users,dc=example,dc=com" -w Bob@123
dn:uid=bob,ou=users,dc=example,dc=com
[jammer@bluebox ldap-config]$ ldapwhoami -x -D "uid=charlie,ou=users,dc=example,dc=com" -w Charlie@123
dn:uid=charlie,ou=users,dc=example,dc=com
4.4: Create Concert Groups
Now, we will create groups that correspond to Concert roles and add users to these groups.
4.4.1: Understanding Group Structure
We will use the groupOfNames object class, which requires:
- cn: Group name
- member: DN of at least one member (required attribute)
4.4.2: Create Groups LDIF File
Create the create-groups.ldif file with the following content:
cat > create-groups.ldif << 'EOF'
# Corporate IT staff Group
dn: cn=corporate_it_staff,ou=groups,dc=example,dc=com
objectClass: groupOfNames
cn: corporate_it_staff
description: Corporate IT staff role group
member: uid=alice,ou=users,dc=example,dc=com
# HR staff Group
dn: cn=hr_staff,ou=groups,dc=example,dc=com
objectClass: groupOfNames
cn: hr_staff
description: HR staff role group
member: uid=bob,ou=users,dc=example,dc=com
# Sales staff Group
dn: cn=sales_staff,ou=groups,dc=example,dc=com
objectClass: groupOfNames
cn: sales_staff
description: Sales staff role group
member: uid=charlie,ou=users,dc=example,dc=com
EOF
4.4.3: Add Groups to LDAP
Do LDAP add to add groups:
# Add the groups
ldapadd -x -D "cn=admin,dc=example,dc=com" -w secret -f create-groups.ldif
Expected output:
adding new entry "cn=corporate_it_staff,ou=groups,dc=example,dc=com"
adding new entry "cn=hr_staff,ou=groups,dc=example,dc=com"
adding new entry "cn=sales_staff,ou=groups,dc=example,dc=com"
4.4.4: Verify Groups Creation
Do LDAP search to verify groups were created:
# List all groups
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret \
-b "ou=groups,dc=example,dc=com" "(cn=*)" cn member
# extended LDIF
#
# LDAPv3
# base <ou=groups,dc=example,dc=com> with scope subtree
# filter: (cn=*)
# requesting: cn member
#
# hr_staff, groups, example.com
dn: cn=hr_staff,ou=groups,dc=example,dc=com
cn: hr_staff
member: uid=bob,ou=users,dc=example,dc=com
# sales_staff, groups, example.com
dn: cn=sales_staff,ou=groups,dc=example,dc=com
cn: sales_staff
member: uid=charlie,ou=users,dc=example,dc=com
# corporate_it_staff, groups, example.com
dn: cn=corporate_it_staff,ou=groups,dc=example,dc=com
cn: corporate_it_staff
member: uid=alice,ou=users,dc=example,dc=com
# search result
search: 2
result: 0 Success
# numResponses: 4
# numEntries: 3
You should see all three groups with their members.
4.4.5: Verify Group Membership
- Do LDAP search to verify group membership for Alice was created:
# Check which groups Alice belongs to
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret -b "ou=groups,dc=example,dc=com" \
"(member=uid=alice,ou=users,dc=example,dc=com)" cn
You should see Alice belongs to corporate_it_staff group.
# extended LDIF
#
# LDAPv3
# base <ou=groups,dc=example,dc=com> with scope subtree
# filter: (member=uid=alice,ou=users,dc=example,dc=com)
# requesting: cn
#
# corporate_it_staff, groups, example.com
dn: cn=corporate_it_staff,ou=groups,dc=example,dc=com
cn: corporate_it_staff
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
- Do LDAP search to verify group membership for Bob was created:
# Check which groups Bob belongs to
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret -b "ou=groups,dc=example,dc=com" \
"(member=uid=bob,ou=users,dc=example,dc=com)" cn
You should see Bob belongs to hr_staff group.
# extended LDIF
#
# LDAPv3
# base <ou=groups,dc=example,dc=com> with scope subtree
# filter: (member=uid=bob,ou=users,dc=example,dc=com)
# requesting: cn
#
# hr_staff, groups, example.com
dn: cn=hr_staff,ou=groups,dc=example,dc=com
cn: hr_staff
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
- Do LDAP search to verify group membership for Charlie was created:
# Check which groups Charlie belongs to
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret -b "ou=groups,dc=example,dc=com" \
"(member=uid=charlie,ou=users,dc=example,dc=com)" cn
You should see Charlie belongs to sales_staff group.
# extended LDIF
#
# LDAPv3
# base <ou=groups,dc=example,dc=com> with scope subtree
# filter: (member=uid=charlie,ou=users,dc=example,dc=com)
# requesting: cn
#
# sales_staff, groups, example.com
dn: cn=sales_staff,ou=groups,dc=example,dc=com
cn: sales_staff
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
4.5: Verify Complete Directory Structure
Let's verify the entire directory structure we've created:
# Display the complete directory tree
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret -b "dc=example,dc=com" -LLL
This will display all entries in the directory. You should see:
- Base DN:
dc=example,dc=com - Two OUs:
ou=usersandou=groups - Three users:
alice,bob,charlie - Three groups:
corporate_it_staff,hr_staff,sales_staff
4.5.1: Visual Verification
Create a simple script to display the directory structure:
cat > verify-structure.sh << 'EOF'
#!/bin/bash
echo "=== LDAP Directory Structure ==="
echo ""
echo "Base DN: dc=example,dc=com"
echo ""
echo "Organizational Units:"
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret -b "dc=example,dc=com" "(ou=*)" dn 2>/dev/null | grep "^dn:" | sed 's/dn: / - /'
echo ""
echo "Users:"
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret -b "ou=users,dc=example,dc=com" "(uid=*)" dn cn 2>/dev/null | grep -E "^dn:|^cn:" | sed 's/dn: / - /' | sed 's/cn: / Name: /'
echo ""
echo "Groups:"
ldapsearch -x -D "cn=admin,dc=example,dc=com" -w secret -b "ou=groups,dc=example,dc=com" "(cn=*)" dn member 2>/dev/null | grep -E "^dn:|^member:" | sed 's/dn: / - /' | sed 's/member: / Member: /'
EOF
chmod +x verify-structure.sh
./verify-structure.sh
4.6: Exit OpenLDAP Host
Now that OpenLDAP configuration is complete, exit back to the Bastion Host:
exit
4.7: Configuration Summary
You have successfully configured OpenLDAP with:
Organizational Units
- ✅
ou=users,dc=example,dc=com- User accounts directory - ✅
ou=groups,dc=example,dc=com- Groups directory
User Accounts
- ✅ alice (Admin) -
uid=alice,ou=users,dc=example,dc=com - ✅ bob (User) -
uid=bob,ou=users,dc=example,dc=com - ✅ charlie (User) -
uid=charlie,ou=users,dc=example,dc=com
Groups
- ✅ corporate_it_staff - Contains alice
- ✅ hr_staff - Contains bob
- ✅ sales_staff - Contains charlie
User Credentials
| Username | Password | Group |
|---|---|---|
| alice | Alice@123 | corporate_it_staff |
| bob | Bob@123 | hr_staff |
| charlie | Charlie@123 | sales_staff |
Troubleshooting
This section provides basic troubleshooting steps in case you encounter any issues while performing the steps above. These steps are optional and only need to be followed if you run into problems.
Error: "ldap_bind: Invalid credentials"
Problem: Cannot authenticate with admin password
Solutions:
- Verify you're using the correct admin password from credentials file
- Check the admin DN is correct:
cn=admin,dc=example,dc=com - Verify OpenLDAP service is running:
sudo systemctl status slapd
Error: "Already exists"
Problem: Entry already exists when trying to add
Solutions:
- Delete the existing entry first:
ldapdelete -x -D "cn=admin,dc=example,dc=com" -W "uid=alice,ou=users,dc=example,dc=com" - Or modify the existing entry instead of adding a new one
Error: "No such object"
Problem: Parent entry doesn't exist
Solutions:
- Verify the base DN exists:
ldapsearch -x -b "dc=example,dc=com" -s base - Create parent OUs before adding users or groups
- Check for typos in DN components
Users Cannot Authenticate
Problem: ldapwhoami fails for test users
Solutions:
- Verify password hash was generated correctly
- Check user entry exists:
ldapsearch -x -b "ou=users,dc=example,dc=com" "(uid=alice)" - Ensure userPassword attribute is set
- Try resetting the password with
ldappasswd
Cannot See Group Memberships
Problem: Group searches don't show members
Solutions:
- Verify group entries exist:
ldapsearch -x -b "ou=groups,dc=example,dc=com" "(cn=*)" - Check member attribute uses full DN of user
- Ensure groupOfNames object class is used
Next Steps
Now that OpenLDAP is configured with users and groups, you're ready to proceed to the next section where you'll integrate Keycloak with OpenLDAP for user federation. This will allow Keycloak to authenticate users against the LDAP directory you just created.
OpenLDAP configuration is complete! You now have a functional user directory with Concert personas ready for SSO integration.