LDAP Sign-in

Set up sign-in via LDAP or Active Directory and map groups to roles

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

  1. 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.
  2. Otherwise, with LDAP_ENABLED=true, oPBWeb connects with the service account (LDAP_BIND_DN), or anonymously if no bind DN is set.
  3. oPBWeb searches with LDAP_USER_FILTER below LDAP_USER_SEARCH_BASE (empty: LDAP_BASE_DN). The search must return exactly one entry.
  4. oPBWeb binds as the user with the DN it found and the entered password, which verifies the password.
  5. oPBWeb determines the role from the memberOf attribute (see below). Without a matching group, there is no access.
  6. 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

VariableDefaultMeaning
LDAP_ENABLEDfalseenable LDAP sign-in
LDAP_HOST–host name of the domain controller or LDAP server
LDAP_PORT636port
LDAP_USE_SSLtrueLDAPS (TLS from connection setup); StartTLS is not supported
LDAP_TLS_VERIFYtrueverify 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.

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:

PurposeFilter
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

  1. Enter the variables in .env as shown above.

  2. Write the service account password to secrets/ldap_bind_password.txt (without a trailing line break is safest; oPBWeb strips leading and trailing whitespace).

  3. If you use your own company CA, place the CA certificate in PEM format as ldap-ca.pem next to setup-opbweb.sh before the setup (the setup moves it to certs/ldap/ldap-ca.pem and proposes it as CA file) or directly in certs/ldap/. The directory certs/ldap/ is mounted read-only in the container as /run/certs/ldap/; LDAP_CA_CERTS_FILE specifies the path inside the container. Without a CA file, oPBWeb verifies against the container’s default CAs.

  4. Restart the stack so that the API reads the new values and the secret:

    ./stop.sh
    ./start.sh
    
  5. Sign 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_*_GROUPS variable 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 memberOf returns directly counts. The primary group of an AD account (usually “Domain Users”) is not included in memberOf.

What each role is allowed to do is described in Users and roles .

Behavior of directory accounts

TopicBehavior
Rolecomes from the groups and is set again on every sign-in; cannot be changed in the user interface
Role change in the directorytakes effect only at the next sign-in with password; a running session renews itself for up to 7 days without asking the directory
Passwordis changed in the directory; Change password and Set password are not available for these accounts
Lock after failed attemptsthe 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 oPBWebpossible; the account can then no longer sign in despite a valid directory password
Revoke access immediatelydeactivate 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-inCauseFix
“Directory service not reachable.”connection, TLS or search with the service account failedcheck 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 entrycheck 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 matchescompare the group DNs exactly with the user’s memberOf; check direct membership
“Account is disabled.”account deactivated in oPBWebreactivate 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.