LDAP & Active Directory Setup
LDAP is the direct-bind transport for on-prem Active Directory and OpenLDAP. It is the only federation path where credentials are posted to the SP: the browser submits username/password to POST /api/auth/idp/ldap/login and the app proxies verification to the directory via a bind. There is no front-channel redirect and therefore no IdP-side MFA in this path, if you require MFA for LDAP-backed users, layer it in-app. Password material transits the SP, so LDAPS is non-negotiable in production.
Configuration Reference
| Field | Type | Required | Description |
|---|---|---|---|
enabled | boolean | Yes | Set to true to enable LDAP authentication |
url | string | Yes | LDAP server URL. Use ldap://hostname:389 for unencrypted or ldaps://hostname:636 for TLS. |
bindDN | string | Yes | Distinguished Name of the service account used to search the directory. Example: CN=svc-simcha,OU=Service Accounts,DC=corp,DC=example,DC=com |
bindCredentials | string | Yes | Password for the service account (bindDN) |
searchBase | string | Yes | The base DN to search for users. Example: OU=Users,DC=corp,DC=example,DC=com |
searchFilter | string | Yes | LDAP search filter to find the user. Use {{username}} as a placeholder for the entered username. Example: (sAMAccountName={{username}}) for AD, (uid={{username}}) for OpenLDAP. |
usernameAttribute | string | No | The LDAP attribute used as the username. sAMAccountName for AD, uid for OpenLDAP. Default: uid |
tlsOptions.rejectUnauthorized | boolean | No | Whether to reject connections with invalid/self-signed TLS certificates. Default: true. Set to false only in dev/test environments with self-signed certs. |
attributeMapping.email | string | Yes | LDAP attribute containing the user's email. AD: mail. OpenLDAP: mail. |
attributeMapping.name | string | Yes | LDAP attribute containing the user's display name. AD: displayName or cn. OpenLDAP: cn. |
Bind Flow
Search-then-bind: (1) the app binds as bindDN/bindCredentials (read-only service account, no write rights needed); (2) it resolves the user DN via searchFilter under searchBase; (3) it rebinds as that DN with the submitted password, the directory, not the app, is the credential authority; (4) it reads attributeMapping attributes plus memberOf for groups; (5) it reconciles the account and issues the session JWT. The service account needs read access to user objects and their memberOf; DC reachability on 389/636 from the app host is required.
Active Directory
Locating config values
# Find your domain's base DN (from a domain-joined machine):
# If your domain is corp.example.com, the base DN is:
# DC=corp,DC=example,DC=com
# Find a user's DN (from PowerShell on a domain controller):
Get-ADUser -Identity "jsmith" | Select-Object DistinguishedName
# Find the search base for all users:
Get-ADOrganizationalUnit -Filter * | Select-Object Name, DistinguishedName
# List available attributes for a user:
Get-ADUser -Identity "jsmith" -Properties * | Select-Object mail, displayName, sAMAccountName, memberOf
Active Directory Configuration Example
{
"ldap": {
"enabled": true,
"url": "ldaps://dc01.corp.example.com:636",
"bindDN": "CN=svc-simcha,OU=Service Accounts,DC=corp,DC=example,DC=com",
"bindCredentials": "ServiceAccountPassword123",
"searchBase": "OU=Users,DC=corp,DC=example,DC=com",
"searchFilter": "(sAMAccountName={{username}})",
"usernameAttribute": "sAMAccountName",
"tlsOptions": {
"rejectUnauthorized": true
},
"attributeMapping": {
"email": "mail",
"name": "displayName"
}
}
}
With this configuration, users log in with their AD username (e.g., jsmith) and their AD password. The application looks up jsmith in the OU=Users,DC=corp,DC=example,DC=com subtree, verifies the password against AD, and extracts the mail and displayName attributes.
Setting Up with OpenLDAP
OpenLDAP Configuration Example
{
"ldap": {
"enabled": true,
"url": "ldap://ldap.example.com:389",
"bindDN": "cn=readonly,dc=example,dc=com",
"bindCredentials": "readonlypassword",
"searchBase": "ou=people,dc=example,dc=com",
"searchFilter": "(uid={{username}})",
"usernameAttribute": "uid",
"tlsOptions": {
"rejectUnauthorized": true
},
"attributeMapping": {
"email": "mail",
"name": "cn"
}
}
}
Group-Based Role Mapping with Active Directory
AD group memberships are read from the memberOf attribute on the user's directory entry. These are full DNs like CN=DBA-Team,OU=Groups,DC=corp,DC=example,DC=com. The role mapping configuration matches against these group names (case-insensitive).
Example: If your AD has these groups and you want to map them:
{
"roleMapping": {
"adminGroups": ["DB-Platform-Admins"],
"approverGroups": ["DBA-Team-Leads", "DB-Change-Approvers"],
"releaseManagerGroups": ["DB-Release-Engineers", "DevOps-Release-Team"]
}
}
A user who is a member of CN=DBA-Team-Leads,OU=Groups,DC=corp,DC=example,DC=com will be assigned the Approver role.
Testing LDAP Connectivity
Before configuring Simcha DB Studio, verify connectivity from the server:
# Test basic connectivity (Linux/macOS)
nc -zv dc01.corp.example.com 636
# Test LDAP search with ldapsearch (Linux)
ldapsearch -x -H ldaps://dc01.corp.example.com:636 \\
-D "CN=svc-simcha,OU=Service Accounts,DC=corp,DC=example,DC=com" \\
-w "ServiceAccountPassword123" \\
-b "OU=Users,DC=corp,DC=example,DC=com" \\
"(sAMAccountName=jsmith)" mail displayName memberOf
# Test via the API (after configuration)
curl -s -X POST http://localhost:5002/api/auth/idp/ldap/login \\
-H "Content-Type: application/json" \\
-d '{"username": "jsmith", "password": "UserPassword123"}'
Security Best Practices
- Always use LDAPS (port 636) in production. Plain LDAP (port 389) transmits passwords in clear text over the network.
- Service account: Use a dedicated service account with read-only access. Do not use a domain admin account.
- Service account password: Store the
bindCredentialsin a secrets manager (AWS Secrets Manager, Azure Key Vault, Vault). Do not hardcode it in configuration files. - TLS certificates: Keep
rejectUnauthorized: truein production. If using an internal CA, install the CA certificate on the application server. - Search base: Scope the
searchBaseas narrowly as possible. Do not use the domain root (DC=corp,DC=example,DC=com) if you can scope to a specific OU. - Search filter: Use specific filters. For AD,
(sAMAccountName={{username}})is preferred over(cn={{username}})because SAM account names are unique within a domain.
LDAP Troubleshooting
| Error | Cause | Fix |
|---|---|---|
LDAP not configured (503) | LDAP is not enabled | Set ldap.enabled to true |
Invalid credentials (401) | User not found or password incorrect | Verify the username exists in the search base. Test with ldapsearch. Verify the password is correct. |
| LDAP connection error in logs | Cannot connect to the LDAP server | Check network connectivity (nc -zv host port). Verify the URL protocol (ldap:// vs ldaps://) and port (389 vs 636). |
| Bind error with service account | Wrong bindDN or bindCredentials | Verify the service account DN is correct and the password has not expired. Test with ldapsearch -D "bindDN" -w "password". |
| User found but email is empty | Wrong attributeMapping.email | The mail attribute may not be populated for this user in AD. Check the user's directory entry. |
| TLS handshake failure | Certificate not trusted | Install the LDAP server's CA certificate on the application server. Or temporarily set rejectUnauthorized: false to diagnose. |
| Groups not mapping correctly | memberOf attribute not returned | Ensure the service account has permission to read memberOf. Verify the user actually belongs to the expected groups. |