Passwords
DS servers simplify safe, centralized password management. DS servers use password policies to govern passwords.
Which password policy applies
The operational attribute, pwdPolicySubentry
, identifies an account’s password policy.
The default global access control instructions prevent this operational attribute from being visible to normal users.
The following example grants access to a group of administrators:
$ 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: ou=People,dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "pwdPolicySubentry||ds-pwp-password-policy-dn")
(version 3.0;acl "Allow Administrators to manage user's password policy";
allow (all) (groupdn = "ldap:///cn=Directory Administrators,ou=Groups,dc=example,dc=com");)
EOF
$ 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=bjensen)" \
pwdPolicySubentry
dn: uid=bjensen,ou=People,dc=example,dc=com
pwdPolicySubentry: cn=Default Password Policy,cn=Password Policies,cn=config
Configure password policies
Adjust the default password policy
You can reconfigure the default password policy, for example, to check that passwords do not contain complete attribute values, and to prevent password reuse. The default policy is a per-server password policy.
-
Apply the changes to the default password policy:
$ dsconfig \ set-password-policy-prop \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --policy-name "Default Password Policy" \ --set password-history-count:7 \ --set password-validator:Attribute\ Value \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --no-prompt
-
Check your work:
$ dsconfig \ get-password-policy-prop \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --policy-name "Default Password Policy" \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --no-prompt Property : Value(s) ------------------------------------------:-------------------------- account-status-notification-handler : - allow-expired-password-changes : false allow-user-password-changes : true default-password-storage-scheme : PBKDF2-HMAC-SHA256 deprecated-password-storage-scheme : - expire-passwords-without-warning : false force-change-on-add : false force-change-on-reset : false grace-login-count : 0 idle-lockout-interval : 0 s last-login-time-attribute : - last-login-time-format : - lockout-duration : 0 s lockout-failure-count : 0 lockout-failure-expiration-interval : 0 s max-password-age : 0 s max-password-reset-age : 0 s min-password-age : 0 s password-attribute : userPassword password-change-requires-current-password : false password-expiration-warning-interval : 5 d password-generator : Random Password Generator password-history-count : 7 password-history-duration : 0 s password-validator : Attribute Value previous-last-login-time-format : - require-change-by-time : - require-secure-authentication : true require-secure-password-changes : true
-
Test changes to the default password policy.
For example, the following tests demonstrate the attribute value password validator. The attribute value password validator rejects a new password when the password is contained in attribute values on the user’s entry.
By default, the attribute value password validator checks all attributes, checks whether portions of the password string match attribute values, where the portions are strings of length 5, and checks the reverse of the password as well:
$ dsconfig \ get-password-validator-prop \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --validator-name Attribute\ Value \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --no-prompt Property : Value(s) -----------------------:-------------------------------------------------- check-substrings : true enabled : true match-attribute : All attributes in the user entry will be checked. min-substring-length : 5 test-reversed-password : true
Consider the attributes present on Babs Jensen’s entry:
$ 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 \ "(uid=bjensen)" dn: uid=bjensen,ou=People,dc=example,dc=com objectClass: person objectClass: cos objectClass: oauth2TokenObject objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: posixAccount objectClass: top classOfService: bronze cn: Barbara Jensen cn: Babs Jensen departmentNumber: 3001 description: Original description diskQuota: 10 GB facsimileTelephoneNumber: +1 408 555 1992 gidNumber: 1000 givenName: Barbara homeDirectory: /home/bjensen l: San Francisco mail: bjensen@example.com mailQuota: 1 GB manager: uid=trigden, ou=People, dc=example,dc=com oauth2Token: {"access_token":"123","expires_in":59,"token_type":"Bearer","refresh_token":"456"} ou: Product Development ou: People preferredLanguage: en, ko;q=0.8 roomNumber: 0209 sn: Jensen street: 201 Mission Street Suite 2900 telephoneNumber: +1 408 555 1862 uid: bjensen uidNumber: 1076
Using the attribute value password validator, passwords like
bjensen12
andbabsjensenspwd
are not valid because substrings of the password match complete attribute values:$ ldappasswordmodify \ --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 \ --newPassword bjensen12 The LDAP password modify operation failed: 19 (Constraint Violation) Additional Information: The provided new password failed the validation checks defined in the server: The provided password was found in another attribute in the user entry $ ldappasswordmodify \ --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 \ --newPassword babsjensenspwd The LDAP password modify operation failed: 19 (Constraint Violation) Additional Information: The provided new password failed the validation checks defined in the server: The provided password was found in another attribute in the user entry
The attribute value password validator does not check, however, whether the password contains substrings of attribute values:
$ ldappasswordmodify \ --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 \ --newPassword babsp4ssw0rd The LDAP password modify operation was successful $ ldappasswordmodify \ --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 babsp4ssw0rd \ --newPassword example.com The LDAP password modify operation was successful
To avoid the problem of the latter example, you could use a dictionary password validator where the dictionary includes
example.com
.
Configure a NIST-inspired subentry policy
You can configure a password policy inspired by NIST 800-63 requirements:
-
Use a strong password storage scheme.
-
Enforce a minimum password length of 8 characters.
-
Check for matches in a dictionary of compromised passwords.
-
Do not use composition rules for password validation.
In other words, do not require a mix of special characters, upper and lower case letters, numbers, or other composition rules.
-
Do not enforce arbitrary password changes.
In other words, do not set a maximum password age.
Follow these steps to set up a replicated, NIST-inspired LDAP subentry password policy:
-
Gzip a copy of a text file of common compromised passwords, one word per line.
This example shows the gzipped text file as
/tmp/10k_most_common.gz
. After successfully updating a subentry password policy with the dictionary data, the input file is no longer required. Lists of common passwords can be found online. -
Make sure you have enabled a strong storage scheme.
Creating a password storage scheme requires access to edit the server configuration, which you might not have when creating a subentry password policy. This example therefore uses the
PBKDF2-HMAC-SHA512
storage scheme, which is enabled by default to use 10,000 iterations.This scheme is intentionally much slower and more CPU-intensive than the
PBKDF2-HMAC-SHA256
scheme with 10 iterations used by the default password policy when you install DS. Test that you have enough resources to sustain the expected peak rates of impacted operations before using a much stronger password storage scheme in your production deployment.Impacted operations include:
-
Adding or importing entries with passwords.
-
Authenticating using a password, such as simple bind.
-
Updating or resetting a password.
-
-
Make sure password policy administrators have the
subentry-write
privilege, and any required ACIs needed to write password policy subentries in the directory data.The following example grants access to password administrators. The administrator accounts are in the data where the password policy is to be stored:
$ 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: cn=subentry-write privilege for administrators,dc=example,dc=com objectClass: collectiveAttributeSubentry objectClass: extensibleObject objectClass: subentry objectClass: top cn: subentry-write privilege for administrators ds-privilege-name;collective: subentry-write subtreeSpecification: {base "ou=people", specificationFilter "(isMemberOf=cn=Directory Administrators,ou=Groups,dc=example,dc=com)" } dn: dc=example,dc=com changetype: modify add: aci aci: (target="ldap:///dc=example,dc=com") (targetattr = "*||ds-pwp-password-policy-dn||pwdPolicySubentry||subtreeSpecification") (version 3.0; acl "Admins can manage entries and password policies"; allow(all) groupdn = "ldap:///cn=Directory Administrators,ou=Groups,dc=example,dc=com";) EOF
Notice here that the directory superuser,
uid=admin
, assigns privileges. Any administrator with theprivilege-change
privilege can assign privileges. However, if the administrator can update administrator privileges, they can assign themselves thebypass-acl
privilege. Then they are no longer bound by access control instructions, including both user data ACIs and global ACIs. For this reason, do not assign theprivilege-change
privilege to normal administrator users. -
Create the password policy as one of the password policy administrators:
$ ldapmodify \ --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 << EOF dn: cn=NIST inspired policy,dc=example,dc=com objectClass: top objectClass: subentry objectClass: ds-pwp-password-policy objectClass: ds-pwp-validator objectClass: ds-pwp-length-based-validator objectClass: ds-pwp-dictionary-validator cn: NIST inspired policy ds-pwp-password-attribute: userPassword ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA512 ds-pwp-length-based-min-password-length: 8 ds-pwp-dictionary-data:<file:///tmp/10k_most_common.gz subtreeSpecification: {base "ou=people", specificationFilter "(objectclass=person)" } EOF
After successfully adding the policy with the dictionary data, you can delete the input file.
-
Check the password policy works appropriately.
The following example shows a rejected password modification:
$ ldappasswordmodify \ --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 \ --newPassword secret12 The LDAP password modify operation failed: 19 (Constraint Violation) Additional Information: The provided new password failed the validation checks defined in the server: The provided password was found in another attribute in the user entry
The following example shows an accepted password modification:
$ ldappasswordmodify \ --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 \ --newPassword aET1OjQeVJECSMgxDPs3U6In The LDAP password modify operation was successful
Create a per-server password policy
This example adds a per-server password policy for new users who have not yet used their credentials to bind:
-
Create the new password policy:
$ dsconfig \ create-password-policy \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --policy-name "New Account Password Policy" \ --set default-password-storage-scheme:PBKDF2-HMAC-SHA256 \ --set force-change-on-add:true \ --set password-attribute:userPassword \ --type password-policy \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --no-prompt
As per-server password policies are not replicated, repeat this step on all replica directory servers.
-
Check your work:
$ dsconfig \ get-password-policy-prop \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --policy-name "New Account Password Policy" \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --no-prompt Property : Value(s) ------------------------------------------:------------------- account-status-notification-handler : - allow-expired-password-changes : false allow-user-password-changes : true default-password-storage-scheme : PBKDF2-HMAC-SHA256 deprecated-password-storage-scheme : - expire-passwords-without-warning : false force-change-on-add : true force-change-on-reset : false grace-login-count : 0 idle-lockout-interval : 0 s last-login-time-attribute : - last-login-time-format : - lockout-duration : 0 s lockout-failure-count : 0 lockout-failure-expiration-interval : 0 s max-password-age : 0 s max-password-reset-age : 0 s min-password-age : 0 s password-attribute : userPassword password-change-requires-current-password : false password-expiration-warning-interval : 5 d password-generator : - password-history-count : 0 password-history-duration : 0 s password-validator : - previous-last-login-time-format : - require-change-by-time : - require-secure-authentication : false require-secure-password-changes : false
-
Change the user’s password policy after the password is successfully updated.
For instructions on assigning a per-server password policy, see Assign a password policy to a user.
List subentry password policies
Per-server password policies are part of the DS server configuration.
Use the dsconfig
command to list, read, and edit them.
Subentry policies are part of the DS directory data.
Use the ldapsearch
command to list and read them.
The following command lists the subentry password policies under dc=example,dc=com
:
$ 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 \
"(&(objectClass=subEntry)(objectClass=ds-pwp-password-policy))"
dn: cn=NIST inspired policy,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
objectClass: ds-pwp-validator
objectClass: ds-pwp-length-based-validator
objectClass: ds-pwp-dictionary-validator
cn: NIST inspired policy
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA512
ds-pwp-dictionary-data:: <data>
ds-pwp-length-based-min-password-length: 8
ds-pwp-password-attribute: userPassword
Assign password policies
Type | To Assign… |
---|---|
Per-server password policy |
Set the ds-pwp-password-policy-dn operational attribute on the user’s account. |
Subentry password policy |
Use one of the following methods:
|
Do not assign more than one password policy to the same account. Conflicting password policies will yield inconsistent results. You can review the password policy assigned to an account by reading the |
Assign a password policy to a user
-
Make sure the password administrator has access to manage password policies:
$ 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: cn=subentry-write privilege for administrators,dc=example,dc=com objectClass: collectiveAttributeSubentry objectClass: extensibleObject objectClass: subentry objectClass: top cn: subentry-write privilege for administrators ds-privilege-name;collective: subentry-write subtreeSpecification: {base "ou=people", specificationFilter "(isMemberOf=cn=Directory Administrators,ou=Groups,dc=example,dc=com)" } dn: dc=example,dc=com changetype: modify add: aci aci: (target="ldap:///dc=example,dc=com") (targetattr = "*||ds-pwp-password-policy-dn||pwdPolicySubentry||subtreeSpecification") (version 3.0; acl "Admins can manage entries and password policies"; allow(all) groupdn = "ldap:///cn=Directory Administrators,ou=Groups,dc=example,dc=com";) EOF
Notice here that the directory superuser,
uid=admin
, assigns privileges. Any administrator with theprivilege-change
privilege can assign privileges. However, if the administrator can update administrator privileges, they can assign themselves thebypass-acl
privilege. Then they are no longer bound by access control instructions, including both user data ACIs and global ACIs. For this reason, do not assign theprivilege-change
privilege to normal administrator users. -
Set the user’s
ds-pwp-password-policy-dn
attribute as the password administrator:$ ldapmodify \ --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 << 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 ds-pwp-password-policy-dn: cn=NIST inspired policy,dc=example,dc=com EOF
-
Check your work:
$ 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=newuser)" \ pwdPolicySubentry dn: uid=newuser,ou=People,dc=example,dc=com pwdPolicySubentry: cn=NIST inspired policy,dc=example,dc=com
Assign a password policy to a group
You can use a collective attribute to assign a password policy. Collective attributes provide a standard mechanism for defining attributes that appear on all the entries in a subtree. For details, see Collective attributes:
-
Make sure the password administrator has the privilege to write subentries:
$ 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=kvaughan,ou=People,dc=example,dc=com changetype: modify add: ds-privilege-name ds-privilege-name: subentry-write EOF
Notice here that the directory superuser,
uid=admin
, assigns privileges. Any administrator with theprivilege-change
privilege can assign privileges. However, if the administrator can update administrator privileges, they can assign themselves thebypass-acl
privilege. Then they are no longer bound by access control instructions, including both user data ACIs and global ACIs. For this reason, do not assign theprivilege-change
privilege to normal administrator users. -
Create a subentry defining the collective attribute that sets the
ds-pwp-password-policy-dn
attribute for group members' entries:$ ldapmodify \ --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 << EOF dn: cn=Password Policy for Dir Admins,dc=example,dc=com objectClass: collectiveAttributeSubentry objectClass: extensibleObject objectClass: subentry objectClass: top cn: Password Policy for Dir Admins ds-pwp-password-policy-dn;collective: cn=Root Password Policy,cn=Password Policies,cn=config subtreeSpecification: { base "ou=People", specificationFilter "(isMemberOf=cn=Directory Administrators,ou=Groups,dc=example,dc=com)"} EOF
-
Check your work:
$ 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=kvaughan)" \ pwdPolicySubentry dn: uid=kvaughan,ou=People,dc=example,dc=com pwdPolicySubentry: cn=Root Password Policy,cn=Password Policies,cn=config
Assign a password policy to a branch
These steps apply only to subentry password policies:
-
Give an administrator the privilege to write subentries, such as those used for setting password policies:
$ 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=kvaughan,ou=People,dc=example,dc=com changetype: modify add: ds-privilege-name ds-privilege-name: subentry-write EOF
Notice here that the directory superuser,
uid=admin
, assigns privileges. Any administrator with theprivilege-change
privilege can assign privileges. However, if the administrator can update administrator privileges, they can assign themselves thebypass-acl
privilege. Then they are no longer bound by access control instructions, including both user data ACIs and global ACIs. For this reason, do not assign theprivilege-change
privilege to normal administrator users. -
Configure a subentry password policy with a
subtreeSpecification
attribute that defines which accounts are assigned the policy.The following example assigns
cn=NIST inspired policy
to accounts underou=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=kvaughan,ou=people,dc=example,dc=com \ --bindPassword bribery << EOF dn: cn=NIST inspired policy,dc=example,dc=com changetype: modify replace: subtreeSpecification subtreeSpecification: { base "ou=people" } EOF
The subtree specification assigns the policy to the people branch with
{ base "ou=people" }
. You could relax the subtree specification value to{}
to apply the policy to all entries anywhere underneathdc=example,dc=com
. You could further restrict the subtree specification by adding aspecificationFilter
. For details, see About subentry scope. -
Check your work to see that an account under
ou=People
has the policy:$ 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=alutz)" \ pwdPolicySubentry dn: uid=alutz,ou=People,dc=example,dc=com pwdPolicySubentry: cn=NIST inspired policy,dc=example,dc=com
About subentry scope
LDAP subentries reside with the user data and so the server replicates them.
Subentries hold operational data.
They are not visible in search results unless explicitly requested.
This section describes how a subentry’s subtreeSpecification
attribute defines
the scope of the subtree that the subentry applies to.
An LDAP subentry’s subtree specification identifies a subset of entries in a branch of the DIT. The subentry scope is these entries. In other words, these are the entries that the subentry affects.
The attribute value for a subtreeSpecification
optionally includes the following parameters:
base
-
Indicates the entry, relative to the subentry’s parent, at the base of the subtree.
By default, the base is the subentry’s parent.
specificationFilter
-
Indicates an LDAP filter. Entries matching the filter are in scope.
DS servers extend the standard implementation to allow any search filter, not just an assertion about the
objectClass
attribute.By default, all entries under the base entry are in scope.
The following illustration shows this for an example collective attribute subentry:
Notice that the base of ou=People
on the subentry cn=Silver Class of Service,dc=example,dc=com
indicates
that the base entry is ou=People,dc=example,dc=com
.
The filter "(classOfService=silver)"
means that Kirsten Vaughan and Sam Carter’s entries are in scope.
Babs Jensen’s entry, with classOfService: bronze
does not match and is therefore not in scope.
The ou=People
organizational unit entry does not have a classOfService
attribute, and so is not in scope, either.
Strong and safe passwords
The difficulty with passwords is that they tend to be relatively easy to guess. Despite decades of advice on how to pick strong passwords, people still routinely pick very weak passwords using common words and phrases or simple variations of them. This makes them extremely easy to guess. Attackers with access to even modest hardware can make billions of guesses per second.
DS servers provide flexible password validation to fit your policies about password content, and to reject weak passwords when users try to save them. It also provides a variety of one-way and reversible password storage schemes. Password strength is a function of both password minimum length, which you can set as part of password policy, and password quality, which requires password validation.
Password validation
When a password is added or updated, a password validator determines whether the server should accept it. Validation does not affect existing passwords.
A user’s password policy specifies which password validators apply whenever that user provides a new password.
Subentry password policies can include attributes of password validator object classes.
Each object class derives from the abstract ds-pwp-validator
class:
The example that follows shows a password policy that requires new passwords to have at least three of the following four character classes:
-
English lowercase characters (a through z)
-
English uppercase characters (A through Z)
-
Base 10 digits (0 through 9)
-
Punctuation characters (for example, !, $, #, %)
Notice how the character-set
values are constructed.
The initial 0:
means the set is optional, whereas 1:
means the set is required:
$ 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: cn=Policy with character set validation,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
objectClass: ds-pwp-validator
objectClass: ds-pwp-character-set-validator
cn: Policy with character set validation
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-character-set-allow-unclassified-characters: true
ds-pwp-character-set-character-set-ranges: 0:a-z
ds-pwp-character-set-character-set-ranges: 0:A-Z
ds-pwp-character-set-character-set-ranges: 0:0-9
ds-pwp-character-set-character-set: 0:!$%^.#
ds-pwp-character-set-min-character-sets: 3
subtreeSpecification: { base "ou=people", specificationFilter "(uid=bjensen)" }
EOF
$ ldappasswordmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password \
--authzID "u:bjensen" \
--newPassword '!ABcd$%^'
An attempt to set an invalid password fails as shown in the following example:
$ ldappasswordmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password \
--authzID "u:bjensen" \
--newPassword hifalutin
The LDAP password modify operation failed: 19 (Constraint Violation)
Additional Information: The provided new password failed the validation
checks defined in the server: The provided password did not contain characters
from at least 3 of the following character sets or ranges: '!$%^.#', '0-9',
'A-Z', 'a-z'
Per-server password policies use validators that are separate configuration objects. The following example lists the password validators available by default for per-server password policies. By default, no password validators are configured in the default password policy:
$ dsconfig \
list-password-validators \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
Password Validator : Type : enabled
------------------------------------:---------------------:--------
At least 8 characters : length-based : true
Attribute Value : attribute-value : true
Character Set : character-set : true
Common passwords : dictionary : true
Dictionary : dictionary : false
Length-Based Password Validator : length-based : true
Repeated Characters : repeated-characters : true
Similarity-Based Password Validator : similarity-based : true
Unique Characters : unique-characters : true
For details, see Password Validator.
For an example showing how to test password quality, see Check Password Quality.
Password storage
Password storage schemes, described in Password Storage Scheme, encode new passwords and store the encoded version. When a client application authenticates with the password, the server encodes the plaintext password using the configured storage scheme, and checks whether the result matches the encoded value stored by the server. If the encoded version is appropriately secure, it is difficult to guess the plaintext password from its encoded value.
DS servers offer a variety of reversible and one-way password storage schemes. With a reversible encryption scheme, an attacker who gains access to the server can recover the plaintext passwords. With a one-way hash storage scheme, the attacker who gains access to the server must still crack the password by brute force, encoding passwords over and over to generate guesses until a match is found. If you have a choice, use a one-way password storage scheme.
Some one-way hash functions are not designed specifically for password storage, but also for use in message authentication and digital signatures. Such functions, like those defined in the Secure Hash Algorithm (SHA-1 and SHA-2) standards, are designed for high performance. Because they are fast, they allow the server to perform authentication at high throughput with low response times. However, high-performance algorithms also help attackers use brute force techniques. One estimate in 2017 is that a single GPU can calculate over one billion SHA-512 hashes per second.
Some one-way hash functions are designed to be computationally intensive. Such functions, like PBKDF2, Argon2, and Bcrypt, are designed to be relatively slow, even on modern hardware. This makes them generally less susceptible to brute force attacks. However, computationally intensive functions reduce authentication throughput and increase response times. With the default number of iterations, the GPU mentioned above might only calculate 100,000 PBKDF2 hashes per second (or 0.01% of the corresponding hashes calculated with SHA-512). If you use these functions, be aware of the potentially dramatic performance impact and plan your deployment accordingly. |
Modern hardware and techniques to pre-compute attempts, such as rainbow tables, make it increasingly easy for attackers to crack passwords by brute force. Password storage schemes that use salt make brute force attacks more expensive. In this context, salt is a random value appended to the password before encoding. The salt is then stored with the encoded value and used when comparing an incoming password to the stored password.
Reversible password storage schemes, such as AES and Blowfish, use symmetric keys for encryption.
The following example lists available alternatives, further described in Password Storage Schemes:
$ dsconfig \
list-password-storage-schemes \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
Password Storage Scheme : Type : enabled
------------------------:--------------------:--------
3DES : triple-des : false
AES : aes : false
Argon2 : argon2 : true
Base64 : base64 : false
Bcrypt : bcrypt : true
Blowfish : blowfish : false
Clear : clear : false
CRYPT : crypt : false
PBKDF2 : pbkdf2 : false
PBKDF2-HMAC-SHA256 : pbkdf2-hmac-sha256 : true
PBKDF2-HMAC-SHA512 : pbkdf2-hmac-sha512 : true
PKCS5S2 : pkcs5s2 : false
Salted SHA-1 : salted-sha1 : false
Salted SHA-256 : salted-sha256 : false
Salted SHA-384 : salted-sha384 : false
Salted SHA-512 : salted-sha512 : false
SCRAM-SHA-256 : scram-sha256 : true
SCRAM-SHA-512 : scram-sha512 : true
SHA-1 : sha1 : false
As shown in Adjust the default password policy,
the default password storage scheme for users is PBKDF2-HMAC-SHA256.
When you add users or import user entries with userPassword
values in plaintext,
the DS server hashes them with the default password storage scheme.
The default directory superuser has a different password policy,
shown in Assign a password policy to a group.
The Root Password Policy uses PBKDF2-HMAC-SHA256 by default.
The choice of default password storage scheme for normal users can significantly impact server performance. Each time a normal user authenticates using simple bind (username/password) credentials, the directory server encodes the user’s password according to the storage scheme in order to compare it with the encoded value in the user’s entry. Schemes such as Salted SHA-512 call for relatively high-performance encoding. Schemes such as PBKDF2-HMAC-SHA256, which are designed to make the encoding process computationally intensive, reduce the bind throughput that can be achieved on equivalent hardware. Take this performance impact into consideration when sizing your deployment. With a computationally intensive scheme such as PBKDF2-HMAC-SHA256, make sure the directory service has enough compute power to absorb the additional load. |
Name | Type of Algorithm | Notes |
---|---|---|
3DES(1) |
Reversible encryption(2) |
Triple DES (Data Encryption Standard) in EDE (Encrypt Decrypt Encrypt) mode. Key size: 168 bits. |
AES(1) |
Reversible encryption(2) |
Advanced Encryption Standard, successor to DES, published by the US National Institute of Standards and Technology (NIST). Key size: 128 bits. |
Argon2 |
One-way hash |
Computationally intensive, memory-hard hashing function. For default settings, see Additional Password Storage Scheme Settings. |
Base64 |
Reversible encoding |
Transfer encoding for representing binary password values in text. Not intended as a secure storage scheme. |
Bcrypt |
One-way hash |
Computationally intensive hashing function, based on the Blowfish cipher. Default cost: 12 (2^12 iterations). |
Blowfish(1) |
Reversible encryption(2) |
Public domain cipher designed by Bruce Schneier as a successor to DES. Key size: 128 bits. |
Clear |
Cleartext, no encoding |
For backwards compatibility and use with certain legacy applications. Not intended as a secure storage scheme. |
CRYPT |
One-way hash |
Based on the UNIX Crypt algorithm. For backwards compatibility and use with certain legacy applications. Not intended as a secure storage scheme. Default algorithm: |
MD5 |
One-way hash |
Based on the MD5 algorithm defined in RFC 1321. For backwards compatibility and use with certain legacy applications. Not intended as a secure storage scheme. |
PBKDF2 |
One-way hash |
Computationally intensive hashing function, based on PBKDF2 algorithm defined in RFC 8018, 5.2. PBKDF2. Default iterations: 10000. The pseudorandom function for the algorithm corresponds to the HMAC based on SHA-1. |
PBKDF2-HMAC-SHA256 |
One-way hash |
Computationally intensive hashing function using PBKDF2. Default iterations: 10000. The pseudorandom function for the algorithm corresponds to the HMAC based on SHA-2, where the hash function is SHA-256. |
PBKDF2-HMAC-SHA512 |
One-way hash |
Computationally intensive hashing function using PBKDF2. Default iterations: 10000. The pseudorandom function for the algorithm corresponds to the HMAC based on SHA-2, where the hash function is SHA-512. |
PKCS5S2 |
One-way hash |
Computationally intensive hashing function, based on Atlassian’s adaptation of the PBKDF2. Number of iterations: 10000. |
RC4(1) |
Reversible encryption(2) |
Based on the Rivest Cipher 4 algorithm. For backwards compatibility and use with certain legacy applications. Not intended as a secure storage scheme. Key size: 128 bits. |
Salted MD5 |
One-way hash |
Based on MD5, with 64 bits of random salt appended to the plaintext before hashing, and then appended to the hash. |
Salted SHA-1 |
One-way hash |
Based on SHA-1, with 64 bits of random salt appended to the plaintext before hashing, and then appended to the hash. |
Salted SHA-256 |
One-way hash |
Based on the SHA-256 hash function using 32-bit words and producing 256-bit digests. SHA-256 is defined in the SHA-2 (Secure Hash Algorithm 2) standard developed by the US National Security Agency (NSA) and published by NIST. The salt is applied as for Salted SHA-1. |
Salted SHA-384 |
One-way hash |
Based on the SHA-384 hash function that effectively truncates the digest of SHA-512 to 384 bits. SHA-384 is defined in the SHA-2 (Secure Hash Algorithm 2) standard developed by the NSA and published by NIST. The salt is applied as for Salted SHA-1. |
Salted SHA-512 |
One-way hash |
Based on the SHA-512 hash function using 64-bit words and producing 512-bit digests. SHA-512 is defined in the SHA-2 (Secure Hash Algorithm 2) standard developed by the NSA and published by NIST. The salt is applied as for Salted SHA-1. |
SCRAM-SHA-256 |
One-way hash |
For use with the standard SASL Salted Challenge Response Authentication Mechanism (SCRAM), named A SASL SCRAM mechanism provides a secure alternative to transmitting plaintext passwords during binds. It is an appropriate replacement for DIGEST-MD5 and CRAM-MD5. With a SCRAM SASL bind, the client must demonstrate proof that it has the original plaintext password. During the SASL bind, the client must perform computationally intensive processing to prove that it has the plaintext password. This computation is like what the server performs for PBKDF2, but the password is not communicated during the bind. Once the server has stored the password, the client pays the computational cost to perform the bind. The server only pays a high computational cost when the password is updated, for example, when an entry with a password is added or during a password modify operation. A SASL SCRAM mechanism therefore offers a way to offload the high computational cost of secure password storage to client applications during authentication. Passwords storage using a SCRAM storage scheme is compatible with simple binds and SASL PLAIN binds. When a password is stored using a SCRAM storage scheme, the server pays the computational cost to perform the bind during a simple bind or SASL PLAIN bind. The SCRAM password storage scheme must match the SASL SCRAM mechanism used for authentication. In other words, SASL SCRAM-SHA-256 requires a SCRAM-SHA-256 password storage scheme. SASL SCRAM-SHA-512 requires a SCRAM-SHA-512 password storage scheme. Default iterations: 10000. The pseudorandom function for the algorithm corresponds to the HMAC based on SHA-2, where the hash function is SHA-256. |
SCRAM-SHA-512 |
One-way hash |
Like SCRAM-SHA-256, but the hash function is SHA-512. The corresponding SASL mechanism is named |
SHA-1 |
One-way hash |
SHA-1 (Secure Hash Algorithm 1) standard developed by the NSA and published by NIST. Not intended as a secure storage scheme. |
(1) Reversible encryption schemes are deprecated.
(2) When you configure a reversible password storage scheme, enable the adminRoot
backend,
and configure a replication domain for cn=admin data
.
These additional steps let the replicas store and replicate the secret keys for password encryption.
Password storage schemes listed in the following table have additional configuration settings.
Scheme | Setting | Description |
---|---|---|
Argon2 |
|
The number of iterations to perform. Default: 2. |
|
The amount of memory to use for a single hash, expressed in kibibytes. Default: 15360. |
|
|
The memory requirement expected during an Argon2 password migration. Ignored if less than |
|
|
The number of threads that work in parallel to compute a hash. Default: 1. |
|
|
The variant of Argon2 algorithm to use (I, D, or ID). Default: ID. |
|
|
The length of the resulting hash. Default: 32. |
|
|
The length of the salt used when hashing passwords. Default: 16. |
|
|
Whether the server should rehash passwords after the cost has been changed. Default: never. |
|
Bcrypt |
|
The cost parameter specifies a key expansion iteration count as a power of two. A default value of 12 (212 iterations) is considered in 2016 as a reasonable balance between responsiveness and security for regular users. |
|
Whether the server should rehash passwords after the cost has been changed. Default: never. |
|
Crypt |
|
Specifies the crypt algorithm to use to encrypt new passwords. The following values are supported:
|
PBKDF2 PBKDF2-HMAC-SHA256 PBKDF2-HMAC-SHA512 |
|
The number of algorithm iterations. The default is 10000. |
|
Whether the server should rehash passwords after the cost has been changed. Default: never. |
|
SCRAM SCRAM-SHA-256 SCRAM-SHA-512 |
|
The number of algorithm iterations. The default is 10000. |
You change the default password policy storage scheme for users by changing the applicable password policy:
$ dsconfig \
set-password-policy-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--policy-name "Default Password Policy" \
--set default-password-storage-scheme:PBKDF2-HMAC-SHA512 \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
Notice that the change in default password storage scheme does not cause the DS server to update any stored password values. By default, the server only stores a password with the new storage scheme the next time the password is changed.
For subentry password policies, set the ds-pwp-default-password-storage-scheme
attribute
to the common name of an enabled password storage scheme.
To list the names of enabled password storage schemes,
use the dsconfig list-password-storage-schemes
command.
The name appears in the first column of the output.
The third column shows whether the scheme is enabled.
DS servers prefix passwords with the scheme used to encode them, which means it is straightforward to see which password storage scheme is used. After the default password storage scheme is changed to PBKDF2-HMAC-SHA512, old user passwords remain encoded with PBKDF2-HMAC-SHA256:
$ 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 \
"(uid=bjensen)" \
userPassword
dn: uid=bjensen,ou=People,dc=example,dc=com
userPassword: {PBKDF2-HMAC-SHA256}10:<hash>
When the password is changed, the new default password storage scheme takes effect:
$ ldappasswordmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password \
--authzID "u:bjensen" \
--newPassword changeit
The LDAP password modify operation was successful
$ 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 changeit \
--baseDN dc=example,dc=com \
"(uid=bjensen)" \
userPassword
dn: uid=bjensen,ou=People,dc=example,dc=com
userPassword: {PBKDF2-HMAC-SHA512}10000:<hash>
When you change the password storage scheme for users, realize that the user passwords must change in order for the DS server to encode them with the chosen storage scheme. If you are changing the storage scheme because the old scheme was too weak, then you no doubt want users to change their passwords anyway.
If, however, the storage scheme change is not related to vulnerability,
use the deprecated-password-storage-scheme
property in per-server password policies,
or the ds-pwp-deprecated-password-storage-scheme
attribute in subentry password policies.
This setting causes the DS server to store the password in the new format after successful authentication.
This makes it possible to do password migration for active users as users gradually change their passwords:
$ 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=kvaughan)" \
userPassword
dn: uid=kvaughan,ou=People,dc=example,dc=com
userPassword: {PBKDF2-HMAC-SHA256}10:<hash>
$ dsconfig \
set-password-policy-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--policy-name "Default Password Policy" \
--set deprecated-password-storage-scheme:PBKDF2-HMAC-SHA256 \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
$ 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=kvaughan)" \
userPassword
dn: uid=kvaughan,ou=People,dc=example,dc=com
userPassword: {PBKDF2-HMAC-SHA512}10000:<hash>
Notice that with deprecated-password-storage-scheme
set appropriately,
Kirsten Vaughan’s password was hashed again after she authenticated successfully.
Password generation
DS servers use password generators when responding with a generated password for the LDAP Password Modify extended operation. A directory administrator resetting a user’s password has the server generate the new password, and the server sends the new password in the response:
$ ldappasswordmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password \
--authzID "u:bjensen"
The LDAP password modify operation was successful
Generated Password: <random>
The default password policy uses the Random Password Generator, described in Random Password Generator:
$ dsconfig \
get-password-policy-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--policy-name "Default Password Policy" \
--property password-generator \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
Property : Value(s)
-------------------:--------------------------
password-generator : Random Password Generator
$ dsconfig \
get-password-generator-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--generator-name "Random Password Generator" \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
Property : Value(s)
-----------------------:-------------------------------------------------------
enabled : true
password-character-set : alphanum:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS
: TUVWXYZ0123456789
password-format : alphanum:10
Notice that the default configuration for the Random Password Generator sets the password-character-set
property,
and references the settings in the password-format
property.
Generated passwords have eight characters:
three from the alpha
set, followed by two from the numeric
set, followed by three from the alpha
set.
The password-character-set
name must be ASCII.
Subentry password policies configure ds-pwp-random-generator
object class attributes.
The following example creates a password with password generation, and demonstrates its use:
$ 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: cn=Policy with random password generation,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
objectClass: ds-pwp-validator
objectClass: ds-pwp-length-based-validator
objectClass: ds-pwp-random-generator
cn: Policy with random password generation
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-random-password-character-set: alpha:ABCDEFGHIJKLMNOPQRSTUVWabcdefghijklmnopqrstuvwxyz
ds-pwp-random-password-character-set: punct:,.!&+=-_
ds-pwp-random-password-character-set: numeric:0123456789
ds-pwp-random-password-format: alpha:3,punct:1,numeric:2,punct:2,numeric:3,alpha:3,punct:2
ds-pwp-length-based-min-password-length: 8
subtreeSpecification: { base "ou=people" }
EOF
$ ldappasswordmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password \
--authzID "u:bjensen"
The LDAP password modify operation was successful
Generated Password: <random>
For details, see ds-pwp-random-generator attributes.
When configuring both password validators and password generators, make sure the generated passwords are acceptable to the validator. In this case, the minimum length is less than the generated password length, for example.
Sample password policies
Lock accounts after repeated bind failures
To help you prevent brute-force attacks, where an attacker tries many passwords in the hope of eventually guessing correctly, DS password policies support configurable account lockout. This feature is an important part of a secure password policy.
When you configure account lockout as part of password policy, DS servers lock an account after the specified number of consecutive authentication failures. Account lockout is not transactional across all replicas in a deployment. Global account lockout occurs as soon as the authentication failure times have been replicated. |
The following commands demonstrate a subentry password policy that locks accounts for five minutes after three consecutive bind failures. With this policy, the directory server records failure times, and slowly discards them. As a result, a brute-force attack is hopefully too slow to be effective, but no administrative action is needed when a user temporarily forgets or mistypes their password.
Once an account is locked, binds continue to fail for the lockout period, even if the credentials are correct.
An account administrator can use the manage-account
command to view the account status,
and to change it if necessary:
Show example commands
# Set the password policy:
$ 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: cn=Lock After Repeated Bind Failures,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
cn: Lock After Repeated Bind Failures
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-lockout-duration: 5 m
ds-pwp-lockout-failure-count: 3
ds-pwp-lockout-failure-expiration-interval: 2 m
subtreeSpecification: { base "ou=people", specificationFilter "(objectClass=posixAccount)" }
EOF
# Attempt to bind three times using the wrong password:
$ 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 wrongPassword \
--baseDn dc=example,dc=com \
"(uid=bjensen)"
The LDAP bind request failed: 49 (Invalid Credentials)
$ 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 wrongPassword \
--baseDn dc=example,dc=com \
"(uid=bjensen)"
The LDAP bind request failed: 49 (Invalid Credentials)
$ 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 wrongPassword \
--baseDn dc=example,dc=com \
"(uid=bjensen)"
The LDAP bind request failed: 49 (Invalid Credentials)
# Observe the results:
$ manage-account \
get-all \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--targetDN uid=bjensen,ou=people,dc=example,dc=com \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin
Password Policy DN: cn=Lock After Repeated Bind Failures,dc=example,dc=com
Seconds Until Authentication Failure Unlock: <seconds>
Enforce regular password changes
The following commands configure a subentry password policy that sets age limits on passwords, requiring that users change their passwords at least every 13 weeks, but not more often than every 4 weeks. The policy also sets the number of passwords to keep in the password history of the entry, preventing users from reusing the same password on consecutive changes:
$ 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: cn=Enforce Regular Password Changes,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
cn: Enforce Regular Password Changes
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-max-password-age: 13 w
ds-pwp-min-password-age: 4 w
ds-pwp-password-history-count: 7
subtreeSpecification: { base "ou=people" }
EOF
Track last login time
The following command configures a subentry password policy that keeps track of the last successful login:
-
Create the password policy to write the timestamp to the attribute on successful login:
$ dsconfig \ create-password-policy \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --policy-name "Track Last Login Time" \ --type password-policy \ --set default-password-storage-scheme:PBKDF2-HMAC-SHA256 \ --set password-attribute:userPassword \ --set last-login-time-attribute:ds-last-login-time \ --set last-login-time-format:"yyyyMMddHH'Z'" \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --no-prompt
Deprecate a password storage scheme
The following commands configure a subentry password policy for deprecating a password storage scheme. This policy uses elements from Enforce regular password changes. The DS server applies the new password storage scheme to re-encode passwords:
-
When they change.
-
When the user successfully binds with the correct password, and the password is currently hashed with a deprecated scheme.
$ dsconfig \
set-password-storage-scheme-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--scheme-name "Salted SHA-512" \
--set enabled:true \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
$ 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: cn=Deprecate a Password Storage Scheme,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
cn: Deprecate a Password Storage Scheme
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-deprecated-password-storage-scheme: Salted SHA-512
ds-pwp-max-password-age: 13 w
ds-pwp-min-password-age: 4 w
ds-pwp-password-history-count: 7
subtreeSpecification: { base "ou=people" }
EOF
Lock idle accounts
The following commands configure a subentry password policy that locks accounts idle for more than 13 weeks. This policy extends the example from Track last login time. The DS server must track last successful login time to calculate how long the account has been idle:
$ 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: cn=Lock Idle Accounts,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
cn: Lock Idle Accounts
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-idle-lockout-interval: 13 w
ds-pwp-last-login-time-attribute: ds-last-login-time
ds-pwp-last-login-time-format: yyyyMMddHH'Z'
subtreeSpecification: { base "ou=people" }
EOF
Allow log in to change an expired password
The following commands configure a subentry password policy that lets users log in twice with an expired password to set a new password:
$ 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: cn=Allow Grace Login,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
cn: Allow Grace Login
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-grace-login-count: 2
subtreeSpecification: { base "ou=people" }
EOF
Require password change on add or reset
The following commands configure a subentry password policy that requires new users to change their password after logging in for the first time. This policy also requires users to change their password after it is reset:
$ 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: cn=Require Password Change on Add or Reset,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
cn: Require Password Change on Add or Reset
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-force-change-on-add: true
ds-pwp-force-change-on-reset: true
subtreeSpecification: { base "ou=people" }
EOF
About password policies
DS password policies govern passwords, account lockout, and account status notification.
DS servers support per-server password policies stored in the configuration, and subentry password policies stored in the (replicated) directory data:
Type | Notes |
---|---|
|
|
|
Per-server password policies
You manage per-server password policies with the dsconfig
command.
When changing a per-server policy, you must update each replica in your deployment.
By default, there are two per-server password policies:
-
The
Default Password Policy
for users. -
The
Root Password Policy
for the directory superuser,uid=admin
.
The following example displays the default per-server password policy for users:
$ dsconfig \
get-password-policy-prop \
--hostname localhost \
--port 4444 \
--bindDN uid=admin \
--bindPassword password \
--policy-name "Default Password Policy" \
--advanced \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePassword:file /path/to/opendj/config/keystore.pin \
--no-prompt
Property : Value(s)
------------------------------------------:------------------------------------
account-status-notification-handler : -
allow-expired-password-changes : false
allow-multiple-password-values : false
allow-pre-encoded-passwords : false
allow-user-password-changes : true
default-password-storage-scheme : PBKDF2-HMAC-SHA256
deprecated-password-storage-scheme : -
expire-passwords-without-warning : false
force-change-on-add : false
force-change-on-reset : false
grace-login-count : 0
idle-lockout-interval : 0 s
java-class : org.opends.server.core.PasswordPoli
: cyFactory
last-login-time-attribute : -
last-login-time-format : -
lockout-duration : 0 s
lockout-failure-count : 0
lockout-failure-expiration-interval : 0 s
max-password-age : 0 s
max-password-reset-age : 0 s
min-password-age : 0 s
password-attribute : userPassword
password-change-requires-current-password : false
password-expiration-warning-interval : 5 d
password-generator : Random Password Generator
password-history-count : 0
password-history-duration : 0 s
password-validator : At least 8 characters, Common
: passwords
previous-last-login-time-format : -
require-change-by-time : -
require-secure-authentication : true
require-secure-password-changes : true
skip-validation-for-administrators : false
state-update-failure-policy : reactive
For detailed descriptions of each property, see Password Policy.
These settings are configured by default:
-
When granted access, users can change their passwords.
-
DS servers use the standard
userPassword
attribute to store passwords.DS servers also support the alternative standard
authPassword
attribute. -
When you import LDIF with
userPassword
values, DS servers apply a one-way hash to the passwords before storing them.When a user provides a password value during a bind, for example, the server hashes the incoming password, and compares it with the stored value. This mechanism helps prevent even the directory superuser from recovering the plain text password:
$ 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 dc=example,dc=com \ "(uid=bjensen)" \ userpassword dn: uid=bjensen,ou=People,dc=example,dc=com userpassword: {PBKDF2-HMAC-SHA256}10:<hash>
-
The server can set a random password when a password administrator resets a user’s password.
Many capabilities are not set by default:
-
No lockout.
-
No password expiration.
-
No password validator to check that passwords contain the appropriate mix of characters.
If the directory service enforces password policy, configure at least the default password policy accordingly.
DS subentry password policies
You manage password policies as LDAP subentries in the application data. Replication applies updates to subentry password policies to all other replicas. Password policy administrators do not need access to the server configuration.
The DS subentry password policy entries have the object classes:
-
ds-pwp-password-policy
for most password policy features. -
A set of password validator object classes for specific validators that derive from the abstract
ds-pwp-validator
class for password validation configuration. -
ds-pwp-random-generator
for password generation on reset.
The following tables describe password policy attributes per object class:
Attribute | Description |
---|---|
|
The attribute type used to hold user passwords. |
|
Names of enabled password storage schemes used to encode plaintext passwords. Default: PBKDF2-HMAC-SHA256. |
|
Name of the password policy |
|
Whether users can change their passwords, assuming access control allows it. Default: true. |
|
Names of enabled account status notification handlers to use with this policy. Use the |
|
Whether the user can change an expired password with the password modify extended operation. Default: false. |
|
Whether user entries can have multiple distinct passwords. Any password is sufficient to authenticate. Default: false. |
|
Whether users can change their passwords by providing a pre-encoded value. Default: false. |
|
Names of deprecated password storage schemes for this policy. On successful authentication, encode the password with the default. |
|
Whether to allow a user’s password to expire even if that user has never seen an expiration warning notification. Default: false. |
|
Whether users are forced to change their passwords upon first authentication after their accounts are added. Default: false. |
|
Whether users are forced to change their passwords after password reset by an administrator. For this purpose, anyone with permission to change a given user’s password other than that user is an administrator. Default: false. |
|
Number of grace logins that a user is allowed after the account has expired so the user can update their password. Default: 0 (disabled). |
|
Maximum number of seconds that an account may remain idle (the associated user does not authenticate to the server) before that user is locked out. Requires maintaining a last login time attribute. Default: 0 seconds (inactive). |
|
Name or OID of the attribute type that is used to hold the last login time for users. Default: The |
|
Format string that is used to generate the last login time value for users. The format string must match the syntax of the Default: |
|
Duration that an account is locked after too many authentication failures. Default: 0 seconds (account remains locked until the administrator resets the password). |
|
Maximum number of authentication failures that a user is allowed before the account is locked out. Default: 0 (disabled). |
|
Duration before an authentication failure is no longer counted against a user for the purposes of account lockout. Default: 0 seconds (never expire). |
|
Duration that a user can continue using the same password before it must be changed (the password expiration interval). Default: 0 seconds (passwords never expire). |
|
Maximum number of seconds that users have to change passwords after they have been reset by an administrator before they become locked. Default: 0 seconds. |
|
Minimum duration after a password change before the user is allowed to change the password again. Default: 0 seconds. |
|
Whether user password changes must include the user’s current password before the change is allowed. This can be done with either the password modify extended operation, or a modify operation using delete and add. Default: false. |
|
Duration before a user’s password actually expires that the server begins to include warning notifications in bind responses for that user. Default: 5 days. |
|
Maximum number of former passwords to maintain in the password history. A value of zero indicates that either no password history is to be maintained if the password history duration has a value of zero seconds, or that there is no maximum number of passwords to maintain in the history if the password history duration has a value greater than zero seconds. Default: 0. |
|
Maximum number of seconds that passwords remain in the password history. Default: 0 seconds (inactive). |
|
Format string(s) that might have been used with the last login time at any point in the past for users associated with the password policy. Default: |
|
Time by which all users with the associated password policy must change their passwords. Specified in generalized time form. |
|
Whether users with the associated password policy are required to authenticate in a secure manner. Default: false. |
|
Whether users with the associated password policy are required to change their password in a secure manner that does not expose the credentials. Default: false. |
|
Whether passwords set by administrators are allowed to bypass the password validation process. Default: false. |
|
How the server deals with the inability to update password policy state information during an authentication attempt. One of the following:
|
Attribute | Description | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Whether this password validator should test the reversed value of the provided password as well as the order in which it was given. Default: false. |
|||||||||||||||||||||
|
Name(s) of the attribute(s) whose values should be checked to determine whether they match the provided password. If no values are provided, then the server checks if the proposed password matches the value of any user attribute in the user’s entry. The server does not check values of operational attributes. |
|||||||||||||||||||||
|
Whether this password validator is to match portions of the password string against attribute values. When false, the server checks whether the entire password matches any user attribute values. When true, the server checks whether the password contains any user attribute values. Consider the case of Babs Jensen (
In summary:
Default: false. |
|||||||||||||||||||||
|
The minimal length of the substring within the password when substring checking is enabled. Default: 0. |
Attribute | Description |
---|---|
|
Whether this password validator allows passwords to contain characters outside of any of the user-defined character sets and ranges. Default: false. |
|
Minimum number of character sets and ranges that a password must contain. Use in conjunction with optional character sets and ranges (those requiring zero characters). The value must include any mandatory character sets and ranges (those requiring greater than zero characters). This is useful in situations where a password must contain characters from mandatory character sets and ranges, and characters from at least N optional character sets and ranges. For example, it is quite common to require that a password contains at least one non-alphanumeric character as well as characters from two alphanumeric character sets (lower-case, upper-case, digits). In this case, this property should be set to 3. |
|
A character set containing characters that a password may contain, and a value indicating the minimum number of characters required from that set. Each value must be an integer (indicating the minimum required characters from the set which may be zero,
indicating that the character set is optional) followed by a colon and the characters to include in that set.
For example, Multiple character sets can be defined in separate values, although no character can appear in more than one character set. |
|
A character range containing characters that a password may contain, and a value indicating the minimum number of characters required from that range. Each value must be an integer (indicating the minimum required characters from the range which may be zero, indicating that the character range is optional) followed by a colon and one or more range specifications. A range specification is 3 characters: the first character allowed, a minus, and the last character allowed.
For example, |
Attribute | Description |
---|---|
|
A gzipped password dictionary, one word per line. This is a single-valued attribute. |
|
Whether this password validator should treat password characters in a case-sensitive manner. Default: false. |
|
Whether this password validator is to match portions of the password string against dictionary words. Default: false (match only the entire password against dictionary words). |
|
The minimal length of the substring within the password in case substring checking is enabled. Default: 0. |
|
Whether this password validator should test the reversed value of the provided password as well as the order in which it was given. Default: false. |
Attribute | Description |
---|---|
|
Minimum plaintext password length. Default: 0 (undefined). |
|
Minimum plaintext password length. Default: 6. |
Attribute | Description |
---|---|
|
The maximum number of times that any character can appear consecutively in a password value. Default: 0 (no maximum limit is enforced). |
|
Whether this password validator should treat password characters in a case-sensitive manner. Default: false. |
Attribute | Description |
---|---|
|
The minimum difference the new and old password. The implementation uses the Levenshtein Distance algorithm to determine the minimum number of changes
(where a change may be inserting, deleting, or replacing a character) to transform one string into the other.
It can prevent users from making only minor changes to their current password when setting a new password.
Note that for this password validator to be effective, it must have access to the user’s current password.
Therefore, if this password validator is to be enabled,
also set Default: 0 (no difference between passwords is acceptable). |
Attribute | Description |
---|---|
|
Whether this password validator should treat password characters in a case-sensitive manner. Default: false. |
|
The minimum number of unique characters that a password will be allowed to contain. Default: 0 (no minimum value is enforced). |
Attribute | Description |
---|---|
|
Named character sets.
The format of the character set is the name of the set followed by a colon and the characters that are in that set.
For example, the value |
|
The format to use for the generated password.
The value is a comma-delimited list of elements in which each of those elements
is comprised of the name of a character set defined in the password-character-set property,
a colon, and the number of characters to include from that set.
For example, a value of |
Interoperable subentry password policies
DS servers support the Internet-Draft,
Password Policy for LDAP Directories (version 09).
The password policies are expressed as LDAP subentries with objectClass: pwdPolicy
.
An Internet-Draft password policy effectively overrides settings in the default per-server password policy for users,
inheriting settings that it does not support or does not include from the per-server password policy.
The following table describes Internet-Draft policy attributes:
Attribute | Description |
---|---|
|
The attribute type used to hold user passwords. |
|
Whether users can change their passwords. Default: true. |
|
Maximum number of seconds before a user’s password actually expires that the server begins to include warning notifications in bind responses for that user. Default: 432000 seconds. |
|
Length of time before an authentication failure is no longer counted against a user for the purposes of account lockout. Default: 0 seconds (never expire). |
|
Number of grace logins that a user is allowed after the account has expired so the user can update their password. Default: 0 (disabled). |
|
Maximum number of former passwords to maintain in the password history. Default: 0 (disabled). |
|
Number of seconds that an account is locked after too many authentication failures. Default: 0 seconds (account remains locked indefinitely). |
|
Maximum number of seconds that a user can continue using the same password before it must be changed (the password expiration interval). Default: 0 seconds (disabled). |
|
Maximum number of authentication failures that a user is allowed before the account is locked out. Default: 0. |
|
Minimum number of seconds after a password change before the user is allowed to change the password again. Default: 0 seconds (disabled). |
|
Whether users are forced to change their passwords after password reset by an administrator. Default: false. |
|
Whether user password changes must use the password modify extended operation, and must include the user’s current password before the change is allowed. Default: false. |
The following table lists Internet-Draft policy attributes that override the per-server policy properties:
Internet-Draft Policy Attribute | Overrides This Server Policy Property |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DS servers ignore the following Internet-Draft password policy attributes:
-
pwdCheckQuality
, because DS servers have password validators. -
pwdMinLength
, because you can use a length-based password validator instead. -
pwdLockout
, because DS servers use other lockout-related password policy attributes.
Internet-Draft based password policies inherit these settings from the default per-server policy for users:
-
account-status-notification-handlers
-
allow-expired-password-changes
-
allow-multiple-password-values
-
allow-pre-encoded-passwords
-
default-password-storage-schemes
-
deprecated-password-storage-schemes
-
expire-passwords-without-warning
-
force-change-on-add
-
idle-lockout-interval
-
last-login-time-attribute
-
last-login-time-format
-
max-password-reset-age
-
password-generator
-
password-history-duration
-
password-validators
-
previous-last-login-time-formats
-
require-change-by-time
-
require-secure-authentication
-
require-secure-password-changes
-
skip-validation-for-administrators
-
state-update-failure-policy