Start here
Use these pages to get a quick, hands-on look at what PingDS software can do. You will download, install, and use DS on your local computer.
Estimated time to complete: 30-45 minutes
Install DS
DS software has no GUI. Instead, DS software is bundled with command-line tools. Because LDAP is standard, you can use third-party GUI tools to view and edit directory data. For a short list, refer to Try third-party tools. |
Prepare for installation
-
To evaluate DS software, make sure you have 10 GB free disk space for the software and for sample data.
-
Verify that you have a supported Java version installed on your local computer.
For details, check the supported Java versions.
-
If you plan to Learn HDAP, make sure the
curl
command is available.For details, refer to the curl site.
Download DS software
-
If you do not have an account on Ping Identity Backstage, sign up for one.
-
Sign in to Ping Identity Backstage.
-
Find and download the latest PingDS ZIP distribution.
Install a directory server
-
Unzip the
.zip
file into the file system directory where you want to install the server.The documentation shows the installation file system directory as
/path/to/opendj
.For example:
-
Bash
-
PowerShell
-
Zsh
$ unzip ~/Downloads/DS-8.0.0.zip -d /path/to
Expand-Archive DS-8.0.0.zip C:\path\to
This example installs DS files with the cross-platform zip. When using the native installer, refer to Use the Windows MSI.
$ unzip ~/Downloads/DS-8.0.0.zip -d /path/to
-
-
Generate and save a deployment ID using the deployment ID password of your choice.
Use this ID and its password when setting up DS servers in your deployment. The DS server uses the two together when generating other keys to protect shared secret keys and secure connections to other DS servers:
-
Bash
-
PowerShell
-
Zsh
$ /path/to/opendj/bin/dskeymgr create-deployment-id --deploymentIdPassword password $ export DEPLOYMENT_ID=<deployment-id>
C:\path\to\opendj\bat\dskeymgr.bat create-deployment-id --deploymentIdPassword password set DEPLOYMENT_ID=<deployment-id>
$ /path/to/opendj/bin/dskeymgr create-deployment-id --deploymentIdPassword password $ export DEPLOYMENT_ID=<deployment-id>
-
-
Use the
setup
command to set up a server with theds-evaluation
profile. The evaluation profile includes Example.com sample data, more lenient access control, and some other features.You must have write access to the folder where you install DS.
The following example runs the command non-interactively. Use the same settings shown here to copy and paste the commands shown in these pages:
-
Bash
-
PowerShell
-
Zsh
$ /path/to/opendj/setup \ --serverId first-ds \ --deploymentId $DEPLOYMENT_ID \ --deploymentIdPassword password \ --rootUserDn uid=admin \ --rootUserPassword password \ --monitorUserPassword password \ --hostname localhost \ --ldapPort 1389 \ --ldapsPort 1636 \ --httpsPort 8443 \ --adminConnectorPort 4444 \ --replicationPort 8989 \ --profile ds-evaluation \ --start \ --acceptLicense
Show output
Validating parameters..... Done Configuring certificates..... Done Configuring server... Done Configuring profile DS evaluation..................... Done Starting directory server............... Done To see basic server status and configuration, you can launch editable:dsBasePath[/path/to/opendj]/bin/status
C:\path\to\opendj\setup.bat ` --serverId first-ds ` --deploymentId <deployment-id> ` --deploymentIdPassword password ` --rootUserDn uid=admin ` --rootUserPassword password ` --monitorUserPassword password ` --hostname localhost ` --ldapPort 1389 ` --ldapsPort 1636 ` --httpsPort 8443 ` --adminConnectorPort 4444 ` --replicationPort 8989 ` --profile ds-evaluation ` --start ` --acceptLicense
Show output
Validating parameters..... Done Configuring certificates..... Done Configuring server..... Done Configuring profile DS evaluation..................... Done Starting directory server............... Done To see basic server status and configuration, you can launch editable:dsWindowsBasePath[C:\path\to\opendj]\bat\status
$ /path/to/opendj/setup \ --serverId first-ds \ --deploymentId $DEPLOYMENT_ID \ --deploymentIdPassword password \ --rootUserDn uid=admin \ --rootUserPassword password \ --monitorUserPassword password \ --hostname localhost \ --ldapPort 1389 \ --ldapsPort 1636 \ --httpsPort 8443 \ --adminConnectorPort 4444 \ --replicationPort 8989 \ --profile ds-evaluation \ --start \ --acceptLicense
Show output
Validating parameters..... Done Configuring certificates..... Done Configuring server... Done Configuring profile DS evaluation..................... Done Starting directory server............... Done To see basic server status and configuration, you can launch editable:dsBasePath[/path/to/opendj]/bin/status
More about setup options
The
setup
command shown here has the following options:--serverId first-ds
-
A server identifier string that’s unique across servers in your deployment.
--deploymentId <deployment-id>
-
The deployment ID is a random string generated using the
dskeymgr
command. It’s paired with a deployment ID password, which is a random string that you choose, and that you must keep secret.Together, the deployment ID and password serve to generate the shared master key that DS servers in the deployment require for protecting shared encryption secrets. By default, they also serve to generate a private CA and keys for TLS to protect communication between DS servers.
When you deploy multiple servers together, reuse the same deployment ID and password for each server installation.
--deploymentIdPassword password
-
This is a random string that you choose, and that you must keep secret. It is paired with the deployment ID.
--rootUserDn uid=admin
-
These options set the credentials for the directory superuser. This user has privileges to perform all administrative operations and isn’t subject to access control. It’s called the root user due to the similarity to the Linux root user.
The root user distinguished name (DN) identifies the directory superuser. In LDAP, a DN is the fully qualified name for a directory entry. The default name is
uid=admin
. --monitorUserPassword password
-
The monitor user has the privilege to read monitoring data. This example doesn’t set the
--monitorUserDn
option, so the DN defaults touid=Monitor
. --hostname localhost
-
The server uses the fully qualified domain name for identification between replicated servers.
Using
localhost
is a shortcut suitable only for evaluation on your local computer. In production, set this to the fully qualified domain name, such asds.example.com
. --ldapPort 1389
-
The reserved port for LDAP is
389
. Use StartTLS to secure connections to this port. The connections aren’t secure by default.Examples in the documentation use
1389
, which is accessible to non-privileged users. --ldapsPort 1636
-
The reserved port for LDAPS is
636
. Secure connections to this port with TLS.Examples in the documentation use
1636
, which is accessible to non-privileged users. --httpsPort 8443
-
The reserved port for HTTPS is
443
.HTTP client applications access directory data and monitoring information on this port.
Examples in the documentation use
8443
, which is accessible to non-privileged users. --adminConnectorPort 4444
-
This is the service port used to configure the server and to run tasks. Secure connections to this port with TLS.
The port used in the documentation is
4444
, which is the initial port suggested during interactive setup. --replicationPort 8989
-
This is the service port used for replication messages.
The port used in the documentation is
8989
, which is the initial port suggested during interactive setup. --profile ds-evaluation
-
The setup profile adds hard-coded entries for users like Babs Jensen, and groups like Directory Administrators. It also generates 100,000 sample LDAP user entries. All generated users have the same password, literally
password
. The generated user accounts are helpful for performance testing.This profile adds entries under the base DN
dc=example,dc=com
. A base DN is the suffix shared by all DNs in a set of directory data.A directory arranges LDAP entries hierarchically. The hierarchical organization resembles a file system on a PC or a web server, often visualized as an upside down tree structure, or a pyramid. In the same way that a full path uniquely identifies each file or folder in a file system, a DN uniquely identifies each LDAP entry.
Each DN consists of components separated by commas, such as
uid=bjensen,ou=People,dc=example,dc=com
. The base DN matches the final components of each DN in that branch of the directory. A DN’s components reflect the hierarchy of directory entries. The user entry with DNuid=bjensen,ou=People,dc=example,dc=com
is under the organizational unit entryou=People,dc=example,dc=com
, which in turn is underdc=example,dc=com
.Basic components have the form
attribute-name=attribute-value
, such asdc=com
. In the exampledc=com
, the attributedc
(DNS domain component) has the valuecom
. The DNdc=example,dc=com
reflects the DNs domain nameexample.com
. --start
-
By default, the
setup
command doesn’t start the server. This lets you complete any necessary configuration steps before starting the server for the first time, which may start the replication process.In this case, you have no further configuration to do. This option causes the server to start immediately.
--acceptLicense
-
Remove this option to read the license and then accept it interactively.
You can also run the
setup
command interactively by starting it without options. -
-
Add the DS tools to your PATH to avoid having to specify the full path for each command:
-
Bash
-
PowerShell
-
Zsh
$ export PATH=/path/to/opendj/bin:${PATH}
$env:PATH += ";C:\path\to\opendj\bat"
$ export PATH=/path/to/opendj/bin:${PATH}
-
-
Run the
status
command:-
Bash
-
PowerShell
-
Zsh
$ status \ --bindDn uid=admin \ --bindPassword password \ --hostname localhost \ --port 4444 \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin
status.bat ` --bindDn uid=admin ` --bindPassword password ` --hostname localhost ` --port 4444 ` --usePkcs12TrustStore C:\path\to\opendj\config\keystore ` --trustStorePassword:file C:\path\to\opendj\config\keystore.pin
$ status \ --bindDn uid=admin \ --bindPassword password \ --hostname localhost \ --port 4444 \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin
The
status
command uses a secure connection to the administration port. To trust the server’s certificate, the command uses the server’s own truststore.Read the output that the
status
command displays. -
Learn LDAP
Lightweight Directory Access Protocol (LDAP) is a standard internet protocol. The following examples show you how to use bundled DS command-line tools to send LDAP requests.
Before you try the examples, set up a server, as described in Install DS. Make sure you added the command-line tools to your PATH:
-
Bash
-
PowerShell
-
Zsh
$ export PATH=/path/to/opendj/bin:${PATH}
$env:PATH += ";C:\path\to\opendj\bat"
$ export PATH=/path/to/opendj/bin:${PATH}
Search
Searching the directory is like looking for someone’s phone number when all you know is their name. You use the value of an attribute you know—in this case, their name—to find their profile. Their profile—in LDAP, their entry—has other attributes of interest like their phone number or email address.
When looking up a person’s entry by their name, more information helps narrow down your search. If two people with the same name live in Los Angeles and New York, you need to know where they live to choose the right person. In an LDAP directory, you need to know at least the base DN for the search.
For this example, assume you know a user’s full name, Babs Jensen
,
and that Babs Jensen’s entry is under the base DN dc=example,dc=com
.
You want to look up Babs Jensen’s email and office location.
The following command sends an appropriate LDAP search request to the server you installed:
-
Bash
-
PowerShell
-
Zsh
$ ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
cn mail street l
Show output
dn: uid=bjensen,ou=People,dc=example,dc=com cn: Barbara Jensen cn: Babs Jensen l: San Francisco mail: bjensen@example.com street: 201 Mission Street Suite 2900
ldapsearch.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword hifalutin `
--baseDn dc=example,dc=com `
"(cn=Babs Jensen)" `
cn mail street l
Show output
dn: uid=bjensen,ou=People,dc=example,dc=com cn: Barbara Jensen cn: Babs Jensen l: San Francisco mail: bjensen@example.com street: 201 Mission Street Suite 2900
$ ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
cn mail street l
Show output
dn: uid=bjensen,ou=People,dc=example,dc=com cn: Barbara Jensen cn: Babs Jensen l: San Francisco mail: bjensen@example.com street: 201 Mission Street Suite 2900
More about the search example
Notice the following characteristics of the search:
-
The command makes a secure connection to the server using secure LDAP (LDAPS).
The command relies on the server’s truststore to trust the CA certificate used to sign the server certificate.
-
The base DN option,
--baseDn dc=example,dc=com
, tells the server where to look for Babs Jensen’s entry. Servers can hold data for multiple base DNs, so this is important information.It is possible to restrict the scope of the search, but the default is to search the entire subtree under the base DN.
-
The command uses a search filter,
"(cn=Babs Jensen)"
, which tells the server, "Find entries whosecn
attribute exactly matches the stringBabs Jensen
without regard to case."The
cn
(commonName
) attribute is a standard attribute for full names.Internally, the directory server has an equality index for the
cn
attribute. The directory uses the index to quickly find matches forbabs jensen
. The default behavior in LDAP is to ignore case, so"(cn=Babs Jensen)"
,"(cn=babs jensen)"
, and"(CN=BABS JENSEN)"
are equivalent.If more than one entry matches the filter, the server returns multiple entries.
-
The filter is followed by a list of LDAP attributes,
cn mail street l
. This tells the server to return only the specified attributes in the search result entries. By default, if you do not specify the attributes to return, the server returns all the user attributes that you have the right to read. -
The result shows attributes from a single entry. Notice that an LDAP entry, represented here in the standard LDIF format, has a flat structure with no nesting.
The DN that uniquely identifies the entry is
uid=bjensen,ou=People,dc=example,dc=com
. Multiple entries can have the same attribute values, but each must have a unique DN. This is the same as saying that the leading relative distinguished name (RDN) value must be unique at this level in the hierarchy. Only one entry directly underou=People,dc=example,dc=com
has the RDNuid=bjensen
.The
mail
,street
,l
(location), anduid
attributes are all standard LDAP attributes likecn
.
For additional examples, refer to LDAP search.
Modify
You installed the server with the ds-evaluation
profile.
That profile grants access to search Example.com data without authenticating to the directory.
When modifying directory data, however, you must authenticate first.
LDAP servers must know who you are to determine what you have access to.
In the following example Babs Jensen modifies the description on her own entry:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin <<EOF
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: New description
EOF
Show output
# MODIFY operation successful for DN uid=bjensen,ou=People,dc=example,dc=com
New-Item -Path . -Name "description.ldif" -ItemType "file" -Value @"
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: New description
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword hifalutin `
description.ldif
Show output
# MODIFY operation successful for DN uid=bjensen,ou=People,dc=example,dc=com
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin <<EOF
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: New description
EOF
Show output
# MODIFY operation successful for DN uid=bjensen,ou=People,dc=example,dc=com
More about the modify example
-
Babs Jensen’s authentication credentials are provided with the
--bindDn
and--bindPassword
options. Notice that the user identifier is Babs Jensen’s DN.Authentication operations bind an LDAP identity to a connection. In LDAP, a client application connects to the server, then binds an identity to the connection. An LDAP client application keeps its connection open until it finishes performing its operations. The server uses the identity bound to the connection to make authorization decisions for subsequent operations, such as search and modify requests.
If no credentials are provided, then the identity for the connection is that of an anonymous user. As a directory administrator, you can configure access controls for anonymous users just as you configure access controls for other users.
A simple bind involving a DN and a password is just one of several supported authentication mechanisms. The documentation frequently shows simple binds in examples because this kind of authentication is so familiar. Alternatives include authenticating with a digital certificate, or using Kerberos.
-
The modification is expressed in standard LDAP Data Interchange Format (LDIF).
The LDIF specifies the DN of the target entry to modify. It then indicates that the change to perform is an LDAP modify, and that the value
New description
is to replace existing values of thedescription
attribute. -
Notice that the result is a comment indicating success. The command’s return code—0, but not shown in the example—also indicates success.
The scripts and applications that you write should use and trust LDAP return codes.
For additional examples, refer to LDAP updates and Passwords and accounts.
Add
Authorized users can modify attributes, and can also add and delete directory entries.
The following example adds a new user entry to the directory:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=admin \
--bindPassword password <<EOF
dn: uid=newuser,ou=People,dc=example,dc=com
uid: newuser
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
cn: New User
sn: User
ou: People
mail: newuser@example.com
userPassword: chngthspwd
EOF
Show output
# ADD operation successful for DN uid=newuser,ou=People,dc=example,dc=com
New-Item -Path . -Name "user.ldif" -ItemType "file" -Value @"
dn: uid=newuser,ou=People,dc=example,dc=com
uid: newuser
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
cn: New User
sn: User
ou: People
mail: newuser@example.com
userPassword: chngthspwd
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn uid=admin `
--bindPassword password `
user.ldif
Show output
# ADD operation successful for DN uid=newuser,ou=People,dc=example,dc=com
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=admin \
--bindPassword password <<EOF
dn: uid=newuser,ou=People,dc=example,dc=com
uid: newuser
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
cn: New User
sn: User
ou: People
mail: newuser@example.com
userPassword: chngthspwd
EOF
Show output
# ADD operation successful for DN uid=newuser,ou=People,dc=example,dc=com
More about the add example
-
The bind DN for the user requesting the add is
uid=admin
. It is also possible to authorize regular users to add entries. -
The entry to add is expressed in standard LDIF.
For additional examples, refer to LDAP updates.
Delete
The following example deletes the user added in Add:
-
Bash
-
PowerShell
-
Zsh
$ ldapdelete \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=admin \
--bindPassword password \
uid=newuser,ou=People,dc=example,dc=com
Show output
# DELETE operation successful for DN uid=newuser,ou=People,dc=example,dc=com
ldapdelete.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn uid=admin `
--bindPassword password `
uid=newuser,ou=People,dc=example,dc=com
Show output
# DELETE operation successful for DN uid=newuser,ou=People,dc=example,dc=com
$ ldapdelete \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=admin \
--bindPassword password \
uid=newuser,ou=People,dc=example,dc=com
Show output
# DELETE operation successful for DN uid=newuser,ou=People,dc=example,dc=com
Notice that the ldapdelete
command specifies the entry to delete by its DN.
For additional examples, refer to LDAP updates.
Learn HDAP
PingDS let you access LDAP data over HTTP using HTTP Directory Access Protocol (HDAP) APIs that transform HTTP operations into LDAP operations.
Before you try the examples, follow the instructions in Install DS.
Prepare
Get the deployment CA certificate to trust the server:
-
Bash
-
PowerShell
-
Zsh
$ dskeymgr \
export-ca-cert \
--deploymentId $DEPLOYMENT_ID \
--deploymentIdPassword password \
--outputFile ca-cert.pem
Configure Windows to trust the deployment CA certificate. Import the deployment CA from the server truststore using Microsoft Management Console (MMC):
-
Run Microsoft Management Console (
mmc.exe
). -
Add the certificates snap-in to import the deployment CA certificate:
-
In the console, select File > Add/Remove Snap-in, then Add.
-
Select Certificates from the list of snap-ins and click Add.
-
Finish the wizard.
-
-
Import the deployment CA certificate using the snap-in:
-
Select Console Root > Trusted Root Certification Authorities > Certificates.
-
In the Action menu, select Import to open the wizard.
-
Use the wizard to import the deployment CA certificate from the server truststore file,
C:\path\to\opendj\config\keystore
.The truststore password is the text in the file
C:\path\to\opendj\config\keystore.pin
.
-
$ dskeymgr \
export-ca-cert \
--deploymentId $DEPLOYMENT_ID \
--deploymentIdPassword password \
--outputFile ca-cert.pem
Create
Use HDAP to create a user resource:
-
Bash
-
JavaScript
-
PowerShell
-
Python
-
Ruby
-
Zsh
$ curl \
--request POST \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
--data '{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People?_prettyPrint=true'
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ], "cn" : [ "New User" ], "givenName" : [ "New" ], "mail" : [ "newuser@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 408 555 1212" ], "uid" : [ "newuser" ] }
const { doRequest, getOptions } = require('./utils')
const options = getOptions({
path: '/hdap/dc=com/dc=example/ou=People?_action=create',
credentials: 'uid=admin:password',
method: 'POST',
body: {
"_id": "dc=com/dc=example/ou=People/uid=newuser",
"objectClass": ["person", "inetOrgPerson", "organizationalPerson", "top"],
"cn": ["New User"],
"givenName": ["New"],
"mail": ["newuser@example.com"],
"manager": ["dc=com/dc=example/ou=People/uid=bjensen"],
"sn": ["User"],
"telephoneNumber": ["+1 408 555 1212"],
"uid": ["newuser"]
}
})
doRequest('HDAP: create with POST', options)
.then(response => { console.log(response) })
.catch(error => { console.error(error) })
Source files for this sample: create-newuser.js, utils.js
$Credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("uid=admin:password"))
$Headers = @{
Authorization = "Basic $Credentials"
}
Invoke-RestMethod `
-Uri https://localhost:8443/hdap/dc=com/dc=example/ou=People `
-Method Post `
-Headers $Headers `
-ContentType application/json `
-Body @"
{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}
"@ | ConvertTo-JSON
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ], "cn" : [ "New User" ], "givenName" : [ "New" ], "mail" : [ "newuser@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 408 555 1212" ], "uid" : [ "newuser" ] }
#!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
import utils
body = {
'_id': 'dc=com/dc=example/ou=People/uid=newuser',
'objectClass': ['person', 'inetOrgPerson', 'organizationalPerson', 'top'],
'cn': ['New User'],
'givenName': ['New'],
'mail': ['newuser@example.com'],
'manager': ['dc=com/dc=example/ou=People/uid=bjensen'],
'sn': ['User'],
'telephoneNumber': ['+1 408 555 1212'],
'uid': ['newuser']
}
headers = { 'Content-Type': 'application/json' }
response = requests.post(
f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People',
auth=HTTPBasicAuth('uid=admin', 'password'),
headers=headers,
json=body,
verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
Source files for this sample: utils.py, create-newuser.py
require_relative 'utils.rb'
require 'faraday'
require 'json'
utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", ssl: options) do |f|
f.headers['Content-Type'] = 'application/json'
f.request :authorization, :basic, 'uid=admin', 'password'
end
body = {
'_id' => "dc=com/dc=example/ou=People/uid=newuser",
'objectClass' => ["person", "inetOrgPerson", "organizationalPerson", "top"],
'cn' => ["New User"],
'givenName' => ["New"],
'mail' => ["newuser@example.com"],
'manager' => ["dc=com/dc=example/ou=People/uid=bjensen"],
'sn' => ["User"],
'telephoneNumber' => ["+1 408 555 1212"],
'uid' => ["newuser"]
}
response = hdap.post do |h|
h.path = 'dc=com/dc=example/ou=People'
h.body = JSON.generate(body)
end
puts "Status code: #{response.status}\nJSON: #{response.body}"
Source files for this sample: utils.rb, create-newuser.rb
HDAP Ruby examples require Ruby 3.2 and the faraday
and json
gems.
$ curl \
--request POST \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
--data '{
"_id" : "dc=com/dc=example/ou=People/uid=newuser",
"objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ],
"cn" : [ "New User" ],
"givenName" : [ "New" ],
"mail" : [ "newuser@example.com" ],
"manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ],
"sn" : [ "User" ],
"telephoneNumber" : [ "+1 408 555 1212" ],
"uid" : [ "newuser" ]
}' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People?_prettyPrint=true'
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "objectClass" : [ "person", "inetOrgPerson", "organizationalPerson", "top" ], "cn" : [ "New User" ], "givenName" : [ "New" ], "mail" : [ "newuser@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 408 555 1212" ], "uid" : [ "newuser" ] }
-
The command makes a secure connection to the server using HTTPS.
-
The user performing the HTTP POST is the directory superuser.
The default authorization mechanism for HTTP access is HTTP Basic authentication. The superuser’s HTTP user ID,
admin
, is mapped to the LDAP DN,uid=admin
. HDAP uses the DN and password to perform a simple LDAP bind for authentication. The directory uses its LDAP-based access control mechanisms to authorize the operation. -
The successful response is the JSON resource that the command created.
Fields names starting with an underscore like
_id
are reserved. For details, refer to HDAP API reference.
For additional details, refer to HDAP API reference and Create.
Read
Use HDAP to read a user resource:
-
Bash
-
JavaScript
-
PowerShell
-
Python
-
Ruby
-
Zsh
$ curl \
--request GET \
--cacert ca-cert.pem \
--user dc=com/dc=example/ou=People/uid=bjensen:hifalutin \
--header 'Content-Type: application/json' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "_rev" : "<revision>", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "New User" ], "givenName" : [ "New" ], "mail" : [ "newuser@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 408 555 1212" ], "uid" : [ "newuser" ] }
const { doRequest, getOptions } = require('./utils')
const options = getOptions({
path: '/hdap/dc=com/dc=example/ou=People/uid=newuser'
})
doRequest('HDAP: read with GET', options)
.then(response => { console.log(response) })
.catch(error => { console.error(error) })
Source files for this sample: read-newuser.js, utils.js
$Credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("dc=com/dc=example/ou=People/uid=bjensen:hifalutin"))
$Headers = @{
Authorization = "Basic $Credentials"
}
Invoke-RestMethod `
-Uri https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser `
-Method Get `
-Headers $Headers `
-ContentType application/json | ConvertTo-JSON
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "_rev" : "<revision>", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "New User" ], "givenName" : [ "New" ], "mail" : [ "newuser@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 408 555 1212" ], "uid" : [ "newuser" ] }
#!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
import utils
response = requests.get(
f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=newuser',
auth=HTTPBasicAuth('dc=com/dc=example/ou=People/uid=kvaughan', 'bribery'),
verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
Source files for this sample: utils.py, read-newuser.py
require_relative 'utils.rb'
require 'faraday'
utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", ssl: options) do |f|
f.headers['Content-Type'] = 'application/json'
f.request :authorization, :basic, 'dc=com/dc=example/ou=People/uid=bjensen', 'hifalutin'
end
response = hdap.get('dc=com/dc=example/ou=People/uid=newuser')
puts "Status code: #{response.status}\nJSON: #{response.body}"
Source files for this sample: utils.rb, read-newuser.rb
HDAP Ruby examples require Ruby 3.2 and the faraday
and json
gems.
$ curl \
--request GET \
--cacert ca-cert.pem \
--user dc=com/dc=example/ou=People/uid=bjensen:hifalutin \
--header 'Content-Type: application/json' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "_rev" : "<revision>", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "New User" ], "givenName" : [ "New" ], "mail" : [ "newuser@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 408 555 1212" ], "uid" : [ "newuser" ] }
Authenticate when making this HTTP GET request. If no credentials are specified, the response is the HTTP 401 Unauthorized:
{"code":401,"reason":"Unauthorized","message":"Invalid Credentials"}
In other words, the HTTP Basic authorization mechanism requires authentication even for read operations.
For additional details, refer to HDAP API reference and Read. You can also query collections of resources, as described in Query.
Update
Use HDAP to update a user resource:
-
Bash
-
JavaScript
-
PowerShell
-
Python
-
Ruby
-
Zsh
$ curl \
--request PUT \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
--header "If-Match: *" \
--data '{
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"telephoneNumber" : [ "+1 234 567 8910" ]
}' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "Updated User" ], "givenName" : [ "Updated" ], "mail" : [ "updated.user@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 234 567 8910" ], "uid" : [ "newuser" ] }
const { doRequest, getOptions } = require('./utils')
const options = getOptions({
path: '/hdap/dc=com/dc=example/ou=People/uid=newuser',
credentials: 'uid=admin:password',
method: 'PUT',
body: {
"cn": ["Updated User"],
"givenName": ["Updated"],
"mail": ["updated.user@example.com"],
"telephoneNumber": ["+1 234 567 8910"]
}
})
doRequest('HDAP: update newuser', options)
.then(response => { console.log(response) })
.catch(error => { console.error(error) })
Source files for this sample: update-newuser.js, utils.js
$Credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("uid=admin:password"))
$Headers = @{
"Authorization" = "Basic $Credentials"
"If-Match" = "*"
}
Invoke-RestMethod `
-Uri https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser `
-Method Put `
-Headers $Headers `
-ContentType application/json `
-Body @"
{
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"telephoneNumber" : [ "+1 234 567 8910" ]
}
"@ | ConvertTo-JSON
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "Updated User" ], "givenName" : [ "Updated" ], "mail" : [ "updated.user@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 234 567 8910" ], "uid" : [ "newuser" ] }
#!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
import utils
body = {
'cn': ['Updated User'],
'givenName': ['Updated'],
'mail': ['updated.user@example.com'],
'telephoneNumber': ['+1 234 567 8910']
}
headers = { 'Content-Type': 'application/json' }
response = requests.put(
f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=newuser',
auth=HTTPBasicAuth('uid=admin', 'password'),
headers=headers,
json=body,
verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
Source files for this sample: utils.py, update-newuser.py
require_relative 'utils.rb'
require 'faraday'
require 'json'
utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
fields = { '_fields': 'telephoneNumber' }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: fields, ssl: options) do |f|
f.headers['Content-Type'] = 'application/json'
f.request :authorization, :basic, 'uid=admin', 'password'
end
body = {
"cn" => ["Updated User"],
"givenName" => ["Updated"],
"mail" => ["updated.user@example.com"],
"telephoneNumber" => ["+1 234 567 8910"]
}
response = hdap.put do |h|
h.path = 'dc=com/dc=example/ou=People/uid=newuser'
h.body = JSON.generate(body)
end
puts "Status code: #{response.status}\nJSON: #{response.body}"
Source files for this sample: utils.rb, update-newuser.rb
HDAP Ruby examples require Ruby 3.2 and the faraday
and json
gems.
$ curl \
--request PUT \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
--header "If-Match: *" \
--data '{
"cn" : [ "Updated User" ],
"givenName" : [ "Updated" ],
"mail" : [ "updated.user@example.com" ],
"telephoneNumber" : [ "+1 234 567 8910" ]
}' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "Updated User" ], "givenName" : [ "Updated" ], "mail" : [ "updated.user@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 234 567 8910" ], "uid" : [ "newuser" ] }
HDAP versions resources with revision numbers.
A revision is specified in the resource’s _rev
field.
The --header "If-Match: *"
tells HDAP to replace the resource regardless of its revision.
Alternatively, set --header "If-Match: revision"
to replace the resource only if its revision matches.
For additional details, refer to HDAP API reference and Update. You can also patch resources instead of replacing them entirely. Refer to Patch.
Delete
Use HDAP to delete a user resource:
-
Bash
-
JavaScript
-
PowerShell
-
Python
-
Ruby
-
Zsh
$ curl \
--request DELETE \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "_rev" : "<revision>", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "Updated User" ], "givenName" : [ "Updated" ], "mail" : [ "updated.user@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 234 567 8910" ], "uid" : [ "newuser" ] }
const { doRequest, getOptions } = require('./utils')
const options = getOptions({
path: '/hdap/dc=com/dc=example/ou=People/uid=newuser',
credentials: 'uid=admin:password',
method: 'DELETE'
})
doRequest('HDAP: delete newuser', options)
.then(response => { console.log(response) })
.catch(error => { console.error(error) })
Source files for this sample: delete-newuser.js, utils.js
$Credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("uid=admin:password"))
$Headers = @{
Authorization = "Basic $Credentials"
}
Invoke-RestMethod `
-Uri https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser `
-Method Delete `
-Headers $Headers `
-ContentType application/json | ConvertTo-JSON
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "_rev" : "<revision>", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "Updated User" ], "givenName" : [ "Updated" ], "mail" : [ "updated.user@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 234 567 8910" ], "uid" : [ "newuser" ] }
#!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
import utils
response = requests.delete(
f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=newuser',
auth=HTTPBasicAuth('uid=admin', 'password'),
verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
Source files for this sample: utils.py, delete-newuser.py
require_relative 'utils.rb'
require 'faraday'
utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", ssl: options) do |f|
f.headers['Content-Type'] = 'application/json'
f.request :authorization, :basic, 'uid=admin', 'password'
end
response = hdap.delete('dc=com/dc=example/ou=People/uid=newuser')
puts "Status code: #{response.status}\nJSON: #{response.body}"
Source files for this sample: utils.rb, delete-newuser.rb
HDAP Ruby examples require Ruby 3.2 and the faraday
and json
gems.
$ curl \
--request DELETE \
--cacert ca-cert.pem \
--user uid=admin:password \
--header 'Content-Type: application/json' \
'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=newuser?_prettyPrint=true'
Show output
{ "_id" : "dc=com/dc=example/ou=People/uid=newuser", "_rev" : "<revision>", "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ], "cn" : [ "Updated User" ], "givenName" : [ "Updated" ], "mail" : [ "updated.user@example.com" ], "manager" : [ "dc=com/dc=example/ou=People/uid=bjensen" ], "sn" : [ "User" ], "telephoneNumber" : [ "+1 234 567 8910" ], "uid" : [ "newuser" ] }
For additional details, refer to HDAP API reference and Delete.
Learn replication
Replication provides automatic data synchronization between directory servers. It ensures that all directory servers eventually share a consistent set of directory data.
More about replication
Replication requires two or more directory servers and additional configuration. This page takes you though the setup process quickly, providing commands that you can reuse. It does not explain each command in detail.

For a full discussion of the subject, refer to Replication and the related pages.
Add a replica
High-level steps:
-
Unpack the files for a second directory server in a different folder.
-
Set up the new server as a replica of the first server using the generated
<deployment-id>
from Install DS.
The following example demonstrates the process:
-
Bash
-
PowerShell
-
Zsh
# Unpack files for a second, replica server in a different folder:
cd ~/Downloads && unzip ~/Downloads/DS-8.0.0.zip && mv opendj /path/to/replica
# Set up a second, replica server:
/path/to/replica/setup \
--serverId second-ds \
--deploymentId $DEPLOYMENT_ID \
--deploymentIdPassword password \
--rootUserDn uid=admin \
--rootUserPassword password \
--hostname localhost \
--ldapPort 11389 \
--ldapsPort 11636 \
--adminConnectorPort 14444 \
--replicationPort 18989 \
--bootstrapReplicationServer localhost:8989 \
--profile ds-evaluation \
--start \
--acceptLicense
# Unpack files for a second, replica server in a different folder:
Expand-Archive DS-8.0.0.zip C:\Temp
Rename-Item -Path C:\Temp\opendj -NewName C:\Temp\replica
Move-Item C:\Temp\replica C:\path\to
# Set up a second, replica server:
C:\path\to\replica\setup.bat `
--serverId second-ds `
--deploymentId <deployment-id> `
--deploymentIdPassword password `
--rootUserDn uid=admin `
--rootUserPassword password `
--hostname localhost `
--ldapPort 11389 `
--ldapsPort 11636 `
--adminConnectorPort 14444 `
--replicationPort 18989 \
--bootstrapReplicationServer locahost:8989 \
--profile ds-evaluation `
--start `
--acceptLicense
# Unpack files for a second, replica server in a different folder:
cd ~/Downloads && unzip ~/Downloads/DS-8.0.0.zip && mv opendj /path/to/replica
# Set up a second, replica server:
/path/to/replica/setup \
--serverId second-ds \
--deploymentId $DEPLOYMENT_ID \
--deploymentIdPassword password \
--rootUserDn uid=admin \
--rootUserPassword password \
--hostname localhost \
--ldapPort 11389 \
--ldapsPort 11636 \
--adminConnectorPort 14444 \
--replicationPort 18989 \
--bootstrapReplicationServer localhost:8989 \
--profile ds-evaluation \
--start \
--acceptLicense
Try replication
With the new replica set up and started, show that replication works:
-
Bash
-
PowerShell
-
Zsh
# Update a description on the first server:
ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin << EOF
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: Replicate this
EOF
# On the first server, read the description to see the effects of your change:
ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
description
# On the second server, read the description to see the change has been replicated:
ldapsearch \
--hostname localhost \
--port 11636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
description
# Update a description on the first server:
New-Item -Path . -Name "mod-desc.ldif" -ItemType "file" -Value @"
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: Replicate this
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword password `
mod-desc.ldif
# On the first server, read the description to see the effects of your change:
ldapsearch.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword hifalutin `
--baseDn dc=example,dc=com `
"(cn=Babs Jensen)" `
description
# On the second server, read the description to see the change has been replicated:
ldapsearch.bat `
--hostname localhost `
--port 11636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword hifalutin `
--baseDn dc=example,dc=com `
"(cn=Babs Jensen)" `
description
# Update a description on the first server:
ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin << EOF
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: Replicate this
EOF
# On the first server, read the description to see the effects of your change:
ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
description
# On the second server, read the description to see the change has been replicated:
ldapsearch \
--hostname localhost \
--port 11636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
description
Show replication works despite crashes and network interruptions:
-
Bash
-
PowerShell
-
Zsh
# Stop the second server to simulate a network outage or server crash:
/path/to/replica/bin/stop-ds
# On the first server, update the description again:
ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin <<EOF
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: Second server is stopped
EOF
# On the first server, read the description to see the change:
ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
description
# Start the second server again to simulate recovery:
/path/to/replica/bin/start-ds
# On the second server, read the description to check that replication has resumed:
ldapsearch \
--hostname localhost \
--port 11636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
description
# Stop the second server to simulate a network outage or server crash:
C:\path\to\replica\bat\stop-ds.bat
# On the first server, update the description again:
New-Item -Path . -Name "mod-desc2.ldif" -ItemType "file" -Value @"
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: Second server is stopped
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword password `
mod-desc2.ldif
# On the first server, read the description to see the change:
ldapsearch.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword hifalutin `
--baseDn dc=example,dc=com `
"(cn=Babs Jensen)" `
description
# Start the second server again to simulate recovery:
C:\path\to\replica\bat\start-ds.bat
# On the second server, read the description to check that replication has resumed:
ldapsearch.bat `
--hostname localhost `
--port 11636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword hifalutin `
--baseDn dc=example,dc=com `
"(cn=Babs Jensen)" `
description
# Stop the second server to simulate a network outage or server crash:
/path/to/replica/bin/stop-ds
# On the first server, update the description again:
ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin <<EOF
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: Second server is stopped
EOF
# On the first server, read the description to see the change:
ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
description
# Start the second server again to simulate recovery:
/path/to/replica/bin/start-ds
# On the second server, read the description to check that replication has resumed:
ldapsearch \
--hostname localhost \
--port 11636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--baseDn dc=example,dc=com \
"(cn=Babs Jensen)" \
description
Unlike some databases, DS replication does not operate in active-passive mode. Instead, you read and write on any running server. Replication replays your changes as soon as possible. Show this to check your understanding:
Notifications
Some applications require notification when directory data updates occur. For example, IDM can sync directory data with another database. Other applications do more processing when certain updates occur.
Replicated DS directory servers publish an external change log over LDAP. This changelog lets authorized client applications read changes to directory data:
-
Bash
-
PowerShell
-
Zsh
$ ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password \
--baseDN cn=changelog \
--control "ecl:true" \
"(&)" \
changes changeLogCookie targetDN
ldapsearch.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=admin `
--bindPassword password `
--baseDN cn=changelog `
--control "ecl:true" `
"(objectclass=*)" `
changes changeLogCookie targetDN
$ ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password \
--baseDN cn=changelog \
--control "ecl:true" \
"(&)" \
changes changeLogCookie targetDN
When looking at the output of the command (not shown here),
notice that the changes
values are base64-encoded in LDIF because they include line breaks.
You can use the DS base64
command to decode them.
For details, refer to Changelog for notifications.
Measure performance
DS directory servers offer high throughput and low response times for most operations. DS software includes the following command-line tools for measuring performance of common LDAP operations:
-
addrate
measures LDAP adds and deletes -
authrate
measures LDAP binds -
modrate
measures LDAP modifications -
searchrate
measures LDAP searches
Before trying the examples that follow, work through the previous examples. You should have two directory server replicas running on your local computer, as described in Learn replication: ![]() |
The following examples show how to measure and verify basic directory performance. For a deeper dive into the subject, read Performance tuning.
Measure modification rates
In deployment, you can expect many directory client applications to change directory data in parallel. The directory has to serve all these requests with high throughput (lots of requests) and low latency (quick responses), so all the client applications can get their work done quickly.
As a first step towards tuning your directory service performance, get a sense of the throughput and response times
you can expect by measuring the LDAP modification rate with the modrate
command:
-
Bash
-
PowerShell
-
Zsh
# Run modrate for 10 seconds against the first server:
modrate \
--maxDuration 10 \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--noRebind \
--numConnections 4 \
--numConcurrentRequests 4 \
--targetDn "uid=user.{1},ou=people,dc=example,dc=com" \
--argument "rand(0,100000)" \
--argument "randstr(16)" \
"description:{2}"
# Read number of modify requests on the LDAPS port:
ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=monitor \
--bindPassword password \
--baseDN "cn=LDAPS,cn=connection handlers,cn=monitor" \
"(&)" \
ds-mon-requests-modify
# Run modrate for 10 seconds against the first server, and observe the performance numbers:
modrate.bat `
--maxDuration 10 `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword password `
--noRebind `
--numConnections 4 `
--numConcurrentRequests 4 `
--targetDn "uid=user.{1},ou=people,dc=example,dc=com" `
--argument "rand(0,100000)" `
--argument "randstr(16)" `
"description:{2}"
# Read number of modify requests on the LDAPS port:
ldapsearch.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=monitor `
--bindPassword password `
--baseDN "cn=LDAPS,cn=connection handlers,cn=monitor" `
"(objectclass=*)" `
ds-mon-requests-modify
# Run modrate for 10 seconds against the first server:
modrate \
--maxDuration 10 \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--noRebind \
--numConnections 4 \
--numConcurrentRequests 4 \
--targetDn "uid=user.{1},ou=people,dc=example,dc=com" \
--argument "rand(0,100000)" \
--argument "randstr(16)" \
"description:{2}"
# Read number of modify requests on the LDAPS port:
ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=monitor \
--bindPassword password \
--baseDN "cn=LDAPS,cn=connection handlers,cn=monitor" \
"(&)" \
ds-mon-requests-modify
When reading the modrate
command output,
notice that it shows statistics for throughput (operations/second), response times (milliseconds), and errors/second.
If you expect all operations to succeed and yet err/sec
is not 0.0, the command options are no doubt incorrectly set.
For an explanation of the command output, refer to modrate.
Notice that the monitoring attributes hold similar, alternative statistics.
Measure search rates
Your directory service exists to hold identity data and to make it easy and quick to find. Almost all directory client applications search the directory. Some applications, such as those providing naming services or those in a call path, require very low latency.
To get a sense of the throughput and response times you can expect from your directory even before you tune performance,
measure the LDAP search rate with the searchrate
command:
-
Bash
-
PowerShell
-
Zsh
# Run searchrate for 10 seconds against the first server:
searchrate \
--maxDuration 10 \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--noRebind \
--numConnections 4 \
--numConcurrentRequests 4 \
--baseDn "dc=example,dc=com" \
--argument "rand(0,100000)" \
"(uid=user.{})"
# Read number of subtree search requests on the LDAPS port:
ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=monitor \
--bindPassword password \
--baseDN "cn=LDAPS,cn=connection handlers,cn=monitor" \
"(&)" \
ds-mon-requests-search-sub
# Run searchrate for 10 seconds against the first server:
searchrate.bat `
--maxDuration 10 `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn uid=bjensen,ou=People,dc=example,dc=com `
--bindPassword password `
--noRebind `
--numConnections 4 `
--numConcurrentRequests 4 `
--baseDn "dc=example,dc=com" `
--argument "rand(0,100000)" `
"(uid=user.{})"
# Read number of subtree search requests on the LDAPS port:
ldapsearch.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=monitor `
--bindPassword password `
--baseDN "cn=LDAPS,cn=connection handlers,cn=monitor" `
"(objectclass=*)" `
ds-mon-requests-search-sub
# Run searchrate for 10 seconds against the first server:
searchrate \
--maxDuration 10 \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--noRebind \
--numConnections 4 \
--numConcurrentRequests 4 \
--baseDn "dc=example,dc=com" \
--argument "rand(0,100000)" \
"(uid=user.{})"
# Read number of subtree search requests on the LDAPS port:
ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=monitor \
--bindPassword password \
--baseDN "cn=LDAPS,cn=connection handlers,cn=monitor" \
"(&)" \
ds-mon-requests-search-sub
Notice that searchrate
command output resembles that of the modrate
command.
The searchrate
output also indicates how many entries each search returned.
For an explanation of the command output, refer to searchrate.
Check replication
When you measured directory performance, the modrate
command made many changes to user’s entries.
Replication between your two DS replicas should replay each change
so client applications get the same response regardless of which replica they use to read a user’s entry.
Check the data on both replicas is synchronized. The following example uses monitoring metrics to check replication delay is zero on each replica:
-
Bash
-
PowerShell
-
Zsh
$ ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=monitor \
--bindPassword password \
--baseDN cn=monitor \
"(ds-mon-current-delay=*)" \
ds-mon-current-delay
Show output
dn: ds-mon-domain-name=dc=example\,dc=com,cn=replicas,cn=replication,cn=monitor ds-mon-current-delay: 0 dn: ds-mon-server-id=second-ds,cn=remote replicas,ds-mon-domain-name=dc=example\,dc=com,cn=replicas,cn=replication,cn=monitor ds-mon-current-delay: 0
ldapsearch.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=monitor `
--bindPassword password `
--baseDN cn=monitor `
"(ds-mon-current-delay=*)" `
ds-mon-current-delay
Show output
dn: ds-mon-domain-name=dc=example\,dc=com,cn=replicas,cn=replication,cn=monitor ds-mon-current-delay: 0 dn: ds-mon-server-id=second-ds,cn=remote replicas,ds-mon-domain-name=dc=example\,dc=com,cn=replicas,cn=replication,cn=monitor ds-mon-current-delay: 0
$ ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=monitor \
--bindPassword password \
--baseDN cn=monitor \
"(ds-mon-current-delay=*)" \
ds-mon-current-delay
Show output
dn: ds-mon-domain-name=dc=example\,dc=com,cn=replicas,cn=replication,cn=monitor ds-mon-current-delay: 0 dn: ds-mon-server-id=second-ds,cn=remote replicas,ds-mon-domain-name=dc=example\,dc=com,cn=replicas,cn=replication,cn=monitor ds-mon-current-delay: 0
Learn access control
Until now, you have used the evaluation setup profile, which makes it easy to access Example.com data. It helps you learn and demonstrate directory services without explicitly granting access after server setup.
In a production directory service where security is important, access is under tighter control. In most cases, access is denied by default to prevent accidental information leaks. You must explicitly grant access where required. To grant access, use access control instructions (ACIs).
The sample ACIs described on this page demonstrate some but not all ACI features. For a deeper dive into the subject, read Access control. |
About ACIs
ACIs are implemented as operational LDAP attributes.
Operational attributes are not meant to store application data but to influence server behavior. They hold internal information for the server’s own use, like replication data, timestamps, or ACIs, which the server needs to provide features like replication, account lockout, or access control. Directory servers only return operational attributes in search results when explicitly requested.
Each ACI influences server behavior by indicating:
-
Which directory data it targets
-
Which permissions it allows or denies
-
Which users or groups it applies to
-
Under which conditions (time, network origin, connection security, user properties) it applies
Example ACI with explanation
The following example ACI gives users access to change their own passwords:
aci: (targetattr = "authPassword || userPassword")
(version 3.0;acl "Allow users to change their own passwords";
allow (write)(userdn = "ldap:///self");)
Consider the characteristics of this ACI attribute:
- Target Entries and Scope
-
The target entries and scope for this ACI are implicit.
The default target is the entry with this
aci
attribute.The default scope includes the target entry and all its subordinates.
In other words, if you set this ACI on
ou=People,dc=example,dc=com
, it affects all users under that base entry. For example, Babs Jensen,uid=bjensen,ou=People,dc=example,dc=com
, can set her own password. - Target Attributes
-
This ACI affects operations on either of the standard password attributes:
(targetattr = "authPassword || userPassword")
.The ACI only has an effect when an operation targets either
authPassword
oruserPassword
and any subtypes of those attribute types. - Permissions
-
This ACI affects only operations that change affected attributes:
allow (write)
.If this is the only ACI that targets password attributes, users have access to change their own passwords, but they do not have access to read passwords.
- Subjects
-
This ACI has an effect when the target entry is the same as the bind DN:
(userdn = "ldap:///self")
.This means the user must authenticate before changing their password.
- Documentation
-
The wrapper around the permissions and subjects contains human-readable documentation about the ACI:
(version 3.0;acl "Allow users to change their own passwords"; … ;)
.Version 3.0 is the only supported ACI version.
- Conditions
-
This ACI does not define any conditions. It applies all the time, for connections from all networks, and so forth.
Server configuration settings can further constrain how clients connect. Such constraints are not specified by this ACI, however.
Use ACIs
To write ACI attributes:
-
A user must have the
modify-acl
administrative privilege.Privileges are server configuration settings that control access to administrative operations.
-
An ACI must give the user permission to change
aci
attributes.
By default, only the directory superuser has the right to add, delete, or modify ACI attributes.
The directory superuser account has a Any account with permission to change ACIs is dangerous because the power can be misused. The user with permissions to change ACIs can give themselves full access to all directory data in their scope. |
Prepare to use the examples:
Stop running servers
Use each server’s stop-ds
command to stop any DS servers running on your computer.
This lets the new server use ports another server was already using.
Get sample data
-
Download the Example.ldif file, shown in the following listing:
Show listing
# # Copyright © 2020 - 2025 Ping Identity Corporation # # This code is to be used exclusively in connection with Ping Identity Corporation software or services. # Ping Identity Corporation only offers such software or services to legal entities # who have entered into a binding license agreement with Ping Identity Corporation. # dn: dc=example,dc=com objectClass: domain objectClass: top dc: example dn: ou=Groups,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: Groups dn: ou=Self Service,ou=Groups,dc=example,dc=com objectClass: organizationalUnit objectClass: top description: Groups that authenticated users can manage on their own ou: Self Service dn: ou=People,dc=example,dc=com objectClass: organizationalUnit objectClass: top description: Description on ou=People ou: People dn: uid=ACI Admin,ou=People,dc=example,dc=com objectClass: person objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: top cn: ACI Admin givenName: ACI mail: aci-admin@example.com ou: People sn: Admin uid: ACI Admin userPassword: 5up35tr0ng dn: uid=bjensen,ou=People,dc=example,dc=com objectClass: person objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: top cn: Babs Jensen givenName: Barbara mail: bjensen@example.com ou: People sn: Jensen uid: bjensen userPassword: 5up35tr0ng
-
Save the file to your computer’s temporary directory, such as
/tmp
orC:\Temp
.
Install server with secure settings
-
Unzip the DS server
.zip
file into the folder where you want to install the server. -
Set up the directory server using the LDIF you downloaded.
Set up the server without the evaluation setup profile, so the access control settings are secure by default. The default password policies require stronger passwords. The configuration grants very little access to regular users. Only
uid=admin
has access to the data:-
Bash
-
PowerShell
-
Zsh
$ /path/to/opendj/setup \ --serverId learn-acis \ --deploymentId $DEPLOYMENT_ID \ --deploymentIdPassword password \ --rootUserDn uid=admin \ --rootUserPassword str0ngAdm1nPa55word \ --hostname localhost \ --ldapPort 1389 \ --ldapsPort 1636 \ --httpsPort 8443 \ --adminConnectorPort 4444 \ --acceptLicense $ dsconfig \ create-backend \ --backend-name exampleData \ --type je \ --set enabled:true \ --set base-dn:dc=example,dc=com \ --offline \ --no-prompt $ import-ldif \ --backendId exampleData \ --ldifFile /tmp/Example.ldif \ --offline $ start-ds --quiet
C:\path\to\opendj\setup.bat ` --serverId learn-acis ` --deploymentId <deployment-id> ` --deploymentIdPassword password ` --rootUserDn uid=admin ` --rootUserPassword str0ngAdm1nPa55word ` --hostname localhost ` --ldapPort 1389 ` --ldapsPort 1636 ` --httpsPort 8443 ` --adminConnectorPort 4444 ` --acceptLicense C:\path\to\opendj\bat\dsconfig.bat ` create-backend ` --backend-name exampleData ` --type je ` --set enabled:true ` --set base-dn:dc=example,dc=com ` --offline ` --no-prompt C:\path\to\opendj\bat\import-ldif.bat ` --backendId exampleData ` --ldifFile C:\Temp\Example.ldif ` --offline C:\path\to\opendj\bat\start-ds.bat --quiet
$ /path/to/opendj/setup \ --serverId learn-acis \ --deploymentId $DEPLOYMENT_ID \ --deploymentIdPassword password \ --rootUserDn uid=admin \ --rootUserPassword str0ngAdm1nPa55word \ --hostname localhost \ --ldapPort 1389 \ --ldapsPort 1636 \ --httpsPort 8443 \ --adminConnectorPort 4444 \ --acceptLicense $ dsconfig \ create-backend \ --backend-name exampleData \ --type je \ --set enabled:true \ --set base-dn:dc=example,dc=com \ --offline \ --no-prompt $ import-ldif \ --backendId exampleData \ --ldifFile /tmp/Example.ldif \ --offline $ start-ds --quiet
-
Grant ACI admin access
Grant the ACI Admin
user access to modify ACIs:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=admin \
--bindPassword str0ngAdm1nPa55word << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "aci") (version 3.0;acl "ACI Admin can manage ACI attributes";
allow (write) userdn = "ldap:///uid=ACI Admin,ou=People,dc=example,dc=com";)
dn: uid=ACI Admin,ou=People,dc=example,dc=com
changetype: modify
add: ds-privilege-name
ds-privilege-name: modify-acl
EOF
New-Item -Path . -Name "aci-admin.ldif" -ItemType "file" -Value @"
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "aci") (version 3.0;acl "ACI Admin can manage ACI attributes";
allow (write) userdn = "ldap:///uid=ACI Admin,ou=People,dc=example,dc=com";)
dn: uid=ACI Admin,ou=People,dc=example,dc=com
changetype: modify
add: ds-privilege-name
ds-privilege-name: modify-acl
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn uid=admin `
--bindPassword str0ngAdm1nPa55word `
aci-admin.ldif
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn uid=admin \
--bindPassword str0ngAdm1nPa55word << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "aci") (version 3.0;acl "ACI Admin can manage ACI attributes";
allow (write) userdn = "ldap:///uid=ACI Admin,ou=People,dc=example,dc=com";)
dn: uid=ACI Admin,ou=People,dc=example,dc=com
changetype: modify
add: ds-privilege-name
ds-privilege-name: modify-acl
EOF
(Optional) Try LDAP examples
Try examples from Learn LDAP.
Babs Jensen does not have the access she had with the evaluation setup profile. For production servers, the best practice is to grant access only when required.
Example ACIs
Prepare to use the examples before trying them.
The ACI Admin
account must have access to manage ACIs.
After you add an example ACI, test users' access.
For inspiration, refer to the examples in Learn LDAP.
ACI syntax is powerful and sometimes challenging to get right. For details, refer to Access control.
ACI: access own entry
The following example grants authenticated users access to read their own entry, and modify some attributes:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "*") (version 3.0;acl "Users can read their entries";
allow (read, search, compare) (userdn = "ldap:///self");)
-
add: aci
aci: (targetattr = "authPassword || description || displayName || homePhone ||
jpegPhoto || preferredLanguage || userPassword")
(version 3.0;acl "Self-service modifications for basic attributes";
allow (write) (userdn = "ldap:///self");)
EOF
New-Item -Path . -Name "self-access.ldif" -ItemType "file" -Value @"
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "*") (version 3.0;acl "Users can read their entries";
allow (read, search, compare) (userdn = "ldap:///self");)
-
add: aci
aci: (targetattr = "authPassword || description || displayName || homePhone ||
jpegPhoto || preferredLanguage || userPassword")
(version 3.0;acl "Self-service modifications for basic attributes";
allow (write) (userdn = "ldap:///self");)
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" `
--bindPassword 5up35tr0ng `
self-access.ldif
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "*") (version 3.0;acl "Users can read their entries";
allow (read, search, compare) (userdn = "ldap:///self");)
-
add: aci
aci: (targetattr = "authPassword || description || displayName || homePhone ||
jpegPhoto || preferredLanguage || userPassword")
(version 3.0;acl "Self-service modifications for basic attributes";
allow (write) (userdn = "ldap:///self");)
EOF
In this example, the list of attributes users can read includes all user attributes. The list users can modify is limited. Other applications may manage other attributes; for example, a user’s manager could require a change through an HR system.
ACI: access subSchemaSubEntry attribute
The subSchemaSubEntry
attribute indicates the entry with the LDAP schema definitions for the current entry.
Many applications retrieve this attribute and the associated schema to properly display or validate attribute values.
The following example demonstrates how to grant access to read this attribute on directory entries:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "subSchemaSubEntry")
(version 3.0;acl "Authenticated users can read subSchemaSubEntry";
allow (read, search, compare) (userdn = "ldap:///all");)
EOF
New-Item -Path . -Name "subSchemaSubentry-access.ldif" -ItemType "file" -Value @"
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "subSchemaSubEntry")
(version 3.0;acl "Authenticated users can read subSchemaSubEntry";
allow (read, search, compare) (userdn = "ldap:///all");)
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" `
--bindPassword 5up35tr0ng `
subSchemaSubentry-access.ldif
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "subSchemaSubEntry")
(version 3.0;acl "Authenticated users can read subSchemaSubEntry";
allow (read, search, compare) (userdn = "ldap:///all");)
EOF
ACI: manage group membership
For some static groups, you might choose to let users manage their own memberships. The following example lets members of self-service groups manage their own membership:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: ou=Self Service,ou=Groups,dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "member") (version 3.0;acl "Self registration";
allow (selfwrite) (userdn = "ldap:///uid=*,ou=People,dc=example,dc=com");)
EOF
New-Item -Path . -Name "self-service-groups.ldif" -ItemType "file" -Value @"
dn: ou=Self Service,ou=Groups,dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "member") (version 3.0;acl "Self registration";
allow (selfwrite) (userdn = "ldap:///uid=*,ou=People,dc=example,dc=com");)
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" `
--bindPassword 5up35tr0ng `
self-service-groups.ldif
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: ou=Self Service,ou=Groups,dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "member") (version 3.0;acl "Self registration";
allow (selfwrite) (userdn = "ldap:///uid=*,ou=People,dc=example,dc=com");)
EOF
The selfwrite
permission is for adding or deleting one’s own DN from a group.
ACI: manage self-service groups
This example lets users create and delete self-managed groups:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: ou=Self Service,ou=Groups,dc=example,dc=com
changetype: modify
add: aci
aci: (targattrfilters="add=objectClass:(objectClass=groupOfNames)")
(version 3.0; acl "Users can create self-service groups";
allow (add) (userdn = "ldap:///uid=*,ou=People,dc=example,dc=com");)
-
add: aci
aci: (version 3.0; acl "Owner can delete self-service groups";
allow (delete) (userattr = "owner#USERDN");)
EOF
New-Item -Path . -Name "self-managed-groups.ldif" -ItemType "file" -Value @"
dn: ou=Self Service,ou=Groups,dc=example,dc=com
changetype: modify
add: aci
aci: (targattrfilters="add=objectClass:(objectClass=groupOfNames)")
(version 3.0; acl "Users can create self-service groups";
allow (add) (userdn = "ldap:///uid=*,ou=People,dc=example,dc=com");)
-
add: aci
aci: (version 3.0; acl "Owner can delete self-service groups";
allow (delete) (userattr = "owner#USERDN");)
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" `
--bindPassword 5up35tr0ng `
self-managed-groups.ldif
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: ou=Self Service,ou=Groups,dc=example,dc=com
changetype: modify
add: aci
aci: (targattrfilters="add=objectClass:(objectClass=groupOfNames)")
(version 3.0; acl "Users can create self-service groups";
allow (add) (userdn = "ldap:///uid=*,ou=People,dc=example,dc=com");)
-
add: aci
aci: (version 3.0; acl "Owner can delete self-service groups";
allow (delete) (userattr = "owner#USERDN");)
EOF
ACI: full access
The following ACI grants Babs Jensen permission to perform all LDAP operations,
allowing her full administrator access to the directory data under dc=example,dc=com
.
Babs can read and write directory data, rename and move entries, and use proxied authorization.
Some operations also require administrative privileges not shown in this example:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "* || +") (version 3.0;acl "Babs has full access";
allow (all, export, import, proxy) (userdn = "ldap:///uid=bjensen,ou=People,dc=example,dc=com");)
EOF
New-Item -Path . -Name "full-access.ldif" -ItemType "file" -Value @"
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "* || +") (version 3.0;acl "Babs has full access";
allow (all, export, import, proxy) (userdn = "ldap:///uid=bjensen,ou=People,dc=example,dc=com");)
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" `
--bindPassword 5up35tr0ng `
full-access.ldif
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "* || +") (version 3.0;acl "Babs has full access";
allow (all, export, import, proxy) (userdn = "ldap:///uid=bjensen,ou=People,dc=example,dc=com");)
EOF
(targetattr = "* || +")
permits access to all user attributes and all operational attributes.
allow (all, import, export, proxy)
permits all user operations, modify DN operations, and proxied authorization.
Notice all
doesn’t allow modify DN or proxied authorization.
ACI: anonymous reads and searches
In LDAP, an anonymous user is one who does not provide bind credentials. By default, most setup profiles only allow anonymous access to read information about the server’s capabilities or before using the StartTLS operation to get a secure connection before providing credentials.
Unless you set up the server with the evaluation profile, anonymous users cannot read application data by default. You can grant them access, however. First, change the global configuration to allow unauthenticated requests. Second, add an ACI to grant access to the entries.
The following command changes the global configuration property,
unauthenticated-requests-policy
,
to allow unauthenticated requests:
-
Bash
-
PowerShell
-
Zsh
$ dsconfig \
set-global-configuration-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword str0ngAdm1nPa55word \
--set unauthenticated-requests-policy:allow \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
dsconfig.bat `
set-global-configuration-prop `
--hostname localhost `
--port 4444 `
--bindDN uid=admin `
--bindPassword str0ngAdm1nPa55word `
--set unauthenticated-requests-policy:allow `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--no-prompt
$ dsconfig \
set-global-configuration-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword str0ngAdm1nPa55word \
--set unauthenticated-requests-policy:allow \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
This ACI makes all user attributes in dc=example,dc=com
data (except passwords) world-readable:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr != "authPassword || userPassword") (version 3.0;acl "Anonymous read-search access";
allow (read, search, compare) (userdn = "ldap:///anyone");)
EOF
New-Item -Path . -Name "anon-access.ldif" -ItemType "file" -Value @"
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr != "authPassword || userPassword") (version 3.0;acl "Anonymous read-search access";
allow (read, search, compare) (userdn = "ldap:///anyone");)
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" `
--bindPassword 5up35tr0ng `
anon-access.ldif
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr != "authPassword || userPassword") (version 3.0;acl "Anonymous read-search access";
allow (read, search, compare) (userdn = "ldap:///anyone");)
EOF
Notice ldap:///anyone
designates anonymous users and authenticated users.
Do not confuse it with ldap:///all
, which designates authenticated users only.
ACI: permit insecure access over loopback only
This ACI uses IP address and Security Strength Factor subjects
to prevent insecure remote access to dc=example,dc=com
data.
In most cases, you explicitly grant permission with allow
,
making it easier to understand and to explain why the server permits a given operation.
This demonstrates one use case where it makes sense to deny permission:
-
Bash
-
PowerShell
-
Zsh
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "* || +") (version 3.0;acl "Restrict insecure LDAP to the loopback address";
deny (all) (ip != "127.0.0.1" and ssf <= "1");)
EOF
New-Item -Path . -Name "deny-cleartext.ldif" -ItemType "file" -Value @"
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "* || +") (version 3.0;acl "Restrict cleartext LDAP to the loopback address";
deny (all) (ip != "127.0.0.1" and ssf <= "1");)
"@
ldapmodify.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" `
--bindPassword 5up35tr0ng `
deny-cleartext.ldif
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDn "uid=ACI Admin,ou=People,dc=example,dc=com" \
--bindPassword 5up35tr0ng << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "* || +") (version 3.0;acl "Restrict insecure LDAP to the loopback address";
deny (all) (ip != "127.0.0.1" and ssf <= "1");)
EOF
-
ssf = 1
means TLS is configured without a cipher.The server verifies integrity using packet checksums, but all content is sent in plain text.
-
ssf = 0
means the content is sent plain text with no connection security.
About directories
A directory resembles a dictionary. If you know a word, you can look up its entry in the dictionary to learn its definition or its pronunciation. If you are bored, curious, or have lots of time, you can also read through the dictionary or the directory.
Where a directory differs from a paper dictionary is in how entries are indexed. Dictionaries typically have only one method of indexation: alphabetical order. In contrast, directories index multiple attributes of their entries. They have indexes names, user identifiers, email addresses, and telephone numbers. You can look up a directory entry by any of these attributes.
PingDS implements the Lightweight Directory Access Protocol (LDAP). Nearly all of what follows is an introduction to LDAP.
PingDS also provides HTTP access to directory data. It helps to understand the underlying LDAP model whether you use HTTP or LDAP.
LDAP history
Phone companies have been managing directories for many decades. The internet itself has relied on distributed directory services like DNS since the mid-1980s.
In the late 1980s, experts from what is now the International Telecommunications Union published the X.500 set of international standards, including the Directory Access Protocol (DAP). The X.500 standards specify Open Systems Interconnect (OSI) protocols and data definitions for general purpose directory services. The X.500 standards were designed to meet the needs of systems built according to the X.400 standards, covering electronic mail services.
LDAP was developed in the early 1990s. LDAP was developed as an alternative for directory access over internet protocols (TCP/IP) rather than OSI protocols. TCP/IP is lightweight enough for desktop implementations. By the mid-1990s, LDAP directory servers were widely used.
LDAP directory servers replicate data. If one server goes down, lookups can continue on other servers. Until the late 1990s, LDAP servers were designed primarily for fast, highly available lookups. If the service needs to support more lookups, you add another replicated directory server.
As organizations rolled out bigger directories for more applications, they also needed fast, highly available updates. Around the year 2000, directories began to support replication with multiple read-write servers. After an update on one server, the service replays it on other peer servers. Adding more servers doesn’t make updates faster because each server must replay each update. The organizations with the very largest directories had trouble replicating all the changes fast enough.
The DS code base began in the mid-2000s when engineers decided the cost of adapting the existing C-based directory technology for high-performance updates would be higher than the cost of building new, high-performance directory using Java technology.
LDAP data
LDAP directory data is organized into entries, similar to the entries for words in the dictionary. LDAP entries usually hold identity data:
dn: uid=bjensen,ou=People,dc=example,dc=com
uid: bjensen
cn: Babs Jensen
cn: Barbara Jensen
facsimileTelephoneNumber: +1 408 555 1992
gidNumber: 1000
givenName: Barbara
homeDirectory: /home/bjensen
l: San Francisco
mail: bjensen@example.com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: posixAccount
objectClass: top
ou: People
ou: Product Development
roomNumber: 0209
sn: Jensen
telephoneNumber: +1 408 555 1862
uidNumber: 1076
Barbara Jensen’s entry has a number of attributes, such as uid: bjensen
, telephoneNumber: +1 408 555 1862
,
and objectClass: posixAccount
.
(The objectClass
attribute type indicates the required and optional attributes for the entry.
You can update object classes online and change the definitions of object classes and attributes.
Unlike many databases, directories let you extend the schema for the data while they’re running.)
When you look up Babs’s entry in the directory, you specify one or more attributes and values to match.
The directory server finds matching entries using one more of its indexes, returning them as it finds them.
Attribute values are not necessarily strings. Some attribute values, like certificates and photos, are binary.
Each entry has a unique identifier.
The previous example shows the identifier at the top of the entry, dn: uid=bjensen,ou=People,dc=example,dc=com
.
DN is an acronym for Distinguished Name.
No two entries in the directory have the same DN.
You must escape some characters when using them in DNs. The following example shows an entry with escaped characters in the DN:
-
Bash
-
PowerShell
$ ldapsearch \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=kvaughan,ou=People,dc=example,dc=com \
--bindPassword bribery \
--baseDN dc=example,dc=com \
"(uid=escape)"
Show output
dn: cn=DN Escape Characters \" \# \+ \, \; \< = \> \\,dc=example,dc=com objectClass: person objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: top givenName: DN Escape Characters uid: escape cn: DN Escape Characters " # + , ; < = > \ sn: " # + , ; < = > \ mail: escape@example.com
ldapsearch.bat `
--hostname localhost `
--port 1636 `
--useSsl `
--usePkcs12TrustStore C:\path\to\opendj\config\keystore `
--trustStorePassword:file C:\path\to\opendj\config\keystore.pin `
--bindDN uid=kvaughan,ou=People,dc=example,dc=com `
--bindPassword bribery `
--baseDN dc=example,dc=com `
"(uid=escape)"
Show output
dn: cn=DN Escape Characters \" \# \+ \, \; \< = \> \\,dc=example,dc=com objectClass: person objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: top givenName: DN Escape Characters uid: escape cn: DN Escape Characters " # + , ; < = > \ sn: " # + , ; < = > \ mail: escape@example.com
LDAP entries are arranged hierarchically in the directory.
The hierarchical organization resembles a file system on a PC or a web server.
Some illustrations picture this as an upside down tree structure or a pyramid.
The DN consists of components separated by commas, uid=bjensen,ou=People,dc=example,dc=com
.
The names are little-endian.
The components reflect the hierarchy of directory entries.

Barbara Jensen’s entry is located under an entry with DN ou=People,dc=example,dc=com
.
This is the organizational unit (OU) and parent entry for the people at Example.com.
The ou=People
entry is under dc=example,dc=com
, the base entry for Example.com.
DC is an acronym for Domain Component.
The directory has other base entries, such as cn=config
for the server configuration.
A directory can serve multiple organizations, too.
You might find dc=example,dc=com
, dc=mycompany,dc=com
, and o=myOrganization
in the same LDAP directory.
When you look up entries, you specify the base DN to look under in the same way
you need to know whether to look in an English or a French dictionary for a given word.
The root entry for the directory, technically the entry with DN ""
(the empty string), is called the root DSE.
It contains information about what the server supports and the base DNs it serves.
A directory server stores two kinds of attributes in a directory entry:
user attributes and operational attributes.
User attributes hold the information for users of the directory.
All attributes shown in the entry above are user attributes.
Operational attributes hold information used by the directory itself.
Examples of operational attributes include entryUUID
, modifyTimestamp
, and subschemaSubentry
.
When an LDAP search operation finds an entry in the directory, the directory server returns all the visible user attributes unless the search request restricts the list of attributes by specifying those attributes explicitly. The directory server does not return any operational attributes unless the search request specifically asks for them.
Generally speaking, applications should change only user attributes
and leave updates of operational attributes to the server.
Use the public server interfaces and commands to change server behavior.
An exception is access control instruction (aci
) attributes.
ACIs are operational attributes that control access to directory data.
Communication
Most HTTP applications connect to the server for each request and close the connection after the response comes.
LDAP has a different model. In LDAP, the client application connects to the server and authenticates. The client then requests any number of operations, perhaps processing results in between requests. The client finally disconnects when done, potentially days later.
The standard operations are as follows:
- Bind (authenticate)
-
The first operation in an LDAP session usually involves the client binding to the LDAP server with the server authenticating the client.
Authentication identifies the client’s identity in LDAP terms, the identity the server uses to authorize access to directory data the client wants to read or change.
If the client does not bind explicitly, the server treats the client as an anonymous client. What the server lets anonymous users do depends on access control and configuration settings.
The client can bind again (rebind) on the same connection.
- Search (lookup)
-
After binding, the client can look up entries under a specified base DN matching an LDAP filter. For example, to look up people with the email address
bjensen@example.com
at Example.com, you specifyou=People,dc=example,dc=com
as the base DN and(mail=bjensen@example.com)
as the LDAP filter. - Compare
-
After binding, the client can compare a specified attribute value with the value stored on an entry in the directory.
- Modify
-
After binding, the client can change one or more attribute values on an entry. Administrators usually restrict the attributes client applications can change.
- Add
-
After binding, the client can add one or more new LDAP entries to the server assuming it has access to do so.
- Delete
-
After binding, the client can delete one or more entries assuming it has access to do so. To delete an entry with other entries underneath, first delete the children, then the parent.
- Modify DN
-
After binding, the client can change an entry DN assuming it has access to do so. This renames the entry or moves it to another location.
For example, if Barbara changes her unique identifier from
bjensen
to something else, her DN would have to change. For another example, if you decide to consolidateou=Customers
andou=Employees
underou=People
instead, all the entries underneath must change distinguished names.Renaming entire branches of entries can be a major operation for the directory, so avoid moving entire branches if you can.
- Unbind
-
When done making requests, the client can request an unbind operation to end the LDAP session.
- Abandon
-
When a request takes too long to complete or when a search request returns too many entries, the client can send an abandon request to drop the operation in progress.
The server doesn’t have to send a response.
Controls and extensions
LDAP has standardized two mechanisms for extending what directory servers can do beyond the basic operations:
-
LDAP controls
-
LDAP extended operations
LDAP controls are information added to an LDAP message to specify how an LDAP operation should be processed:
-
The server-side sort request control tells the server to return search results in sorted order.
-
The subtree delete request control tells the server to remove child entries with the target entry.
-
The persistent search control lets the client application get change notifications with an ongoing server. Whenever changes happen in the scope of the search, the server sends additional search results. Persistent searches are "permanent" though they can be idle for long periods of time.
-
A directory server can send response controls when the response contains special information. Examples include responses for entry change notification, password policy, and paged results.
For the list of supported LDAP controls, refer to Supported LDAP controls.
LDAP extended operations are additional LDAP operations not included in the original standard list:
-
The cancel extended operation works like an abandon operation with a response from the server.
-
The StartTLS extended operation lets you connect on an unsecure port and start Transport Layer Security (TLS) negotiations to protect communications.
For the list of supported LDAP extended operations, refer to Supported LDAP extended operations.
Indexes
Directories have indexes for multiple attributes. By default, DS does not let normal users perform unindexed searches because servers have to scan an entire directory database when looking for matches.
As directory administrator, you make sure directory data is properly indexed. DS software provides tools for building and managing indexes. For details, refer to Indexes.
Schema
Some databases hold huge amounts of data per application in an application-specific layout. Although such databases can support multiple applications, data organization depends on the applications served.
In contrast, directories are designed for shared, centralized services. The shared, centralized nature of directory services fosters interoperability in practice. It has helped directory services be successful in the long term.
LDAP schemas make the shared model of directory user information possible. LDAP schemas define the data the directory can contain. Directory entries are not arbitrary objects. Their attributes are completely predictable from publicly readable definitions. Many schema definitions are literally standard and defined by RFCs. They are the same not just across a directory service but across different directory services.
Unlike some databases, a directory service can also LDAP schema updates over LDAP while it is running. This gives you great flexibility in adapting the directory to store new data without changing existing data and without stopping the directory service.
For a closer look, refer to LDAP schema.
Access control
Directory services support fine-grained access control.
The directory administrator controls who can access specific data and when, how, where, and under what conditions they can do so with access control instructions (ACIs); for example, ACIs let you:
-
Permit only specific directory operations.
-
Scope controls to apply to the whole directory or to a single entry.
-
Specify network conditions and the encryption strength required for an operation.
ACIs are stored on entries in the directory, so you can update access controls while the service is running. You can delegate control over ACIs to client applications. DS software combines ACIs and separate administrative privileges to secure access to directory data.
For more information, read Access control.
Replication
DS replication consists of copying each update to the directory service to multiple directory servers. This brings both redundancy, in the case of network partitions or of crashes, and scalability for read operations. Most directory deployments involve multiple servers replicating together.
Automated conflict resolution
With writable replicated servers, replication conflicts can arise; for example, two applications write different values to the same attribute on the same entry on the two replicas.
In nearly all cases, DS replication can resolve these situations automatically. This makes the directory service resilient and safe even in the unpredictable real world.
Scaling up
It’s easier to scale a directory service for read operations than for write operations.
To add capacity for read operations, add replicated servers.
Adding servers doesn’t scale up write operations because each write operation must be replayed everywhere. If you have N servers, you have N updates to replay.
Eventual consistency
Replication is eventually consistent.
When directory data changes on one server, it eventually converges to be the same everywhere. The data isn’t necessarily the same everywhere at any particular time, depending on the rate of changes.
Client applications sometimes get this wrong. They write to a pool of load balanced directory servers, immediately read back what they wrote, and can’t tolerate the possible differences. If application users complain about consistency, try mitigating poor application practices with a directory proxy.
HTTP access
DS software maps LDAP data as JSON resources over HTTP for REST clients (HDAP).
LDAP schemas define the HDAP data model:
-
LDAP entries hold sets of attributes, not arbitrarily nested objects.
Each HDAP resource is an JSON object with fields at the top level:
{ "_id" : "dc=com/dc=example/ou=People/uid=bjensen", "_rev" : "<revision>", "mail" : [ "bjensen@example.com" ], "cn" : [ "Barbara Jensen", "Babs Jensen" ], "sn" : [ "Jensen" ] }
-
JSON has arrays, ordered collections that can contain duplicates.
LDAP attributes are sets, unordered collections without duplicates.
HDAP arrays have set semantics in which no duplicates are allowed, and the element order is arbitrary.
If you want a field with nested JSON or an array instead of a set, define a json
syntax attribute.
For details, refer to Schema and JSON.
You can deploy HDAP as a separate gateway servlet or through an HTTP connection handler on a DS server.
Deployment
When you have understood enough of the concepts to build directory services, prepare the service and test it thoroughly before you roll out shared, centralized services for your organization.
Start with Deployment when beginning your project.
Best practices
Follow these best practices for writing effective, maintainable, high-performance directory client applications.
Authenticate correctly
Unless your application performs only read operations, authenticate to the directory server. Some directory services require authentication to read directory data.
Once you authenticate (bind), directory servers make authorization decisions based on your identity. With servers that support proxied authorization, once authenticated, your application can request an operation on behalf of another identity, such as the identity of the end user.
Your application therefore should have an account, such as cn=My App,ou=Apps,dc=example,dc=com
.
The directory administrator can authorize appropriate access for your application’s account,
and monitor your application’s requests to help you troubleshoot problems if they arise.
Applications can use simple, password-based authentication. When using password-based authentication, use secure connections to protect credentials over the network. For applications, prefer certificate-based authentication if possible.
Reuse connections
LDAP is a stateful protocol. You authenticate (bind), you perform operations, you unbind. The server maintains a context that lets it make authorization decisions concerning your requests. Therefore, reuse connections whenever possible.
Because LDAP supports asynchronous requests, it is normal and expected to make multiple requests over the same connection. Your application can share a pool of connections to avoid the overhead of setting them up and tearing them down.
Check connection health
In a network built for HTTP applications, your long-lived LDAP connections can get cut by network equipment configured to treat idle and old connections as stale resources to reclaim.
When you maintain a particularly long-lived connection, such as a connection for a persistent search, periodically perform a health check to maintain the connection operational.
A health check involves reading or writing an attribute on a well-known entry in your data. It can serve the purposes of maintaining the connection operational, and of verifying access to your data. A success result for a read indicates that the data is available, and the application can read it. A success result for a write indicates that the data is available, and the application can write to it. The exact check to perform depends on how your application uses the directory. Under some circumstances, your data might be temporarily read-only, for example.
When using a connection timeout, take care not to set the timeout so low that long operations, such as unindexed searches, fail to complete before the timeout.
Request exactly what you need all at once
By the time your application makes it to production, you should know what attributes you want. Request them explicitly, and request all the attributes in the same search.
For example, if you require mail
and cn
, then specify both attributes in your search request.
Use specific LDAP filters
The difference in results between a general filter (mail=*@example.com)
,
and a good, specific filter like (mail=user@example.com)
can be
huge numbers of entries and enormous amounts of processing time,
both for the directory server that has to return search results,
and for your application that has to sort through them.
Many use cases can be handled with short, specific filters. As a rule, prefer equality filters over substring filters.
DS servers reject unindexed searches by default, because unindexed searches are resource-intensive. If your application needs to use a filter that results in an unindexed search, work with the directory administrator to find a solution, such as adding the indexes required for your search filters.
Always use &
with !
to restrict the potential result set
before returning all entries that do not match part of the filter.
For example, (&(location=Oslo)(!(mail=birthday.girl@example.com)))
.
Make modifications specific
Specific modifications help directory servers apply and replicate your changes more effectively.
When you modify attributes with multiple values, such as a static group member attribute, replace or delete specific values individually, rather than replacing the entire list of values.
Trust result codes
Trust the LDAP result code from the directory server. For example, if you request a modification, and you get a success result, consider the operation a success. Do not immediately issue a search to get the modified entry.
LDAP replication model is loosely convergent. In other words, the directory server sends you the success result before replicating the change to every directory server replica across the network. If you issue a read immediately after a write, a load balancer may direct the request to another replica. The result might differ from what you expect.
The loosely convergent model means that the entry could have changed since you read it. If needed, use LDAP assertions to set conditions for your LDAP operations.
Handle input securely
When taking input directly from a user or another program, use appropriate methods to sanitize the data. Failure to sanitize the input data can leave your application vulnerable to injection attacks.
For Java applications, the PingDS format()
methods for filters and DNs
are similar to the Java String.format()
methods.
In addition to formatting the output, they escape the input objects.
When building a search filter, use one of the methods of the DS APIs to escape input.
Check group membership on the account, not the group
Reading an entire large static group entry to check membership is wasteful.
If you need to determine which groups an account belongs to, request the DS virtual attribute, isMemberOf
,
when you read the account entry.
Other directory servers use other names for this attribute that identifies the groups to an account belongs to.
Check support for features you use
Directory servers expose their capabilities as operational attribute values on the root DSE,
which is the entry whose DN is an empty string, ""
.
This lets your application discover capabilities at run time, rather than storing configuration separately. Putting effort into checking directory capabilities makes your application easier to deploy and to maintain.
For example, rather than hard-coding dc=example,dc=com
as a base DN in your configuration,
read the root DSE namingContexts
attribute.
Directory servers also expose their schema over LDAP.
The root DSE attribute subschemaSubentry
shows the DN of the entry for LDAP schema definitions.
Store large attribute values by reference
To serve results quickly with high availability, directory servers cache content and replicate it everywhere. If you already store large attribute values elsewhere, such as photos or audio messages, keep only a reference to external content in a user’s account.
Take care with persistent search and server-side sorting
A persistent search lets your application receive updates from the server as they happen by keeping the connection open and forcing the server to check whether to return additional results any time it performs a modification in the scope of your search. Directory administrators therefore might hesitate to grant persistent search access to your application.
DS servers expose a change log to let you discover updates with less overhead. If you do have to use a persistent search instead, try to narrow the scope of your search.
DS servers support a resource-intensive, standard operation called server-side sorting. When your application requests a server-side sort, the directory server retrieves all matching entries, sorts the entries in memory, and returns the results. For result sets of any size, server-side sorting ties up server resources that could be used elsewhere. Alternatives include sorting the results after your application receives them, or working with the directory administrator to enable appropriate browsing (virtual list view) indexes for applications that must regularly page through long lists of search results.
Reuse schemas where possible
DS servers come with schema definitions for a wide range of standard object classes and attribute types. Directories use unique, IANA-registered object identifiers (OIDs) to avoid object class and attribute type name clashes. The overall goal is Internet-wide interoperability.
Therefore, reuse schema definitions that already exist whenever you reasonably can. Reuse them as is. Do not try to redefine existing schema definitions.
If you must add schema definitions for your application, extend existing object classes with AUXILIARY classes. Take care to name your schemas such that they do not clash with other names.
When you have defined schema required for your application, work with the directory administrator to add your definitions to the directory service. DS servers let directory administrators update schema definitions over LDAP. There is no need to interrupt the service to add your application. Directory administrators can, however, have other reasons why they hesitate to add your schema definitions. Coming to the discussion prepared with good schema definitions, explanations of why they should be added, and evident regard for interoperability makes it easier for the directory administrator to grant your request.
Read directory server schemas during initialization
By default, PingDS APIs use a minimal, built-in core schema, rather than reading the schema from the server. Doing so automatically would incur a significant performance cost. Unless schemas change, your application only needs to read them once.
When you start your application, read directory server schemas as a one-off initialization step.
Once you have the directory server schema definitions, use them to validate entries.
Handle referrals
When a directory server returns a search result, the result is not necessarily an entry. If the result is a referral, then your application should follow up with an additional search based on the URIs provided in the result.
Troubleshooting: check result codes
LDAP result codes are standard, and listed in LDAP result codes.
When your application receives a result, it must rely on the result code value to determine what action to take. When the result is not what you expect, read or at least log the additional message information.
Troubleshooting: check server logs
If you can read the directory server access log, then check what the server did with your application’s request.
The following excerpt shows a successful search by cn=My App,ou=Apps,dc=example,dc=com
:
Show excerpt
{"eventName":"DJ-LDAP","client":{"ip":"<clientIp>","port":12345},"server":{"ip":"<serverIp>","port":1636},"request":{"protocol":"LDAPS","operation":"CONNECT","connId":4},"transactionId":"0","response":{"status":"SUCCESSFUL","statusCode":"0","elapsedTime":0,"elapsedTimeUnits":"MILLISECONDS"},"timestamp":"<timestamp>","_id":"<uuid>"}
{"eventName":"DJ-LDAP","client":{"ip":"<clientIp>","port":12345},"server":{"ip":"<serverIp>","port":1636},"request":{"protocol":"LDAPS","operation":"TLS","connId":4},"transactionId":"0","response":{"status":"SUCCESSFUL","statusCode":"0","elapsedTime":0,"elapsedTimeUnits":"MILLISECONDS"},"security":{"protocol":"TLSv1.3","cipher":"TLS_AES_128_GCM_SHA256","ssf":128},"timestamp":"<timestamp>","_id":"<uuid>"}
{"eventName":"DJ-LDAP","client":{"ip":"<clientIp>","port":12345},"server":{"ip":"<serverIp>","port":1636},"request":{"protocol":"LDAPS","operation":"BIND","connId":4,"msgId":1,"version":"3","dn":"cn=My App,ou=Apps,dc=example,dc=com","authType":"SIMPLE"},"transactionId":"<uuid>","response":{"status":"SUCCESSFUL","statusCode":"0","elapsedTime":1,"elapsedQueueingTime":0,"elapsedProcessingTime":1,"elapsedTimeUnits":"MILLISECONDS","additionalItems":{"ssf":128}},"userId":"cn=My App,ou=Apps,dc=example,dc=com","timestamp":"<timestamp>","_id":"<uuid>"}
{"eventName":"DJ-LDAP","client":{"ip":"<clientIp>","port":12345},"server":{"ip":"<serverIp>","port":1636},"request":{"protocol":"LDAPS","operation":"SEARCH","connId":4,"msgId":2,"dn":"dc=example,dc=com","scope":"sub","filter":"(uid=kvaughan)","attrs":["isMemberOf"]},"transactionId":"<uuid>","response":{"status":"SUCCESSFUL","statusCode":"0","elapsedTime":3,"elapsedQueueingTime":0,"elapsedProcessingTime":3,"elapsedTimeUnits":"MILLISECONDS","nentries":1,"entrySize":430},"userId":"cn=My App,ou=Apps,dc=example,dc=com","timestamp":"<timestamp>","_id":"<uuid>"}
{"eventName":"DJ-LDAP","client":{"ip":"<clientIp>","port":12345},"server":{"ip":"<serverIp>","port":1636},"request":{"protocol":"LDAPS","operation":"UNBIND","connId":4,"msgId":3},"transactionId":"<uuid>","timestamp":"<timestamp>","_id":"<uuid>"}
{"eventName":"DJ-LDAP","client":{"ip":"<clientIp>","port":12345},"server":{"ip":"<serverIp>","port":1636},"request":{"protocol":"LDAPS","operation":"DISCONNECT","connId":4},"transactionId":"0","response":{"status":"SUCCESSFUL","statusCode":"0","elapsedTime":0,"elapsedTimeUnits":"MILLISECONDS","reason":"Client Unbind"},"timestamp":"<timestamp>","_id":"<uuid>"}
Notice these features of the messages:
-
The request operation types appear in upper case.
-
The messages track the client information and identify the specific sequence of operations with connection ID (
connId
) and message ID (msgID
) numbers. -
The
elapsedTime
for the response indicates the total time to complete the request. TheelapsedQueueingTime
is the time the request waited in the queue. TheelapsedProcessingTime
is the time actively processing the request. -
A status code 0 corresponds to a successful result, as described in RFC 4511.
For details about the message format, refer to Access log format.
Next steps
After you work through the examples in these pages, try the following suggestions:
Learn about replication
Data replication is sometimes called the "killer feature" of LDAP directories. Its strengths are in enabling very high availability for directory services even during network outages, and automatically resolving conflicts that can occur when the network is down, for example. LDAP directories have been improving and hardening replication features for decades.
Its weaknesses are that replication protocols have not been standardized for interoperability, and that unwary developers can misunderstand its property of eventual consistency if they are too used to the strong, immediate consistency of monolithic, transactional databases.
Replication necessarily involves multiple servers and additional configuration. You can learn more about it by reading Replication and the related pages.
Browse DS documentation
Category | Topics Covered |
---|---|
DS features, fixes, and known issues |
|
Implementing common use cases for directory services |
|
Deploying PingDS in on-premises and cloud environments |
|
Installing DS software |
|
Upgrading DS software |
|
Configuring DS servers after installation |
|
Ensuring a PingDS deployment is secure |
|
Day-to-day operations for maintaining DS servers |
|
Configuring DS server logs |
|
What to monitor when running DS servers, and where to look for metrics and other information |
|
How to use LDAP features and command-line tools |
|
How to configure and use DS REST APIs for HTTP access (HDAP) |
|
The |
|
Evolving LDAP SDK and server APIs, including common APIs |
|
LDAP-specific features of DS software |
|
All default LDAP schema, including monitoring attributes and object classes |
|
DS server error log messages by category and ID |
|
Tools bundled with DS software |
Try third-party tools
LDAP is a standard protocol, and so you can use LDAP-compliant third-party tools to manage directory data:
Many software solutions include support for LDAP authentication and LDAP-based address books.
Ping Identity does not endorse or support third-party tools.
Use DS with AM
-
Backend directory servers in the AM Deployment planning documentation
-
Prepare external stores in the AM Installation documentation
-
Configure CTS token stores in the AM Core token service documentation.
-
You can install DS directory servers for use as external AM stores.
For details, refer to Setup profiles.
Use DS with IDM
-
External DS repository and Select a repository in the IDM Installation documentation
Also refer to Install DS as an IDM repository.
-
One-way synchronization from LDAP to IDM, Two-way synchronization between LDAP and IDM, and other LDAP-related pages in the IDM Samples documentation
-
DS repository configuration and Mappings with a DS repository in the IDM Object modeling documentation
-
Synchronize passwords with DS in the IDM Password synchronization documentation
Remove DS software
For details, refer to Uninstallation.
Glossary
- Abandon operation
-
LDAP operation to stop processing of a request in progress, after which the server drops the connection without a reply to the client application.
- Access control
-
Control to grant or to deny access to a resource.
- Access control instruction (ACI)
-
Instruction added as a directory entry attribute for fine-grained control over what a given user or group member is authorized to do in terms of LDAP operations and access to user data.
ACIs are implemented independently from privileges, which apply to administrative operations.
Related: Privilege
- Access control list (ACL)
-
An access control list connects a user or group of users to one or more security entitlements. For example, users in group sales are granted the entitlement read-only to some financial data.
- Access log
-
Server log tracing the operations the server processes including timestamps, connection information, and information about the operation itself.
- Account lockout
-
The act of making an account temporarily or permanently inactive after successive authentication failures.
- Active user
-
A user that has the ability to authenticate and use the services, having valid credentials.
- Add operation
-
LDAP operation to add a new entry or entries to the directory.
- Anonymous
-
A user that does not need to authenticate, and is unknown to the system.
- Anonymous bind
-
A bind operation using simple authentication with an empty DN and an empty password, allowing anonymous access such as reading public information.
- Approximate index
-
Index is used to match values that "sound like" those provided in the filter.
- Attribute
-
Properties of a directory entry, stored as one or more key-value pairs. Typical examples include the common name (
cn
) to store the user’s full name and variations of the name, user ID (uid
) to store a unique identifier for the entry, andmail
to store email addresses. - Attribute value assertion (AVA)
-
An attribute description and a matching rule assertion value for the attribute.
DS software uses AVAs in RDNs, and to determine whether an entry matches an assertion. For example, a search filter specifying the AVA
uid=bjensen
asserts that matching entries have auid
attribute value equal tobjensen
. - Audit log
-
Type of access log that dumps changes in LDIF.
- Authentication
-
The process of verifying who is requesting access to a resource; the act of confirming the identity of a principal.
- Authorization
-
The process of determining whether access should be granted to an individual based on information about that individual; the act of determining whether to grant or to deny a principal access to a resource.
- Backend
-
Repository that stores directory data. Different implementations with different capabilities exist.
- Binary copy
-
Backup files from one replica are restored on another replica.
- Bind operation
-
LDAP authentication operation to determine the client’s identity in LDAP terms, the identity which is later used by the server to authorize (or not) access to directory data that the client wants to lookup or change.
- Branch
-
The distinguished name (DN) of a non-leaf entry in the Directory Information Tree (DIT), and that entry and all its subordinates taken together.
Some administrative operations allow you to include or exclude branches by specifying the DN of the branch.
Related: Suffix
- Collective attribute
-
A standard mechanism for defining attributes that appear on all the entries in a particular subtree.
- Compare operation
-
LDAP operation to compare a specified attribute value with the value stored on an entry in the directory.
- Control
-
Information added to an LDAP message to further specify how an LDAP operation should be processed. DS supports many LDAP controls.
- Change sequence number (CSN)
-
An opaque string uniquely identifying a single change to directory data. A CSN indicates exactly when a change occurred on which replica. An example CSN is
010f016df804edca0000008fevaluation-only
.DS replication uses CSNs to replay replicated operations consistently on all replicas. DS replicas record CSNs in historical data values for
ds-sync-state
andds-sync-hist
attributes.When troubleshooting replication data consistency, it can be useful to interpret CSNs. Contact support for help.
- Database cache
-
Memory space set aside to hold database content.
- Delete operation
-
LDAP operation to remove an existing entry or entries from the directory.
- Directory
-
A directory is a network service which lists participants in the network such as users, computers, printers, and groups. The directory provides a convenient, centralized, and robust mechanism for publishing and consuming information about network participants.
- Directory hierarchy
-
A directory can be organized into a hierarchy in order to make it easier to browse or manage. Directory hierarchies normally represent something in the physical world, such as organizational hierarchies or physical locations.
For example, the top level of a directory may represent a company, the next level down divisions, the next level down departments, and down the hierarchy. Alternately, the top level may represent the world, the next level down countries, next states or provinces, and next cities.
- Directory Information Tree (DIT)
-
A set of directory entries organized hierarchically in a tree structure, where the vertices are the entries, and the arcs between vertices define relationships between entries.
- Directory object
-
A directory object is an item in a directory. Example objects include users, user groups, computers, and more. Objects may be organized into a hierarchy and contain identifying attributes.
Related: Entry
- Directory proxy server
-
Server that forwards LDAP requests to remote directory servers. A standalone directory proxy server does not store user data.
- Directory server
-
Server application for centralizing information about network participants. A highly available directory service consists of multiple directory servers configured to replicate directory data.
Related: Replication
- Directory superuser
-
Directory account with privileges to do full administration of the DS server, including bypassing access control evaluation, changing access controls, and changing administrative privileges.
Related: Superuser
- Distinguished name (DN)
-
Fully qualified name for a directory entry, such as
uid=bjensen,ou=People,dc=example,dc=com
, built by concatenating the entry RDN (uid=bjensen
) with the DN of the parent entry (ou=People,dc=example,dc=com
). - Domain
-
A replication domain consists of several directory servers sharing the same synchronized set of data.
The base DN of a replication domain specifies the base DN of the replicated data.
- Dynamic group
-
Group that specifies members using LDAP URLs.
- Entry
-
An entry is an object in the directory, defined by one of more object classes, and their related attributes.
- Entry cache
-
Memory space set aside to hold frequently accessed, large entries, such as static groups.
- Equality index
-
Index used to match values that correspond exactly (though generally without case sensitivity) to the value provided in the search filter.
- Errors log
-
Server log tracing server events, error conditions, and warnings, categorized and identified by severity.
- Etime
-
Elapsed time within the server to process a request, starting from the moment the decoded operation is available to be processed by a worker thread.
- Export
-
Save directory data in an LDIF file.
- Extended operation
-
Additional LDAP operation not included in the original standards. DS servers support several standard LDAP extended operations.
- Extensible match index
-
Index for a matching rule other than approximate, equality, ordering, presence, substring or VLV, such as an index for generalized time.
- External user
-
An individual that accesses company resources or services but is not working for the company. Typically, a customer or partner.
- Filter
-
An LDAP search filter is an expression that the server uses to find entries that match a search request, such as
(mail=*@example.com)
to match all entries having an email address in the example.com domain. - Group
-
Entry identifying a set of members whose entries are also in the directory.
- Generation ID
-
The initial state identifier for a replicated directory server base DN. It is a hash of the first 1000 entries of the base DN, computed when creating the backend, importing data from LDIF, or initializing replication.
Replication can only proceed between base DNs that have the same generation ID.
- HDAP
-
Short for HTTP Directory Access Protocol.
HDAP is not a standard. HDAP is the name of the feature providing REST APIs and HTTP access to directory data. HDAP translates HTTP requests to LDAP requests and LDAP responses to HTTP responses.
- HDAP gateway
-
Standalone HDAP web application.
- Idle time limit
-
Defines how long DS allows idle connections to remain open.
- Import
-
Read in and index directory data from an LDIF file.
- Inactive user
-
An entry in the directory that once represented a user but which is now no longer able to be authenticated.
- Index
-
Directory server backend feature to allow quick lookup of entries based on their attribute values.
- Index entry limit
-
When the number of entries that an index key points to exceeds the index entry limit, DS stops maintaining the list of entries for that index key.
- Internal user
-
An individual who works within the company either as an employee or as a contractor.
- LDAP Data Interchange Format (LDIF)
-
Standard, portable, text-based representation of directory content.
Refer to RFC 2849.
- LDAP URL
-
LDAP Uniform Resource Locator, such as
ldaps://ds.example.com:636/dc=example,dc=com??sub?(uid=bjensen)
.Refer to RFC 2255.
- LDAPS
-
LDAP over SSL.
- Lightweight Directory Access Protocol (LDAP)
-
A simple and standardized network protocol used by applications to connect to a directory, search for objects and add, edit or remove objects.
Refer to RFC 4510.
- Matching rule
-
Defines rules for performing matching operations against assertion values. Matching rules are frequently associated with an attribute syntax, and are used to compare values according to that syntax.
For example, the
distinguishedNameEqualityMatch
matching rule can be used to determine whether two DNs are equal and can ignore unnecessary spaces around commas and equal signs, differences in capitalization in attribute names, and other discrepancies. - Modify DN operation
-
LDAP modification operation to request that the server change the distinguished name of an entry.
- Modify operation
-
LDAP modification operation to request that the server change one or more attributes of an entry.
- Naming context
-
Base DN under which client applications can look for user data.
- Object class
-
Identifies entries that share certain characteristics. Most commonly, an entry’s object classes define the attributes that must and may be present on the entry.
Object classes are stored on entries as values of the
objectClass
attribute. Object classes are defined in the directory schema, and can be abstract (defining characteristics for other object classes to inherit), structural (defining the basic structure of an entry, one structural inheritance per entry), or auxiliary (for decorating entries already having a structural object class with other required and optional attributes). - Object identifier (OID)
-
String that uniquely identifies an object, such as
0.9.2342.19200300.100.1.1
for the user ID attribute or1.3.6.1.4.1.1466.115.121.1.15
forDirectoryString
syntax. - Operational attribute
-
An attribute that has a special (operational) meaning for the server, such as
pwdPolicySubentry
ormodifyTimestamp
.
- Ordering index
-
Index used to match values for a filter that specifies a range.
- Password policy
-
A set of rules regarding what sequence of characters constitutes an acceptable password. Acceptable passwords are generally those that would be too difficult for another user, or an automated program to guess and thereby defeat the password mechanism.
Password policies may require a minimum length, a mixture of different types of characters (lowercase, uppercase, digits, punctuation marks, and other characters), avoiding dictionary words or passwords based on the user’s name, and other attributes.
Password policies may also require that users not reuse old passwords and that users change their passwords regularly.
- Password reset
-
Password change performed by a user other than the user who owns the entry.
- Password storage scheme
-
Mechanism for encoding user passwords stored on directory entries. DS implements a number of password storage schemes.
- Password validator
-
Mechanism for determining whether a proposed password is acceptable for use. DS implements a number of password validators.
- Plugin
-
Java library with accompanying configuration that implements a feature through processing that is not essential to the core operation of DS servers.
As the name indicates, plugins can be plugged in to an installed server for immediate configuration and use without recompiling the server.
DS servers invoke plugins at specific points in the lifecycle of a client request. The DS configuration framework lets directory administrators manage plugins with the same tools used to manage the server.
- Presence index
-
Index used to match the fact that an attribute is present on the entry, regardless of the value.
- Principal
-
Entity that can be authenticated, such as a user, a device, or an application.
- Privilege
-
Server configuration settings controlling access to administrative operations such as exporting and importing data, restarting the server, performing password reset, and changing the server configuration.
Privileges are implemented independently from access control instructions (ACI), which apply to LDAP operations and user data.
Related: Access control instruction
- Referential integrity
-
Ensuring that group membership remains consistent following changes to member entries.
- Referint log
-
Server log tracing referential integrity events, with entries similar to the errors log.
- Referral
-
Reference to another directory location, which can be another directory server running elsewhere or another container on the same server, where the current operation can be processed.
- Relative distinguished name (RDN)
-
Initial portion of a DN that distinguishes the entry from all other entries at the same level, such as
uid=bjensen
inuid=bjensen,ou=People,dc=example,dc=com
.
- Replica
-
Directory server this is configured to use replication.
- Replication
-
Data synchronization that ensures all directory servers participating eventually share a consistent set of directory data.
- Replication server
-
Server dedicated to transmitting replication messages. A standalone replication server does not store user data.
- Root DSE
-
The directory entry with distinguished name "" (empty string), where DSE is an acronym for DSA-Specific Entry. DSA is an acronym for Directory Server Agent, a single directory server.
The root DSE serves to expose information over LDAP about what the directory server supports in terms of LDAP controls, auth password schemes, SASL mechanisms, LDAP protocol versions, naming contexts, features, LDAP extended operations, and other information.
- Schema
-
LDAP schema defines the object classes, attributes types, attribute value syntaxes, matching rules and other constrains on entries held by the directory server.
- Search filter
-
Refer to: Filter
- Search operation
-
LDAP lookup operation where a client requests that the server return entries based on an LDAP filter, and a base DN under which to search.
- Simple authentication
-
Bind operation performed with a user’s entry DN and user’s password.
Use simple authentication only if the network connection is secure.
- Size limit
-
Sets the maximum number of entries returned for a search.
- Static group
-
Group that enumerates member entries.
- Subentry
-
An entry, such as a password policy entry, that resides with the user data but holds operational data, and is not visible in search results unless explicitly requested.
- Substring index
-
Index used to match values specified with wildcards in the filter.
- Suffix
-
The distinguished name (DN) of a root entry in the Directory Information Tree (DIT), and that entry and all its subordinates taken together as a single object of administrative tasks such as export, import, indexing, and replication.
- Superuser
-
User with privileges to perform unconstrained administrative actions on DS server. This account is analogous to the Linux
root
and WindowsAdministrator
accounts.The conventional default superuser DN is
uid=admin
. You can create additional superuser accounts, each with different administrative privileges.Superuser privileges include the following:
-
bypass-acl
: The holder is not subject to access control. -
privilege-change
: The holder can edit administrative privileges. -
proxied-auth
: The holder can make requests on behalf of another user, including directory superusers.
Related: Directory superuser, Privilege
-
- Task
-
Mechanism to provide remote access to server administrative functions.
DS software supports tasks to back up and restore backends, to import and export LDIF files, and to stop and restart the server.
- Time limit
-
Defines the maximum processing time DS devotes to a search operation.
- Unbind operation
-
LDAP operation to release resources at the end of a session.
- Unindexed search
-
Search operation for which no matching index is available.
If no indexes are applicable, then the directory server potentially has to go through all entries to look for candidate matches. For this reason, the
unindexed-search
privilege, which allows users to request searches for which no applicable index exists, is reserved for the directory manager by default. - User
-
An entry that represents an individual that can be authenticated through credentials contained or referenced by its attributes. A user may represent an internal user or an external user, and may be an active user or an inactive user.
- User attribute
-
An attribute for storing user data on a directory entry such as
mail
orgivenname
. - Virtual attribute
-
An attribute with dynamically generated values that appear in entries but are not persistently stored in the backend.
- Virtual directory
-
An application that exposes a consolidated view of multiple physical directories over an LDAP interface. Consumers of the directory information connect to the virtual directory’s LDAP service.
Behind the scenes, requests for information and updates to the directory are sent to one or more physical directories where the actual information resides. Virtual directories enable organizations to create a consolidated view of information that for legal or technical reasons cannot be consolidated into a single physical copy.
- Virtual list view (VLV) index
-
Browsing index designed to help the directory server respond to client applications that need, for example, to browse through a long list of results a page at a time in a GUI.
- Virtual static group
-
DS group that lets applications get dynamic groups represented as static groups.
- X.500
-
A family of standardized protocols for accessing, browsing and maintaining a directory. X.500 is functionally similar to LDAP, but is generally considered to be more complex, and has consequently not been widely adopted.