Performing LDAP OperationsOpenDJ comes with a Control Panel browser for managing entries and also
command-line tools for performing LDAP operations. This chapter demonstrates
how to use the command line tools to script LDAP operations.Searching the DirectorySearching dataSearching the directory resembles searching for a phone number in
a paper phone book. You can look up a phone number because you know the
last name of a subscriber's entry. In other words, you use the value of
one attribute of the entry to find entries that have another attribute
you want.Yet whereas a paper phone book has only one index (alphabetical order
by name), the directory has many indexes. For a search you therefore always
specify which index to use, by specifying which attribute(s) you are using
to lookup entries.Your paper phone book might be divided into white pages for residential
subscribers, and yellow pages for businesses. If you are looking up an
individual's phone number, you limit your search to the white pages.
Directory services divide entries in various ways, often to separate
organizations, and to separate groups from user entries from printers for
example, but potentially in other ways. When searching you therefore also
specify where in the directory to search.The ldapsearch command thus takes at minimum a
search base DN option and an LDAP filter. The search base DN identifies
where in the directory to search for entries that match the filter.
For example, if you are looking for printers, you might specify the base
DN as ou=Printers,dc=example,dc=com. Perhaps you are
visiting the GNB00 office and are looking for a
printer.
$ ldapsearch --baseDN ou=Printers,dc=example,dc=com "(printerLocation=GNB00)"In the example, the LDAP filter indicates to the directory that you
want to lookup printer entries where the printerLocation
attribute is equal to GNB00.You also specify the host and port to access directory services,
what protocol to use (for example, LDAP/SSL, or StartTLS to protect
communication). If the directory service does not allow anonymous access
to the data you want to search, you also identify who is performing the
search and provide their credentials, such as a password or
certificate. Finally, you can specify a list of attributes to return.
If you do not specify attributes, then the search returns all user attributes
for the entry.Review the following examples in this section to get a sense of how
searches work.Search: Simple FilterThe following example searches for entries with user IDs
(uid) containing jensen, returning
only DNs and user ID values.
$ ldapsearch --port 1389 --baseDN dc=example,dc=com "(uid=*jensen*)" uiddn: uid=ajensen,ou=People,dc=example,dc=com
uid: ajensen
dn: uid=bjensen,ou=People,dc=example,dc=com
uid: bjensen
dn: uid=gjensen,ou=People,dc=example,dc=com
uid: gjensen
dn: uid=jjensen,ou=People,dc=example,dc=com
uid: jjensen
dn: uid=kjensen,ou=People,dc=example,dc=com
uid: kjensen
dn: uid=rjensen,ou=People,dc=example,dc=com
uid: rjensen
dn: uid=tjensen,ou=People,dc=example,dc=com
uid: tjensen
Result Code: 0 (Success)Search: Complex FilterThe following example returns entries with uid
containing jensen for users located in Santa Clara. The
command returns the attributes associated with the person
object class.
$ ldapsearch \
--port 1389 \
--baseDN ou=people,dc=example,dc=com \
"(&(uid=*jensen*)(l=Santa Clara))" \
@persondn: uid=ajensen,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
cn: Allison Jensen
telephoneNumber: +1 408 555 7892
sn: Jensen
dn: uid=gjensen,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
cn: Gern Jensen
telephoneNumber: +1 408 555 3299
sn: Jensen
dn: uid=kjensen,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
cn: Kurt Jensen
telephoneNumber: +1 408 555 6127
sn: Jensen
dn: uid=tjensen,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
cn: Ted Jensen
telephoneNumber: +1 408 555 8622
sn: Jensen
Complex filters can use both "and" syntax,
(&(filtercomp)(filtercomp)),
and "or" syntax,
(|(filtercomp)(filtercomp)).Search: Return Operational AttributesUse + in the attribute list after the filter
to return all operational attributes. Alternatively, specify operational
attributes by name.
$ ldapsearch --port 1389 --baseDN dc=example,dc=com uid=bjensen +dn: uid=bjensen,ou=People,dc=example,dc=com
numSubordinates: 0
structuralObjectClass: inetOrgPerson
pwdPolicySubentry: cn=Default Password Policy,cn=Password Policies,cn=config
subschemaSubentry: cn=schema
hasSubordinates: false
entryDN: uid=bjensen,ou=people,dc=example,dc=com
entryUUID: fc252fd9-b982-3ed6-b42a-c76d2546312cSearch: Return Attributes for an Object ClassUse @objectClass in the
attribute list after the filter to return the attributes associated with
a particular object class.
$ ldapsearch --port 1389 --baseDN dc=example,dc=com uid=bjensen @persondn: uid=bjensen,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
cn: Barbara Jensen
cn: Babs Jensen
telephoneNumber: +1 408 555 1862
sn: JensenSearch: Escaping Search Filter CharactersRFC 4515:
Lightweight Directory Access Protocol (LDAP): String Representation
of Search Filters mentions a number of characters that you must
handle with care when using them in search filters.For a filter like (attr=value), the following list indicates characters
that you must replace with a backslash ( \ ) followed
by two hexadecimal digits when using them as part of the
value string.Replace * with \2a.Replace ( with \28.Replace ) with \29.Replace \ with \5c.Replace NUL (0x00) with \00.The following example shows a filter with escaped characters matching
an actual value.
$ ldapsearch --port 1389 --baseDN dc=example,dc=com \
"(description=\28*\5c*\2a\29)" descriptiondn: uid=bjensen,ou=People,dc=example,dc=com
description: (A \great\ description*)Search: List Active AccountsOpenDJ supports extensible matching rules, meaning you can pass in
filters specifying a matching rule OID that extends your search beyond what
you can do with standard LDAP. One specific matching rule of this type that
OpenDJ supports is the generalized time based "later than" and "earlier
than" matching rules. See the example, Configure
an Extensible Match Index, showing how to build an index
for these matching rules.You can use these matching rules to list, for example, all users who
have authenticated recently.First set up an attribute to store a last login timestamp.
You can do this by adding a schema file for the attribute.
$ ldapmodify \
--port 1389 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password
dn: cn=schema
changetype: modify
add: attributeTypes
attributeTypes: ( lastLoginTime-oid
NAME 'lastLoginTime'
DESC 'Last time the user logged in'
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE
NO-USER-MODIFICATION
USAGE directoryOperation
X-ORIGIN 'OpenDJ example documentation' )Processing MODIFY request for cn=schema
MODIFY operation successful for DN cn=schemaConfigure the applicable password policy to write the last login
timestamp when a user authenticates. The following command configures the
default password policy to write the timestamp in generalized time format
to the lastLoginTime operational attribute on the user's
entry.
$ dsconfig \
set-password-policy-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--policy-name "Default Password Policy" \
--set last-login-time-attribute:lastLoginTime \
--set last-login-time-format:"yyyyMMddHH'Z'" \
--trustAll \
--no-promptWait a while for users to authenticate again (or test it yourself) so
that OpenDJ writes the timestamps. The following search then returns users
who have authenticated in the last three months (13 weeks) after you
configured OpenDJ to keep the last login timestamps.
$ ldapsearch \
--port 1389 \
--baseDN dc=example,dc=com \
"(lastLoginTime:1.3.6.1.4.1.26027.1.4.6:=13w)" maildn: uid=bjensen,ou=People,dc=example,dc=com
mail: bjensen@example.com
dn: uid=kvaughan,ou=People,dc=example,dc=com
mail: kvaughan@example.comSearch: Language SubtypeOpenDJ directory server supports many language subtypes. See the
chapter on Localization for a list.When you perform a search you can request the language subtype by
OID or by language subtype string. For example, the following search gets
the French version of a common name. The example uses the
base64 command provided with OpenDJ directory server to
decode the attribute value.
$ ldapsearch \
--port 1389 \
--baseDN dc=example,dc=com \
"(givenName:fr:=Fréderique)" cn\;lang-frdn: uid=fdupont,ou=People,dc=example,dc=com
cn;lang-fr:: RnJlZMOpcmlxdWUgRHVwb250
$ base64 decode -d RnJlZMOpcmlxdWUgRHVwb250Fredérique DupontAt the end of the OID or language subtype, you further specify the
matching rule as follows:Add .1 for less thanAdd .2 for less than or equal toAdd .3 for equal to (default)Add .4 for greater than or equal toAdd .5 for greater thanAdd .6 for substringThe following table describes the operators you can use in LDAP search
filters.Comparing Attribute ValuesComparing attribute valuesThe compare operation checks whether an attribute value you specify
matches the attribute value stored on one or more directory entries.Compare: Checking authPasswordIn this example, Kirsten Vaughan checks whether the hashed password
value matches the stored value on authPassword.
$ ldapcompare \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
'authPassword:MD5$dFHgpDxXUT8=$qlC4xMXvmVlusJLz9/WJ5Q==' \
uid=kvaughan,ou=people,dc=example,dc=comComparing type authPassword with value
MD5$dFHgpDxXUT8=$qlC4xMXvmVlusJLz9/WJ5Q== in entry
uid=kvaughan,ou=people,dc=example,dc=com
Compare operation returned true for entry
uid=kvaughan,ou=people,dc=example,dc=comUpdating the DirectoryUpdating dataLDIFExamplesAuthorized users can change directory data using the LDAP add, modify,
modify DN, and delete operations.Adding EntriesWith the ldapmodify -a command, authorized users
can add entire entries from the same sort of LDIF file used to import
and export data.Add: Two New Users
$ cat new-users.ldifdn: cn=Arsene Lupin,ou=Special Users,dc=example,dc=com
objectClass: person
objectClass: top
cn: Arsene Lupin
telephoneNumber: +33 1 23 45 67 89
sn: Lupin
dn: cn=Horace Velmont,ou=Special Users,dc=example,dc=com
objectClass: person
objectClass: top
cn: Horace Velmont
telephoneNumber: +33 1 12 23 34 45
sn: Velmont
$ ldapmodify \
--defaultAdd \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
--filename new-users.ldifProcessing ADD request for cn=Arsene Lupin,ou=Special Users,dc=example,dc=com
ADD operation successful for DN
cn=Arsene Lupin,ou=Special Users,dc=example,dc=com
Processing ADD request for cn=Horace Velmont,ou=Special Users,dc=example,dc=com
ADD operation successful for DN
cn=Horace Velmont,ou=Special Users,dc=example,dc=comModifying Entry AttributesWith the ldapmodify command, authorized users
can change the values of attributes in the directory using LDIF as specified
in RFC 2849.Modify: Adding AttributesThe following example adds a description and JPEG photo to Sam
Carter's entry.
$ cat scarter-mods.ldifdn: uid=scarter,ou=people,dc=example,dc=com
changetype: modify
add: description
description: Accounting Manager
-
add: jpegphoto
jpegphoto:<file:///tmp/Samantha-Carter.jpg
$ ldapmodify \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
--filename scarter-mods.ldifProcessing MODIFY request for uid=scarter,ou=people,dc=example,dc=com
MODIFY operation successful for DN uid=scarter,ou=people,dc=example,dc=comModify: Changing an Attribute ValueThe following example replaces the description on Sam Carter's
entry.
$ cat scarter-newdesc.ldifdn: uid=scarter,ou=people,dc=example,dc=com
changetype: modify
replace: description
description: Accounting Director
$ ldapmodify \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
--filename scarter-newdesc.ldifProcessing MODIFY request for uid=scarter,ou=people,dc=example,dc=com
MODIFY operation successful for DN uid=scarter,ou=people,dc=example,dc=comModify: Deleting an Attribute ValueThe following example deletes the JPEG photo on Sam Carter's
entry.
$ cat /path/to/scarter-deljpeg.ldifdn: uid=scarter,ou=people,dc=example,dc=com
changetype: modify
delete: jpegphoto
$ ldapmodify \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
--filename scarter-deljpeg.ldifProcessing MODIFY request for uid=scarter,ou=people,dc=example,dc=com
MODIFY operation successful for DN uid=scarter,ou=people,dc=example,dc=comModify: Optimistic ConcurrencyImagine you are writing an application that lets end users update
user profiles through a browser. You store user profiles as OpenDJ entries.
Your end users can look up user profiles and modify them. Your application
assumes that the end users can tell the right information when they see it,
and so aims to update profiles exactly as users see them on their
screens.Consider two users, Alice and Bob, both busy and often interrupted.
Alice has Babs Jensen's new phone and room numbers. Bob has Babs's new
location and description. Both assume that they have all the information
that has changed. What can you do to make sure that your application
applies the right changes when Alice and Bob simulaneously update Babs
Jensen's profile?OpenDJ offers a couple of features to help you in this situation.
One of the features is the LDAP Assertion
Control, used to tell OpenDJ to perform the modify only if
an assertion you make stays true. The other feature is OpenDJ's support
for entity tag (ETag) attributes, making it easy to
check whether the entry in the directory is the same as the entry you
read.Alice and Bob both get Babs's entry. In LDIF the relevant
attributes from the entry look like this. Notice the ETag.dn: uid=bjensen,ou=People,dc=example,dc=com
telephoneNumber: +1 408 555 1862
roomNumber: 0209
l: Cupertino
ETag: 000000007a1999dfBob prepares his changes in your application. Bob is almost ready
to submit the new location and description when Carol stops by to ask Bob
a few questions.Alice starts just after Bob, but manages to submit her changes
without getting interrupted. Now Babs's entry looks like this.dn: uid=bjensen,ou=People,dc=example,dc=com
description: Updated by Alice
telephoneNumber: +47 2108 1746
roomNumber: 1389
l: Cupertino
ETag: 00000000aec2c1e9In your application, you use the ETag attribute value with the
assertion control to prevent Bob's update from going through when the
ETag value has changed. Your application tries the equivalent of the
following commands with Bob's updates.
$ cat /path/to/bobs.ldifdn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: l
l: Grenoble
-
add: description
description: Employee of the Month
$ ldapmodify \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--port 1389 \
--filename /path/to/bobs.ldif \
--assertionFilter "(ETag=000000007a1999df)"Processing MODIFY request for uid=bjensen,ou=People,dc=example,dc=com
MODIFY operation failed
Result Code: 122 (Assertion Failed)
Additional Information: Entry uid=bjensen,ou=People,dc=example,dc=com
cannot be modified because the request contained an LDAP assertion control
and the associated filter did not match the contents of the that entryYour application therefore reloads Babs's entry, also getting the new
ETag value, 00000000aec2c1e9, and lets Bob try again.
This time Bob's changes do not collide with other changes. Babs's entry is
successfully updated.dn: uid=bjensen,ou=People,dc=example,dc=com
description: Employee of the Month
telephoneNumber: +47 2108 1746
roomNumber: 1389
l: Grenoble
ETag: 00000000e882c35eFiltering Add & Modify OperationsUpdating dataFilteringSome client applications send updates including attributes with names
that differ from the attribute names defined in OpenDJ. Other client
applications might try to update attributes they should not update, such
as the operational attributes creatorsName,
createTimestamp, modifiersName,
and modifyTimestamp. Ideally you would fix the client
application behavior, but that is not always feasible.You can configure the attribute cleanup plugin to filter add and
modify requests, renaming attributes in requests using incorrect names,
and removing attributes that applications should not change.Renaming Incoming AttributesThe following example renames incoming email
attributes to mail attributes. First, configure the
attribute cleanup plugin to rename the inbound attribute.
$ dsconfig \
create-plugin \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--type attribute-cleanup \
--plugin-name "Rename email to mail" \
--set enabled:true \
--set rename-inbound-attributes:email:mail \
--trustAll \
--no-promptNext, see that it works as expected.$ cat email.ldifdn: 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
email: newuser@example.com
userPassword: changeme
$ ldapmodify \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--defaultAdd \
--filename email.ldifProcessing ADD request for uid=newuser,ou=People,dc=example,dc=com
ADD operation successful for DN uid=newuser,ou=People,dc=example,dc=com
$ ldapsearch --port 1389 --baseDN dc=example,dc=com uid=newuser maildn: uid=newuser,ou=People,dc=example,dc=com
mail: newuser@example.comRemoving Incoming AttributesThe following example prevents client applications from adding or
modifying creatorsName,
createTimestamp, modifiersName,
and modifyTimestamp attributes. First, set up the
attribute cleanup plugin.
$ dsconfig \
create-plugin \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--type attribute-cleanup \
--plugin-name "Remove attrs" \
--set enabled:true \
--set remove-inbound-attributes:creatorsName \
--set remove-inbound-attributes:createTimestamp \
--set remove-inbound-attributes:modifiersName \
--set remove-inbound-attributes:modifyTimestamp \
--trustAll \
--no-promptNext, see that it works as expected.
$ cat badattrs.ldifdn: uid=badattr,ou=People,dc=example,dc=com
uid: newuser
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
cn: Bad Attr
sn: Attr
ou: People
mail: badattr@example.com
userPassword: changeme
creatorsName: cn=Bad Attr
createTimestamp: Never in a million years.
modifiersName: cn=Directory Manager,cn=Root DNs,cn=config
modifyTimestamp: 20110930164937Z
$ ldapmodify \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--defaultAdd \
--filename badattrs.ldifProcessing ADD request for uid=badattr,ou=People,dc=example,dc=com
ADD operation successful for DN uid=badattr,ou=People,dc=example,dc=com
$ ldapsearch --port 1389 --baseDN dc=example,dc=com uid=badattr +dn: uid=badattr,ou=People,dc=example,dc=com
numSubordinates: 0
structuralObjectClass: inetOrgPerson
pwdPolicySubentry: cn=Default Password Policy,cn=Password Policies,cn=config
subschemaSubentry: cn=schema
hasSubordinates: false
entryDN: uid=badattr,ou=people,dc=example,dc=com
entryUUID: 35e5cb0e-e929-49d8-a50f-2df036d60db9
pwdChangedTime: 20110930165959.135Z
creatorsName: cn=Directory Manager,cn=Root DNs,cn=config
createTimestamp: 20110930165959ZRenaming EntriesThe Relative Distinguished Name (RDN) refers to the part of an
entry's DN that distinguishes it from all other DNs at the same level
in the directory tree. For example uid=bjensen is
the RDN of the entry having DN
uid=bjensen,ou=People,dc=example,dc=com.With the ldapmodify command, authorized users
can rename entries in the directory.When you change the RDN of the entry, you are renaming the entry,
modifying the value of the naming attribute, but also modifying the entry's
DN.Rename: Modifying the DNSam Carter is changing her last name to Jensen, and changing her
login from scarter to sjensen.
The following example renames and changes Sam Carter's entry accordingly.
Notice the boolean field, deleteoldrdn: 1, which
indicates that the previous RDN, uid: scarter, should
be removed. (Setting deleteoldrdn: 0 instead would
preserve uid: scarter on the entry.)
$ cat /path/to/scarter-sjensen.ldifdn: uid=scarter,ou=people,dc=example,dc=com
changetype: modrdn
newrdn: uid=sjensen
deleteoldrdn: 1
dn: uid=sjensen,ou=people,dc=example,dc=com
changetype: modify
replace: cn
cn: Sam Jensen
-
replace: sn
sn: Jensen
-
replace: homeDirectory
homeDirectory: /home/sjensen
-
replace: mail
mail: sjensen@example.com
$ ldapmodify \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
--filename /path/to/scarter-sjensen.ldifProcessing MODIFY DN request for uid=scarter,ou=people,dc=example,dc=com
MODIFY DN operation successful for DN uid=scarter,ou=people,dc=example,dc=com
Processing MODIFY request for uid=sjensen,ou=people,dc=example,dc=com
MODIFY operation successful for DN uid=sjensen,ou=people,dc=example,dc=comMoving EntriesWhen you rename an entry with child entries, the directory has
to move all the entries underneath.The modify DN operation only works when moving entries in the same
backend, under the same suffix. Also, depending on the number of entries
you move, this can be a resource-intensive operation.With the ldapmodify command, authorized users
can move entries in the directory.Move: Merging Customer and Employees Under
ou=PeopleThe following example moves
ou=Customers,dc=example,dc=com to
ou=People,dc=example,dc=com, and then moves each
employee under ou=Employees,dc=example,dc=com
under ou=People,dc=example,dc=com as well, finally
removing the empty ou=Employees,dc=example,dc=com
container. Here, deleteoldrdn: 1 indicates that the
old RDN, ou: Customers, should be removed from the
entry. For employees, deleteoldrdn: 0 indicates that
old RDNs, in this case uid attribute values, should
be preserved.
$ cat move-customers.ldifdn: ou=Customers,dc=example,dc=com
changetype: modrdn
newrdn: ou=People
deleteoldrdn: 1
newsuperior: dc=example,dc=com
$ ldapmodify \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--filename move-customers.ldifProcessing MODIFY DN request for ou=Customers,dc=example,dc=com
MODIFY DN operation successful for DN ou=Customers,dc=example,dc=com
$ cat move-employees.pl#!/usr/bin/perl -w
# For each employee, construct a spec to move under ou=People.
while (<>)
{
# Next line folded for readability only. Should not be split.
$_ =~ s/dn: (.*?)(,.*)/dn: $1$2\nchangetype: moddn\nnewrdn: $1\n
deleteoldrdn: 0\nnewsuperior: ou=People,dc=example,dc=com/;
print;
}
$ ldapsearch --port 1389 --baseDN ou=Employees,dc=example,dc=com uid=* - \
| move-employees.pl > /tmp/move-employees.ldif
$ head -n 6 /tmp/move-employees.ldifdn: uid=abarnes,ou=Employees,dc=example,dc=com
changetype: moddn
newrdn: uid=abarnes
deleteoldrdn: 0
newsuperior: ou=People,dc=example,dc=com
$ ldapmodify \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--filename /tmp/move-employees.ldifProcessing MODIFY DN request for uid=abarnes,ou=Employees,dc=example,dc=com
MODIFY DN operation successful for DN uid=abarnes,ou=Employees,dc=example,dc=com
Processing MODIFY DN request for uid=abergin,ou=Employees,dc=example,dc=com
MODIFY DN operation successful for DN uid=abergin,ou=Employees,dc=example,dc=com
...
Processing MODIFY DN request for uid=wlutz,ou=Employees,dc=example,dc=com
MODIFY DN operation successful for DN uid=wlutz,ou=Employees,dc=example,dc=com
$ ldapdelete \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
ou=Employees,dc=example,dc=comProcessing DELETE request for ou=Employees,dc=example,dc=com
DELETE operation successful for DN ou=Employees,dc=example,dc=comDeleting EntriesWith the ldapmodify command, authorized users
can delete entries from the directory.Delete: Removing a SubtreeThe following example uses the subtree delete option to remove
all Special Users from the directory.
$ ldapdelete \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--deleteSubtree "ou=Special Users,dc=example,dc=com"Processing DELETE request for ou=Special Users,dc=example,dc=com
DELETE operation successful for DN ou=Special Users,dc=example,dc=comChanging PasswordsPasswordsChangingWith the ldappasswordmodify command, authorized
users can change and reset user passwords.Password ResetResetting passwordsThe following example shows Kirsten Vaughan resetting Sam Carter's
password. Kirsten has the appropriate privilege to reset Sam's
password.
$ ldappasswordmodify \
--useStartTLS \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
--authzID "dn:uid=scarter,ou=people,dc=example,dc=com" \
--newPassword ChangeMeThe LDAP password modify operation was successful
The ldappasswordmodify command uses
the LDAP Password Modify extended operation.
If this extended operation is performed on a connection
that is already associated with a user
—in other words, when a user first does a bind on the connection,
and then requests the LDAP Password Modify extended operation—
then the operation is performed as the user associated with the connection.
If the user associated with the connection
is not the user whose password is being changed,
then OpenDJ considers it a password reset.
Whenever one user changes another user's password,
OpenDJ considers it a password reset.
Often password policies specify that users
must change their passwords again after a password reset.
If you want your application to change a user's password,
rather than reset a user's password,
have your application request the password change
as the user whose password is changing.
To change the password as the user, you can
bind as the user whose password should be changed,
use the LDAP Password Modify extended operation
with an authorization ID but without performing a bind,
or use proxied authorization.
For instructions on using proxied authorization, see the section on
Configuring Proxied Authorization.
You could also accomplish password reset with the following command,
but set-password-is-reset is a hidden option, supported
only for testing.
$ manage-account \
set-password-is-reset \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--targetDN uid=scarter,ou=people,dc=example,dc=com \
--operationValue truePassword Is Reset: trueChange Own PasswordYou can use the ldappasswordmodify command to
change your password, as long as you know your current password.
$ ldappasswordmodify \
--port 1389 \
--authzID "dn:uid=bjensen,ou=people,dc=example,dc=com" \
--currentPassword hifalutin \
--newPassword secret12The LDAP password modify operation was successfulThe same operation works for cn=Directory
Manager.
$ ldappasswordmodify \
--port 1389 \
--authzID "dn:cn=Directory Manager" \
--currentPassword password \
--newPassword secret12The LDAP password modify operation was successfulPasswords With Special CharactersOpenDJ expects passwords to be UTF-8 encoded (base64 encoded when
included in LDIF).
$ echo $LANGen_US.utf8
$ ldappasswordmodify \
--port 1389 \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword hifalutin \
--currentPassword hifalutin \
--newPassword pàsswȏrdThe LDAP password modify operation was successful
$ ldapsearch \
--port 1389 \
--bindDN uid=bjensen,ou=People,dc=example,dc=com \
--bindPassword pàsswȏrd \
--baseDN dc=example,dc=com \
"(uid=bjensen)" cndn: uid=bjensen,ou=People,dc=example,dc=com
userPassword: {SSHA}k0eEeCxj9YRXUp8yJn0Z/mwqe+wrcFb1N1gg2g==
cn: Barbara Jensen
cn: Babs JensenConfiguring Default SettingsPortsSettings for toolsYou can use ~/.opendj/tools.properties to set
the defaults for bind DN, host name, and port number as in the following
example.hostname=directory.example.com
port=1389
bindDN=uid=kvaughan,ou=People,dc=example,dc=com
ldapcompare.port=1389
ldapdelete.port=1389
ldapmodify.port=1389
ldappasswordmodify.port=1389
ldapsearch.port=1389The location on Windows is
%UserProfile%/.opendj/tools.properties.Authenticating To the Directory ServerAuthenticatingAuthentication is the act of confirming the identity of a principal.
Authorization is the act of determining whether to grant or to deny access to
a principal. Authentication is done to make authorization decisions.As explained in Configuring
Privileges & Access Control, OpenDJ directory server
implements fine-grained access control for authorization. What is authorized
depends on who is requesting the operation. Directory servers like OpenDJ must
first therefore authenticate the principals using the clients before they can
authorize or deny access. The LDAP bind operation, where a directory client
authenticates with the directory server, is therefore the first LDAP operation
in every LDAP session.Clients bind by providing both a means to find their principal's entry
in the directory and also providing some credentials that the directory server
can check against their entry.In the simplest bind operation, the client provides a zero-length
name and a zero-length password. This results in an anonymous bind, meaning
the client is authenticated as an anonymous user of the directory. In the
simplest examples in , notice that no
authentication information is provided. The examples work because the
client commands default to requesting anonymous binds when you provide no
credentials, and because access controls for the sample data allow anonymous
clients to read, search, and compare some directory data.In a simple bind operation, the client provides an LDAP name, such as
the DN identifying its entry, and the corresponding password stored on the
userPassword attribute of the entry. In
, notice that to change directory data the
client provides the bind DN and bind password of a user who has permission
to change directory data. The commands do not work with a bind DN and bind
password because access controls for the sample data only allow authorized
users to change directory data.Users rarely provide client applications with DNs, however. Instead
users might provide a client application with an identity string like a user
ID or an email address for example. Depending on how the DNs are constructed,
the client application can either build the DN directly from the user's
identity string, or use a session where the bind has been done with some
other identity to search for the user entry based on the user's identity
string. Given the DN constructed or found, the client application can then
perform a simple bind.For example, suppose Babs Jensen enters her email address,
bjensen@example.com, and her password in order to log in.
The client application might search for the entry matching
(mail=bjensen@example.com) under base DN
dc=example,dc=com. Alternatively, the client application
might know to extract the user ID bjensen from the address,
and then build the corresponding DN,
uid=bjensen,ou=people,dc=example,dc=com in order to
bind.Identity mappersWhen an identifier string provided by the user can readily be mapped to
the user's entry DN, OpenDJ directory server can do the translation between
the identifier string and the entry DN. This translation is the job of a
component called an identity mapper. Identity mappers are used to perform
PLAIN SASL authentication (with a user name and password), SASL GSSAPI
authentication (Kerberos V5), SASL CRAM MD5 and DIGEST MD5 authentication.
They also handle authorization IDs during password modify extended operations
and proxied authorization.One use of PLAIN SASL is to translate user names from HTTP Basic
authentication to LDAP authentication. The following example shows PLAIN SASL
authentication using the default Exact Match identity mapper. In this
(contrived) example, Babs Jensen reads the hashed value of her password.
(According to the access controls in the example data, Babs must authenticate
to read her password.) Notice the authentication ID is her user ID,
u:bjensen, rather than the DN of her entry.
$ ldapsearch \
--port 1389 \
--useStartTLS \
--baseDN dc=example,dc=com \
--saslOption mech=PLAIN \
--saslOption authid=u:bjensen \
--bindPassword hifalutin \
"(cn=Babs Jensen)" cn userPassworddn: uid=bjensen,ou=People,dc=example,dc=com
cn: Barbara Jensen
cn: Babs Jensen
userPassword: {SSHA}7S4Si+vPE513cYQ7otiqb8hjiCzU7XNTv0RPBA==The Exact Match identity mapper searches for a match between the string
provided (here, bjensen) and the value of a specified
attribute (by default the uid attribute). If
you know users are entering their email addresses, you could create an
exact match identity mapper for email addresses, and then use that for PLAIN
SASL authentication as in the following example.
$ dsconfig \
create-identity-mapper \
--hostname opendj.example.com \
--port 4444 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--mapper-name "Email Mapper" \
--type exact-match \
--set match-attribute:mail \
--set enabled:true \
--no-prompt
$ dsconfig \
set-sasl-mechanism-handler-prop \
--hostname opendj.example.com \
--port 4444 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--handler-name PLAIN \
--set identity-mapper:"Email Mapper" \
--no-prompt
$ ldapsearch \
--port 1389 \
--useStartTLS \
--baseDN dc=example,dc=com \
--saslOption mech=PLAIN \
--saslOption authid=u:bjensen@example.com \
--bindPassword hifalutin \
"(cn=Babs Jensen)" cn userPassworddn: uid=bjensen,ou=People,dc=example,dc=com
cn: Barbara Jensen
cn: Babs Jensen
userPassword: {SSHA}7S4Si+vPE513cYQ7otiqb8hjiCzU7XNTv0RPBA==The Regular Expression identity mapper uses a regular expression to
extract a substring from the string provided, and then searches for a match
between the substring and the value of a specified attribute. In the case
of example data where an email address is user ID
+ @ + domain, you can use the default Regular
Expression identity mapper in the same way as the email mapper from the
previous example. The default regular expression pattern is
^([^@]+)@.+$, and the part of the identity string matching
([^@]+) is used to find the entry by user ID.
$ dsconfig \
set-sasl-mechanism-handler-prop \
--hostname opendj.example.com \
--port 4444 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--handler-name PLAIN \
--set identity-mapper:"Regular Expression" \
--no-prompt
$ ldapsearch \
--port 1389 \
--useStartTLS \
--baseDN dc=example,dc=com \
--saslOption mech=PLAIN \
--saslOption authid=u:bjensen@example.com \
--bindPassword hifalutin \
"(cn=Babs Jensen)" cn userPassworddn: uid=bjensen,ou=People,dc=example,dc=com
cn: Barbara Jensen
cn: Babs Jensen
userPassword: {SSHA}7S4Si+vPE513cYQ7otiqb8hjiCzU7XNTv0RPBA==Try the dsconfig command interactively to experiment
with match-pattern and replace-pattern
settings for the Regular Expression identity mapper. The
match-pattern can be any regular expression supported by
javax.util.regex.Pattern.Configuring Proxied AuthorizationProxied authorizationProxied authorization provides a standard control as defined in RFC 4370 (and an
earlier Internet-Draft) for binding with the user credentials of a proxy, who
carries out LDAP operations on behalf of other users. You might use proxied
authorization, for example, to have your application bind with its
credentials, and then carry out operations as the users who login to the
application.Suppose you have an administrative directory client application that
has an entry in the directory with DN
cn=My App,ou=Apps,dc=example,dc=com. You can give that
application the access rights and privileges to use proxied authorization.
The default access control for OpenDJ permits authenticated users to use
the proxied authorization control.Suppose also that when directory administrator, Kirsten Vaughan, logs
in to your application to change Babs Jensen's entry, your application looks
up Kirsten's entry, and finds that she has DN
uid=kvaughan,ou=People,dc=example,dc=com. For the example
commands in the following procedure. My App uses proxied authorization to
make a change to Babs's entry as Kirsten.To Set Up Proxied AuthorizationGrant access to applications that can use proxied authorization.
$ ldapmodify \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (target="ldap:///dc=example,dc=com") (targetattr ="*
")(version 3.0; acl "Allow apps proxied auth"; allow(all, proxy
)(userdn = "ldap:///cn=*,ou=Apps,dc=example,dc=com");)Processing MODIFY request for dc=example,dc=com
MODIFY operation successful for DN dc=example,dc=comGrant the privilege to use proxied authorization to My App.
$ ldapmodify \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password
dn: cn=My App,ou=Apps,dc=example,dc=com
changetype: modify
add: ds-privilege-name
ds-privilege-name: proxied-authProcessing MODIFY request for cn=My App,ou=Apps,dc=example,dc=com
MODIFY operation successful for DN cn=My App,ou=Apps,dc=example,dc=comTest that My App can use proxied authorization.
$ ldapmodify \
--port 1389 \
--bindDN "cn=My App,ou=Apps,dc=example,dc=com" \
--bindPassword password \
--proxyAs "dn:uid=kvaughan,ou=People,dc=example,dc=com"
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: Changed through proxied authProcessing MODIFY request for uid=bjensen,ou=People,dc=example,dc=com
MODIFY operation successful for DN uid=bjensen,ou=People,dc=example,dc=comIf you need to map authorization identifiers using the
u: form rather than using dn:, you can
set the identity mapper with the global configuration setting,
proxied-authorization-identity-mapper. For example, if you
get user ID values from the client, such as bjensen, you
can use the Exact Match Identity Mapper to match those to DNs based on an
attribute of the entry. Use the dsconfig command
interactively to investigate the settings you need.Authenticating Using a CertificateCertificatesStartTLSSSLOne alternative to simple binds with user name/password combinations
consists in storing a digital certificate on the user entry, and then using
the certificate as credentials during the bind. You can use this mechanism for
example to let applications bind without using passwords.Simply by setting up a secure connection with a certificate, the client
is in effect authenticating to the server. The server must close the
connection if it cannot trust the client certificate. However, the process
of establishing a secure connection does not in itself identify the client
to OpenDJ directory server.Instead when binding with a certificate, the client must request the
SASL External mechanism by which OpenDJ directory server maps the certificate
to the client entry in the directory. When it finds a match, OpenDJ sets the
authorization identity for the connection to that of the client, and the bind
is successful.For the whole process of authenticating with a certificate to work
smoothly, OpenDJ and the client must trust each others' certificates, the
client certificate must be stored on the client entry in the directory, and
OpenDJ must be configured to map the certificate to the client entry.To Add Certificate Information to an EntryBefore trying to bind to OpenDJ directory server using a certificate,
create a certificate, and then add the certificate attributes to the
entry.Example.ldif includes an entry for
cn=My App,ou=Apps,dc=example,dc=com. Examples in this
section use that entry, and use the Java keytool command
to manage the certificate.Create a certificate using the DN of the client entry as the
distinguished name string.
$ keytool \
-genkey \
-alias myapp-cert \
-keyalg rsa \
-dname "cn=My App,ou=Apps,dc=example,dc=com" \
-keystore keystore \
-storepass changeit \
-keypass changeitGet the certificate signed.If you cannot get the certificate signed by a Certificate Authority,
self-sign the certificate.
$ keytool \
-selfcert \
-alias myapp-cert \
-validity 7300 \
-keystore keystore \
-storepass changeit \
-keypass changeitMake note of the certificate fingerprints.Later in this procedure you update the client application entry with
the MD5 fingerprint, which in this example is
48:AC:F9:13:11:E0:AB:C4:65:A2:83:9E:DB:FE:0C:37.
$ keytool \
-list \
-v \
-alias myapp-cert \
-keystore keystore \
-storepass changeitAlias name: myapp-cert
Creation date: Jan 18, 2013
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=My App, OU=Apps, DC=example, DC=com
Issuer: CN=My App, OU=Apps, DC=example, DC=com
Serial number: 5ae2277
Valid from: Fri Jan 18 18:27:09 CET 2013 until: Thu Jan 13 18:27:09 CET 2033
Certificate fingerprints:
MD5: 48:AC:F9:13:11:E0:AB:C4:65:A2:83:9E:DB:FE:0C:37
SHA1: F9:61:54:37:AA:C1:BC:92:45:07:64:4B:23:6C:BC:C9:CD:1D:44:0F
SHA256: 2D:B1:58:CD:33:40:E9:...:FD:61:EA:C9:FF:6A:19:93:FE:E4:84:E3
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 54 C0 C5 9C 73 37 85 4B F2 3B D3 37 FD 45 0A AB T...s7.K.;.7.E..
0010: C9 6B 32 95 .k2.
]
]Export the certificate to a file in binary format.
$ keytool \
-export \
-alias myapp-cert \
-keystore keystore \
-storepass changeit \
-keypass changeit \
-file myapp-cert.crtCertificate stored in file </path/to/myapp-cert.crt>Modify the entry to add attributes related to the certificate.By default, you need the userCertificate
value.If you want OpenDJ to map the certificate to its fingerprint, use
ds-certificate-fingerprint. This example uses the MD5
fingerprint, which corresponds to the default setting for the Fingerprint
Certificate Mapper.If you want to map the certificate subject DN to an attribute of the
entry, use ds-certificate-subject-dn.
$ cat addcert.ldifdn: cn=My App,ou=Apps,dc=example,dc=com
changetype: modify
add: objectclass
objectclass: ds-certificate-user
-
add: ds-certificate-fingerprint
ds-certificate-fingerprint: 48:AC:F9:13:11:E0:AB:C4:65:A2:83:9E:DB:FE:0C:37
-
add: ds-certificate-subject-dn
ds-certificate-subject-dn: CN=My App, OU=Apps, DC=example, DC=com
-
add: userCertificate;binary
userCertificate;binary:<file:///path/to/myapp-cert.crt
$ ldapmodify \
--port 1389 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--filename addcert.ldifProcessing MODIFY request for cn=My App,ou=Apps,dc=example,dc=com
MODIFY operation successful for DN cn=My App,ou=Apps,dc=example,dc=comCheck your work.
$ ldapsearch \
--port 1389 \
--hostname opendj.example.com \
--baseDN dc=example,dc=com \
"(cn=My App)"dn: cn=My App,ou=Apps,dc=example,dc=com
ds-certificate-fingerprint: 4B:F5:CF:2C:2D:B3:86:14:FF:43:A8:37:17:DD:E7:55
userCertificate;binary:: MIIDOzCCAiOgAwIBAgIESfC6IjANBgkqhkiG9w0BAQsFADBOMRMwEQY
KCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTENMAsGA1UECxMEQXBwczEPMA
0GA1UEAxMGTXkgQXBwMB4XDTEzMDExNzE3MTEwM1oXDTEzMDQxNzE3MTEwM1owTjETMBEGCgmSJomT8
ixkARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxDTALBgNVBAsTBEFwcHMxDzANBgNVBAMT
Bk15IEFwcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJQYq+jG4ZQdNkyBT4OQBZ0sFkl
X5o2yBViDMGl1sSWIRGLpFwu6iq1chndPBJYTC+FkT66yEEOwWOpSfcYdFHkMQP0qp5A8mgP6bYkeH1
ROvQ1nhLs0ILuksR10CVIQ5b1zv6bGEFhA9gSKmpHfQOSt9PXq8+kuz+4RgZk9Il28tgDNMm91wSJr7
kqi5g7a2a7Io5s9L2FeLhVSBYwinWQnASk8nENrhcE0hHkrpGsaxdhIQBQQvm+SRC0dI4E9iwBGI3Lw
lV3a4KTa5DlYD6cDREI6B8XlSdc1DaIhwC8CbsE0WJQoCERSURdjkuHrPck6f69HKUFRiC7JMT3dFbs
CAwEAAaMhMB8wHQYDVR0OBBYEFFTAxZxzN4VL8jvTN/1FCqvJazKVMA0GCSqGSIb3DQEBCwUAA4IBAQ
BXsAIEw7I5XUzLFHvXb2N0hmW/Vmhb/Vlv9LTT8JcCRJy4zaiyS9Q+Sp9zQUkrXauFnNAhJLwpAymjZ
MCOq1Th1bw9LnIzbccPQ/1+ZHLKDU5pgnc5BcvaV6Zl6COLLH2OOt0XMZ/OrODBV1M6STfhChqcowff
xp72pWMQe+kpZfzjeDBk4kK2hUNTZsimB9qRyrDAMCIXdmdmFv1o07orxjy8c/6S1329swiiVqFckBR
aXIa8wCcXjpQbZacDODeKk6wZIKxw4miLg1YByCMa7vkUfz+Jj+JHgbHjyoT/G82mtDbX02chLgXbDm
xJPFN3mwAC7NEkSPbqd35nJlf3
objectClass: person
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: ds-certificate-user
objectClass: top
ds-certificate-subject-dn: CN=My App, OU=Apps, DC=example, DC=com
cn: My App
sn: AppWhen using a self-signed certificate, import the client certificate
into the trust store for OpenDJ.When the client presents its certificate to OpenDJ, by default OpenDJ
has to be able to trust the client certificate before it can accept the
connection. If OpenDJ cannot trust the client certificate, it cannot
establish a secure connection.
$ keytool \
-import \
-alias myapp-cert \
-file /path/to/myapp-cert.crt \
-keystore /path/to/opendj/config/truststore \
-storepass `cat /path/to/opendj/config/keystore.pin`Owner: CN=My App, OU=Apps, DC=example, DC=com
Issuer: CN=My App, OU=Apps, DC=example, DC=com
Serial number: 5ae2277
Valid from: Fri Jan 18 18:27:09 CET 2013 until: Thu Jan 13 18:27:09 CET 2033
Certificate fingerprints:
MD5: 48:AC:F9:13:11:E0:AB:C4:65:A2:83:9E:DB:FE:0C:37
SHA1: F9:61:54:37:AA:C1:BC:92:45:07:64:4B:23:6C:BC:C9:CD:1D:44:0F
SHA256: 2D:B1:58:CD:33:40:E9:...:FD:61:EA:C9:FF:6A:19:93:FE:E4:84:E3
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 54 C0 C5 9C 73 37 85 4B F2 3B D3 37 FD 45 0A AB T...s7.K.;.7.E..
0010: C9 6B 32 95 .k2.
]
]
Trust this certificate? [no]:yesCertificate was added to keystoreWhen using a certificate signed by a CA whose certificate is not
delivered with the Java runtime environment$JAVA_HOME/jre/lib/security/cacerts holds the
certificates for many CAs. To get the full list, use the following
command.
$ keytool \
-list \
-v \
-keystore $JAVA_HOME/jre/lib/security/cacerts \
-storepass changeit, import the CA certificate either
into the Java runtime environment trust store, or into the OpenDJ trust
store as shown in the following example.
$ keytool \
-import \
-alias ca-cert \
-file ca.crt \
-keystore /path/to/opendj/config/truststore \
-storepass `cat /path/to/opendj/config/keystore.pin`Owner: EMAILADDRESS=admin@example.com, CN=Example CA, O=Example Corp, C=FR
Issuer: EMAILADDRESS=admin@example.com, CN=Example CA, O=Example Corp, C=FR
Serial number: d4586ea05c878b0c
Valid from: Tue Jan 29 09:30:31 CET 2013 until: Mon Jan 24 09:30:31 CET 2033
Certificate fingerprints:
MD5: 8A:83:61:9B:E7:18:A2:21:CE:92:94:96:59:68:60:FA
SHA1: 01:99:18:38:3A:57:D7:92:7B:D6:03:8C:7B:E4:1D:37:45:0E:29:DA
SHA256: 5D:20:F1:86:CC:CD:64:50:1E:54:...:DF:15:43:07:69:44:00:FB:36:CF
Signature algorithm name: SHA1withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 30 07 67 7D 1F 09 B6 E6 90 85 95 58 94 37 FD 31 0.g........X.7.1
0010: 03 D4 56 7B ..V.
]
[EMAILADDRESS=admin@example.com, CN=Example CA, O=Example Corp, C=FR]
SerialNumber: [ d4586ea0 5c878b0c]
]
#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 30 07 67 7D 1F 09 B6 E6 90 85 95 58 94 37 FD 31 0.g........X.7.1
0010: 03 D4 56 7B ..V.
]
]
Trust this certificate? [no]:yesCertificate was added to keystoreIf you updated the OpenDJ trust store to add a certificate, restart
OpenDJ to make sure it reads the updated trust store and can recognize the
certificate.
$ stop-ds --restartStopping Server...
...
... The Directory Server has started successfullyTo Configure Certificate MappersOpenDJ uses certificate mappers during binds to establish a mapping
between a client certificate and the entry that corresponds to that
certificate. The certificate mappers provided out of the box include the
following.Fingerprint Certificate MapperLooks for the MD5 (default) or SHA1 certificate fingerprint in an
attribute of the entry (default:
ds-certificate-fingerprint).Subject Attribute To User Attribute MapperLooks for a match between an attribute of the certificate subject
and an attribute of the entry (default: match cn in
the certificate to cn on the entry, or match
emailAddress in the certificate to
mail on the entry).Subject DN to User Attribute Certificate MapperLooks for the certificate subject DN in an attribute of the entry
(default: ds-certificate-subject-dn).Subject Equals DN Certificate MapperLooks for an entry whose DN matches the certificate subject DN.If the default configurations for the certificate mappers are
acceptable, you do not need to change them. They are enabled by
default.The following steps demonstrate how to change the Fingerprint Mapper
default algorithm of MD5 to SHA1.List the certificate mappers to retrieve the correct name.
$ dsconfig \
list-certificate-mappers \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password
Certificate Mapper : Type : enabled
------------------------------------:-------------------------------------:--------
Fingerprint Mapper : fingerprint : true
Subject Attribute to User Attribute : subject-attribute-to-user-attribute : true
Subject DN to User Attribute : subject-dn-to-user-attribute : true
Subject Equals DN : subject-equals-dn : true
Examine the current configuration.
$ dsconfig \
get-certificate-mapper-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--mapper-name "Fingerprint Mapper"
Property : Value(s)
----------------------:---------------------------
enabled : true
fingerprint-algorithm : md5
fingerprint-attribute : ds-certificate-fingerprint
user-base-dn : -Change the configuration as necessary.
$ dsconfig \
set-certificate-mapper-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--mapper-name "Fingerprint Mapper" \
--set fingerprint-algorithm:sha1 \
--no-promptSet the External SASL Mechanism Handler to use the appropriate
certificate mapper (default: Subject Equals DN).Clients applications use the SASL External mechanism during the bind
to have OpenDJ set the authorization identifier based on the entry that
matches the client certificate.
$ dsconfig \
set-sasl-mechanism-handler-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--handler-name External \
--set certificate-mapper:"Fingerprint Mapper" \
--no-promptAuthenticate With Client CertificateInstead of providing a bind DN and password as for simple
authentication, use the SASL EXTERNAL authentication mechanism, and provide
the certificate. As a test with example data you can try an anonymous search,
and then try with certificate-based authentication.Before you try this example, make sure OpenDJ is set up to accept
StartTLS from clients, and that you have set up the client certificate
as described above. Next, create a password .pin file for your client key
store.
$ echo changeit > keystore.pin
$ chmod 400 keystore.pinAlso, if OpenDJ directory server uses a certificate for StartTLS that
was not signed by a well-known CA, import the appropriate certificate into
the client key store, which can then double as a trust store. For example,
if OpenDJ uses a self-signed certificate, import the server certificate into
the key store.
$ keytool \
-export \
-alias server-cert \
-file server-cert.crt \
-keystore /path/to/opendj/config/keystore \
-storepass `cat /path/to/opendj/config/keystore.pin`
$ keytool \
-import \
-trustcacerts \
-alias server-cert \
-file server-cert.crt \
-keystore keystore \
-storepass `cat keystore.pin`If OpenDJ directory server uses a CA-signed certificate, but the CA is
not well known, import the CA certificate into your keystore.
$ keytool \
-import \
-trustcacerts \
-alias ca-cert \
-file ca-cert.crt \
-keystore keystore \
-storepass `cat keystore.pin`Now that you can try the example, notice that OpenDJ does not return
the userPassword value for an anonymous search.
$ ldapsearch \
--port 1389 \
--hostname opendj.example.com \
--baseDN dc=example,dc=com \
--useStartTLS \
--trustStorePath keystore \
--trustStorePasswordFile keystore.pin \
"(cn=My App)" userPassworddn: cn=My App,ou=Apps,dc=example,dc=comOpenDJ does let users read the values of their own
userPassword attributes after they bind
successfully.
$ ldapsearch \
--port 1389 \
--hostname opendj.example.com \
--baseDN dc=example,dc=com \
--useStartTLS \
--useSASLExternal \
--certNickName myapp-cert \
--keyStorePath keystore \
--keyStorePasswordFile keystore.pin \
--trustStorePath keystore \
--trustStorePasswordFile keystore.pin \
"(cn=My App)" userPassworddn: cn=My App,ou=Apps,dc=example,dc=com
userPassword: {SSHA}vy/vTthOQoV/wH3MciTOBKKR4OX+0dSN/a09Ew==You can also try the same test with other certificate mappers.
# Fingerprint mapper
$ dsconfig \
set-sasl-mechanism-handler-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--handler-name External \
--set certificate-mapper:"Fingerprint Mapper" \
--no-prompt
$ ldapsearch \
--port 1389 \
--hostname opendj.example.com \
--baseDN dc=example,dc=com \
--useStartTLS \
--useSASLExternal \
--certNickName myapp-cert \
--keyStorePath keystore \
--keyStorePasswordFile keystore.pin \
--trustStorePath keystore \
--trustStorePasswordFile keystore.pin \
"(cn=My App)" userPassworddn: cn=My App,ou=Apps,dc=example,dc=com
userPassword: {SSHA}vy/vTthOQoV/wH3MciTOBKKR4OX+0dSN/a09Ew==
# Subject Attribute to User Attribute mapper
$ dsconfig \
set-sasl-mechanism-handler-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--handler-name External \
--set certificate-mapper:"Subject Attribute to User Attribute" \
--no-prompt
$ ldapsearch \
--port 1389 \
--hostname opendj.example.com \
--baseDN dc=example,dc=com \
--useStartTLS \
--useSASLExternal \
--certNickName myapp-cert \
--keyStorePath keystore \
--keyStorePasswordFile keystore.pin \
--trustStorePath keystore \
--trustStorePasswordFile keystore.pin \
"(cn=My App)" userPassworddn: cn=My App,ou=Apps,dc=example,dc=com
userPassword: {SSHA}vy/vTthOQoV/wH3MciTOBKKR4OX+0dSN/a09Ew==
# Subject DN to User Attribute mapper
$ dsconfig \
set-sasl-mechanism-handler-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--handler-name External \
--set certificate-mapper:"Subject DN to User Attribute" \
--no-prompt
$ ldapsearch \
--port 1389 \
--hostname opendj.example.com \
--baseDN dc=example,dc=com \
--useStartTLS \
--useSASLExternal \
--certNickName myapp-cert \
--keyStorePath keystore \
--keyStorePasswordFile keystore.pin \
--trustStorePath keystore \
--trustStorePasswordFile keystore.pin \
"(cn=My App)" userPassworddn: cn=My App,ou=Apps,dc=example,dc=com
userPassword: {SSHA}vy/vTthOQoV/wH3MciTOBKKR4OX+0dSN/a09Ew==