LDAP Sign-in
Audience: Technical administration
Overview
In addition to local accounts, oPBWeb can sign users in against an LDAP directory or Active Directory. The role in oPBWeb is then derived from the group memberships in the directory. You configure the connection with LDAP_* variables in .env and the password of the service account in secrets/ldap_bind_password.txt. There are no settings for this in the user interface.
How sign-in works
- If oPBWeb has a local account with the entered user name, oPBWeb signs in locally only. The directory is not queried, even if the password is wrong.
- Otherwise, with
LDAP_ENABLED=true, oPBWeb connects with the service account (LDAP_BIND_DN), or anonymously if no bind DN is set. - oPBWeb searches with
LDAP_USER_FILTERbelowLDAP_USER_SEARCH_BASE(empty:LDAP_BASE_DN). The search must return exactly one entry. - oPBWeb binds as the user with the DN it found and the entered password, which verifies the password.
- oPBWeb determines the role from the
memberOfattribute (see below). Without a matching group, there is no access. - On the first successful sign-in, oPBWeb creates the account with the source Directory (LDAP). Display name (
displayName), email (mail) and role are taken from the directory again on every sign-in.
Local accounts therefore always stay local, including the first administrator account. This way you can still get into oPBWeb if the directory is down.
Variables
| Variable | Default | Meaning |
|---|---|---|
LDAP_ENABLED | false | enable LDAP sign-in |
LDAP_HOST | – | host name of the domain controller or LDAP server |
LDAP_PORT | 636 | port |
LDAP_USE_SSL | true | LDAPS (TLS from connection setup); StartTLS is not supported |
LDAP_TLS_VERIFY | true | verify the server certificate |
LDAP_CA_CERTS_FILE | – | CA file inside the container, e.g. /run/certs/ldap/ca.pem |
LDAP_BASE_DN | – | base DN of the directory |
LDAP_USER_SEARCH_BASE | – | search base for users; empty = LDAP_BASE_DN |
LDAP_USER_FILTER | (&(objectClass=user)(sAMAccountName={username})) | search filter; {username} is replaced by the entered name (escaped) |
LDAP_BIND_DN | – | DN of the service account used for the search; empty = anonymous search |
LDAP_ADMIN_GROUPS | – | group DNs for the Administrator role |
LDAP_RELEASER_GROUPS | – | group DNs for the Releaser role |
LDAP_PACKAGER_GROUPS | – | group DNs for the Packager role |
LDAP_VIEWER_GROUPS | – | group DNs for the Viewer role |
The service account password is not in .env but in secrets/ldap_bind_password.txt (created empty by init-secrets.sh). The connection has a time limit of 10 seconds for setup and 15 seconds for responses.
With LDAP_USE_SSL=false, user passwords travel over the network unencrypted. Use LDAPS in production. LDAP_TLS_VERIFY=false disables certificate verification and is meant only for a short test.
Active Directory example
An example for the domain example.local. Replace all names with your values:
LDAP_ENABLED=true
LDAP_HOST=dc01.example.local
LDAP_PORT=636
LDAP_USE_SSL=true
LDAP_TLS_VERIFY=true
LDAP_CA_CERTS_FILE=/run/certs/ldap/ca.pem
LDAP_BASE_DN=dc=example,dc=local
LDAP_USER_SEARCH_BASE=ou=Benutzer,dc=example,dc=local
LDAP_USER_FILTER=(&(objectClass=user)(sAMAccountName={username}))
LDAP_BIND_DN=cn=svc-opbweb,ou=Dienstkonten,dc=example,dc=local
LDAP_ADMIN_GROUPS=cn=opbweb-admins,ou=Gruppen,dc=example,dc=local
LDAP_RELEASER_GROUPS=cn=opbweb-releaser,ou=Gruppen,dc=example,dc=local
LDAP_PACKAGER_GROUPS=cn=opbweb-packager,ou=Gruppen,dc=example,dc=local;cn=client-team,ou=Gruppen,dc=example,dc=local
LDAP_VIEWER_GROUPS=cn=opbweb-leser,ou=Gruppen,dc=example,dc=local
More filters, adapt them to your directory:
| Purpose | Filter |
|---|---|
| sign-in with UPN instead of account name | (&(objectClass=user)(userPrincipalName={username})) |
| exclude disabled AD accounts | (&(objectClass=user)(sAMAccountName={username})(!(userAccountControl:1.2.840.113556.1.4.803:=2))) |
OpenLDAP with uid | (&(objectClass=inetOrgPerson)(uid={username})) – requires the memberOf overlay |
Setup
Enter the variables in
.envas shown above.Write the service account password to
secrets/ldap_bind_password.txt(without a trailing line break is safest; oPBWeb strips leading and trailing whitespace).If you use your own company CA, place the CA certificate in PEM format as
ldap-ca.pemnext tosetup-opbweb.shbefore the setup (the setup moves it tocerts/ldap/ldap-ca.pemand proposes it as CA file) or directly incerts/ldap/. The directorycerts/ldap/is mounted read-only in the container as/run/certs/ldap/;LDAP_CA_CERTS_FILEspecifies the path inside the container. Without a CA file, oPBWeb verifies against the container’s default CAs.Restart the stack so that the API reads the new values and the secret:
./stop.sh ./start.shSign in with a directory account. Under Users and roles, the account appears with the source Directory (LDAP) and the assigned role.
Groups and roles
- Each
LDAP_*_GROUPSvariable contains one or more full group DNs, separated by;. - oPBWeb compares the DNs case-insensitively, but otherwise exactly with the values from
memberOf. - The highest role wins: Administrator over Releaser over Packager over Viewer.
- No matching group, no access: sign-in fails with “No permission for oPBWeb (no matching group).” If none of the four variables is set, nobody can sign in via LDAP.
- oPBWeb does not resolve nested groups; only what
memberOfreturns directly counts. The primary group of an AD account (usually “Domain Users”) is not included inmemberOf.
What each role is allowed to do is described in Users and roles .
Behavior of directory accounts
| Topic | Behavior |
|---|---|
| Role | comes from the groups and is set again on every sign-in; cannot be changed in the user interface |
| Role change in the directory | takes effect only at the next sign-in with password; a running session renews itself for up to 7 days without asking the directory |
| Password | is changed in the directory; Change password and Set password are not available for these accounts |
| Lock after failed attempts | the account lock applies only to local accounts; for directory accounts, the directory’s lockout policy applies. The limit for failed attempts per address also applies to LDAP sign-ins. |
| Deactivating in oPBWeb | possible; the account can then no longer sign in despite a valid directory password |
| Revoke access immediately | deactivate the account under Users and roles; this also ends running sessions |
Accounts with the same name: if a local account has the same name as a directory account, the local account always applies.
Troubleshooting
| Message at sign-in | Cause | Fix |
|---|---|---|
| “Directory service not reachable.” | connection, TLS or search with the service account failed | check the API log (see below): host, port, CA file, bind DN and password |
| “Wrong user name or password.” | wrong password, user not found, or the filter returns more than one entry | check filter and search base; test sign-in with the same account directly against the directory |
| “No permission for oPBWeb (no matching group).” | sign-in succeeded, but no group matches | compare the group DNs exactly with the user’s memberOf; check direct membership |
| “Account is disabled.” | account deactivated in oPBWeb | reactivate it under Users and roles |
The API writes connection and search errors to its log:
docker logs opbweb-api 2>&1 | grep -i "LDAP search failed"
Typical causes are a host name that does not match the certificate, a missing or wrong CA file (path inside the container, not on the host), an empty secrets/ldap_bind_password.txt, or a domain controller that cannot be reached from the Docker host.
To cross-check the search, use ldapsearch on a machine with the OpenLDAP tools. Example, adapt it to your values:
ldapsearch -H ldaps://dc01.example.local:636 \
-D "cn=svc-opbweb,ou=Dienstkonten,dc=example,dc=local" -W \
-b "ou=Benutzer,dc=example,dc=local" \
"(&(objectClass=user)(sAMAccountName=mmuster))" memberOf displayName mail
You can copy the memberOf values from the output directly into the LDAP_*_GROUPS variables.