Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .vale/styles/config/vocabularies/DependencyTrack/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
(?i)triag(e|ing)
ACLs
APIs
Active Directory
Aiven
ApacheDS
Artifactory
Atlassian
BOM
Expand All @@ -18,6 +20,7 @@ Dependency-Track
Diataxis
Entra
Exploitability
Fedora 389 Directory Server
Flashpoint
GUIDs
HDDs
Expand All @@ -30,6 +33,7 @@ JWTs
Jira
KEKs
Keycloak
LDAP
LDAPS
Liquibase
Lucene
Expand Down
201 changes: 102 additions & 99 deletions docs/guides/administration/configuring-ldap.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,152 +8,155 @@ log in with their directory credentials rather than a locally managed password.

- A service account in the LDAP directory with read access to users and groups.
- Network connectivity from the Dependency-Track API server to the LDAP server.
- If using LDAPS (recommended for production), a valid TLS certificate on the LDAP server.
If the certificate is signed by an internal CA, see [Configuring Internal CA](configuring-internal-ca.md).
- For LDAPS (recommended in production), a valid TLS certificate on the LDAP server.
If an internal CA issued the certificate, see [Configuring internal CA trust](configuring-internal-ca.md).

## Configuration

All LDAP settings are configured via [app properties](../../reference/configuration/properties.md).
The most practical way to supply them in a container deployment is via environment variables.
Configure all LDAP settings via [app properties](../../reference/configuration/properties.md).
The examples below use property names; see [Application configuration](../../reference/configuration/application.md#environment-variable-mapping)
for how property names map to environment variables.

### Minimal configuration

At least, enable LDAP and configure the server connection:

```ini linenums="1"
DT_LDAP_ENABLED=true
DT_LDAP_SERVER_URL=ldap://ldap.example.com:389
DT_LDAP_BASEDN=dc=example,dc=com
DT_LDAP_SECURITY_AUTH=simple
DT_LDAP_BIND_USERNAME=cn=dt-service,dc=example,dc=com
DT_LDAP_BIND_PASSWORD=changeme
DT_LDAP_AUTH_USERNAME_FORMAT=uid={0},ou=users,dc=example,dc=com
DT_LDAP_ATTRIBUTE_NAME=cn
DT_LDAP_ATTRIBUTE_MAIL=mail
Enable LDAP and configure the server connection:

```properties linenums="1"
dt.ldap.enabled=true
dt.ldap.server.url=ldap://ldap.example.com:389
dt.ldap.basedn=dc=example,dc=com
dt.ldap.security.auth=simple
dt.ldap.bind.username=cn=dt-service,dc=example,dc=com
dt.ldap.bind.password=changeme
dt.ldap.auth.username.format=uid={0},ou=users,dc=example,dc=com
dt.ldap.attribute.name=cn
dt.ldap.attribute.mail=mail
```

The `{0}` placeholder in `DT_LDAP_AUTH_USERNAME_FORMAT` is substituted with the
username entered at login.
!!! tip
Dependency-Track substitutes the `{0}` placeholder in `dt.ldap.auth.username.format`
with the username entered at login.
Comment on lines +36 to +38
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dt.ldap.auth.username.format examples and the tip use a {0} placeholder, but the configuration reference for that property currently documents %s as the substitution variable (docs/reference/configuration/properties.md under dt.ldap.auth.username.format). Please align the placeholder syntax between this guide and the reference (either update the guide to %s or update the reference to {0}), otherwise readers may copy a format string that won't work at runtime.

Copilot uses AI. Check for mistakes.

### User provisioning

When enabled, accounts are created automatically the first time an LDAP user logs in.
Without provisioning, accounts must be created manually before users can log in.
When enabled, Dependency-Track creates accounts automatically the first time an LDAP
user logs in. Otherwise, an administrator must create each account before its user can
log in.

```ini
DT_LDAP_USER_PROVISIONING=true
```properties
dt.ldap.user.provisioning=true
```

### Team synchronisation

When enabled, team membership in Dependency-Track is kept in sync with LDAP group
membership. Teams must be mapped to LDAP groups in **Administration Access Management Teams**.
When enabled, Dependency-Track keeps team membership in sync with LDAP group membership.
Map teams to LDAP groups under **Administration > Access Management > Teams**.

```ini
DT_LDAP_TEAM_SYNCHRONIZATION=true
DT_LDAP_GROUPS_FILTER=(&(objectClass=groupOfUniqueNames))
DT_LDAP_USER_GROUPS_FILTER=(&(objectClass=groupOfUniqueNames)(uniqueMember={USER_DN}))
DT_LDAP_GROUPS_SEARCH_FILTER=(&(objectClass=groupOfUniqueNames)(cn=*{SEARCH_TERM}*))
DT_LDAP_USERS_SEARCH_FILTER=(&(objectClass=inetOrgPerson)(cn=*{SEARCH_TERM}*))
```properties
dt.ldap.team.synchronization=true
dt.ldap.groups.filter=(&(objectClass=groupOfUniqueNames))
dt.ldap.user.groups.filter=(&(objectClass=groupOfUniqueNames)(uniqueMember={USER_DN}))
dt.ldap.groups.search.filter=(&(objectClass=groupOfUniqueNames)(cn=*{SEARCH_TERM}*))
dt.ldap.users.search.filter=(&(objectClass=inetOrgPerson)(cn=*{SEARCH_TERM}*))
```

The `{USER_DN}` placeholder is substituted with the authenticated user's distinguished
name. The `{SEARCH_TERM}` placeholder is substituted with search input from the UI.
!!! tip
Dependency-Track substitutes `{USER_DN}` with the authenticated user's distinguished
name, and `{SEARCH_TERM}` with search input from the UI.

---

## Tested Configurations
## Tested configurations

The following configurations have been tested with specific directory implementations.
Adapt values such as base DNs, bind credentials, and attribute names to match your
environment.
The configurations below work with specific directory implementations. Adapt values
such as base DNs, bind credentials, and attribute names to match your environment.

### Microsoft Active Directory

Active Directory uses a global catalog port (3268/3269) for forest-wide searches.
Users typically authenticate with their User Principal Name (`user@domain.com`).

```ini linenums="1"
DT_LDAP_ENABLED=true
DT_LDAP_SERVER_URL=ldap://ldap.example.com:3268
DT_LDAP_BASEDN=dc=example,dc=com
DT_LDAP_SECURITY_AUTH=simple
DT_LDAP_BIND_USERNAME=CN=DT Service Account,DC=example,DC=com
DT_LDAP_BIND_PASSWORD=changeme
DT_LDAP_AUTH_USERNAME_FORMAT={0}@example.com
DT_LDAP_ATTRIBUTE_NAME=userPrincipalName
DT_LDAP_ATTRIBUTE_MAIL=mail
DT_LDAP_GROUPS_FILTER=(&(objectClass=group)(objectCategory=Group))
DT_LDAP_USER_GROUPS_FILTER=(&(objectClass=group)(objectCategory=Group)(member:1.2.840.113556.1.4.1941:={USER_DN}))
DT_LDAP_GROUPS_SEARCH_FILTER=(&(objectClass=group)(objectCategory=Group)(cn=*{SEARCH_TERM}*))
DT_LDAP_USERS_SEARCH_FILTER=(&(objectClass=user)(objectCategory=Person)(cn=*{SEARCH_TERM}*))
```properties linenums="1"
dt.ldap.enabled=true
dt.ldap.server.url=ldap://ldap.example.com:3268
dt.ldap.basedn=dc=example,dc=com
dt.ldap.security.auth=simple
dt.ldap.bind.username=CN=DT Service Account,DC=example,DC=com
dt.ldap.bind.password=changeme
dt.ldap.auth.username.format={0}@example.com
dt.ldap.attribute.name=userPrincipalName
dt.ldap.attribute.mail=mail
dt.ldap.groups.filter=(&(objectClass=group)(objectCategory=Group))
dt.ldap.user.groups.filter=(&(objectClass=group)(objectCategory=Group)(member:1.2.840.113556.1.4.1941:={USER_DN}))
dt.ldap.groups.search.filter=(&(objectClass=group)(objectCategory=Group)(cn=*{SEARCH_TERM}*))
dt.ldap.users.search.filter=(&(objectClass=user)(objectCategory=Person)(cn=*{SEARCH_TERM}*))
```

!!! tip
The `member:1.2.840.113556.1.4.1941:=` OID in the user groups filter enables
recursive group membership lookup (LDAP_MATCHING_RULE_IN_CHAIN). This ensures
nested group memberships are resolved correctly.
recursive group membership lookup (LDAP_MATCHING_RULE_IN_CHAIN), so
Dependency-Track resolves nested group memberships correctly.

For LDAPS (recommended in production), change the port to `3269` and update the URL:

```ini
DT_LDAP_SERVER_URL=ldaps://ldap.example.com:3269
```properties
dt.ldap.server.url=ldaps://ldap.example.com:3269
```

### ApacheDS

```ini linenums="1"
DT_LDAP_ENABLED=true
DT_LDAP_SERVER_URL=ldap://ldap.example.com:389
DT_LDAP_BASEDN=dc=example,dc=com
DT_LDAP_SECURITY_AUTH=simple
DT_LDAP_BIND_USERNAME=uid=admin,ou=system
DT_LDAP_BIND_PASSWORD=changeme
DT_LDAP_AUTH_USERNAME_FORMAT=uid={0},ou=users,dc=example,dc=com
DT_LDAP_ATTRIBUTE_NAME=cn
DT_LDAP_ATTRIBUTE_MAIL=mail
DT_LDAP_GROUPS_FILTER=(&(objectClass=groupOfUniqueNames))
DT_LDAP_USER_GROUPS_FILTER=(&(objectClass=groupOfUniqueNames)(uniqueMember={USER_DN}))
DT_LDAP_GROUPS_SEARCH_FILTER=(&(objectClass=groupOfUniqueNames)(cn=*{SEARCH_TERM}*))
DT_LDAP_USERS_SEARCH_FILTER=(&(objectClass=inetOrgPerson)(cn=*{SEARCH_TERM}*))
```properties linenums="1"
dt.ldap.enabled=true
dt.ldap.server.url=ldap://ldap.example.com:389
dt.ldap.basedn=dc=example,dc=com
dt.ldap.security.auth=simple
dt.ldap.bind.username=uid=admin,ou=system
dt.ldap.bind.password=changeme
dt.ldap.auth.username.format=uid={0},ou=users,dc=example,dc=com
dt.ldap.attribute.name=cn
dt.ldap.attribute.mail=mail
dt.ldap.groups.filter=(&(objectClass=groupOfUniqueNames))
dt.ldap.user.groups.filter=(&(objectClass=groupOfUniqueNames)(uniqueMember={USER_DN}))
dt.ldap.groups.search.filter=(&(objectClass=groupOfUniqueNames)(cn=*{SEARCH_TERM}*))
dt.ldap.users.search.filter=(&(objectClass=inetOrgPerson)(cn=*{SEARCH_TERM}*))
```

### Fedora 389 Directory Server

```ini linenums="1"
DT_LDAP_ENABLED=true
DT_LDAP_SERVER_URL=ldap://ldap.example.com:389
DT_LDAP_BASEDN=dc=example,dc=com
DT_LDAP_SECURITY_AUTH=simple
DT_LDAP_BIND_USERNAME=cn=Directory Manager
DT_LDAP_BIND_PASSWORD=changeme
DT_LDAP_AUTH_USERNAME_FORMAT=uid={0},ou=people,dc=example,dc=com
DT_LDAP_ATTRIBUTE_NAME=uid
DT_LDAP_ATTRIBUTE_MAIL=mail
DT_LDAP_GROUPS_FILTER=(&(objectClass=groupOfUniqueNames))
DT_LDAP_USER_GROUPS_FILTER=(&(objectClass=groupOfUniqueNames)(uniqueMember={USER_DN}))
DT_LDAP_GROUPS_SEARCH_FILTER=(&(objectClass=groupOfUniqueNames)(cn=*{SEARCH_TERM}*))
DT_LDAP_USERS_SEARCH_FILTER=(&(objectClass=inetOrgPerson)(uid=*{SEARCH_TERM}*))
```properties linenums="1"
dt.ldap.enabled=true
dt.ldap.server.url=ldap://ldap.example.com:389
dt.ldap.basedn=dc=example,dc=com
dt.ldap.security.auth=simple
dt.ldap.bind.username=cn=Directory Manager
dt.ldap.bind.password=changeme
dt.ldap.auth.username.format=uid={0},ou=people,dc=example,dc=com
dt.ldap.attribute.name=uid
dt.ldap.attribute.mail=mail
dt.ldap.groups.filter=(&(objectClass=groupOfUniqueNames))
dt.ldap.user.groups.filter=(&(objectClass=groupOfUniqueNames)(uniqueMember={USER_DN}))
dt.ldap.groups.search.filter=(&(objectClass=groupOfUniqueNames)(cn=*{SEARCH_TERM}*))
dt.ldap.users.search.filter=(&(objectClass=inetOrgPerson)(uid=*{SEARCH_TERM}*))
```

### NetIQ / Novell eDirectory

eDirectory typically uses LDAPS on port 636 and an organisation-based DN structure.

```ini linenums="1"
DT_LDAP_ENABLED=true
DT_LDAP_SERVER_URL=ldaps://ldap.example.com:636
DT_LDAP_BASEDN=o=example
DT_LDAP_SECURITY_AUTH=simple
DT_LDAP_BIND_USERNAME=cn=admin,o=example
DT_LDAP_BIND_PASSWORD=changeme
DT_LDAP_AUTH_USERNAME_FORMAT=uid={0},ou=users,o=example
DT_LDAP_ATTRIBUTE_NAME=uid
DT_LDAP_ATTRIBUTE_MAIL=mail
DT_LDAP_GROUPS_FILTER=(&(objectClass=groupOfUniqueNames))
DT_LDAP_USER_GROUPS_FILTER=(&(objectClass=groupOfUniqueNames)(uniqueMember={USER_DN}))
DT_LDAP_GROUPS_SEARCH_FILTER=(&(objectClass=groupOfUniqueNames)(cn=*{SEARCH_TERM}*))
DT_LDAP_USERS_SEARCH_FILTER=(&(objectClass=inetOrgPerson)(uid=*{SEARCH_TERM}*))
```properties linenums="1"
dt.ldap.enabled=true
dt.ldap.server.url=ldaps://ldap.example.com:636
dt.ldap.basedn=o=example
dt.ldap.security.auth=simple
dt.ldap.bind.username=cn=admin,o=example
dt.ldap.bind.password=changeme
dt.ldap.auth.username.format=uid={0},ou=users,o=example
dt.ldap.attribute.name=uid
dt.ldap.attribute.mail=mail
dt.ldap.groups.filter=(&(objectClass=groupOfUniqueNames))
dt.ldap.user.groups.filter=(&(objectClass=groupOfUniqueNames)(uniqueMember={USER_DN}))
dt.ldap.groups.search.filter=(&(objectClass=groupOfUniqueNames)(cn=*{SEARCH_TERM}*))
dt.ldap.users.search.filter=(&(objectClass=inetOrgPerson)(uid=*{SEARCH_TERM}*))
```

---
Expand All @@ -162,10 +165,10 @@ DT_LDAP_USERS_SEARCH_FILTER=(&(objectClass=inetOrgPerson)(uid=*{SEARCH_TERM}*))

For a full list of LDAP-related configuration properties and their types, defaults, and
environment variable equivalents, see the
[configuration reference](../../reference/configuration/properties.md#dtldapenabled).
[configuration reference](../../reference/configuration/properties.md#ldap).

## See also

- [Permissions](../../reference/permissions.md): mapping LDAP groups to Dependency-Track teams
- [Configuring OIDC](configuring-oidc.md): alternative to LDAP using OpenID Connect
- [Configuring Internal CA](configuring-internal-ca.md): trust internal TLS certificates for LDAPS
- [Configuring OpenID Connect](configuring-oidc.md): alternative to LDAP using OpenID Connect
- [Configuring internal CA trust](configuring-internal-ca.md): trust internal TLS certificates for LDAPS
1 change: 1 addition & 0 deletions docs/includes/abbreviations.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*[EPSS]: Exploit Prediction Scoring System
*[GHSA]: GitHub Security Advisory
*[KEK]: Key Encryption Key
*[LDAP]: Lightweight Directory Access Protocol
*[NVD]: National Vulnerability Database
*[OSV]: Open Source Vulnerabilities
*[PURL]: Package URL, a standardized format for identifying software packages
Expand Down