---
title: Configure password policies
description: 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.
component: pingds
version: 7.4
page_id: pingds:security-guide:pwp-configure
canonical_url: https://docs.pingidentity.com/pingds/8.1/security-guide/pwp-configure.html
llms_txt: https://docs.pingidentity.com/pingds/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: 2023-09-18T15:00:15Z
keywords: ["Features", "LDAP", "Security", "Setup &amp; Configuration"]
superseded_by: https://docs.pingidentity.com/pingds/8.1/security-guide/pwp-configure.html
section_ids:
  default-pwp: Adjust the default password policy
  recommended-pwp: Configure a NIST-inspired subentry policy
  create-per-server-pwp: Create a per-server password policy
---

# 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.

1. Apply the changes to the default password policy:

   ```bash
   $ 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
   ```

2. Check your work:

   ```bash
   $ 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
   ```

3. 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:

   ```bash
   $ 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:

   ```bash
   $ 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` and `babsjensenspwd` are not valid because substrings of the password match complete attribute values:

   ```bash
   $ 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
   ```

## 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:

1. 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.

2. 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.

3. 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:

   ```bash
   $ 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 the `privilege-change` privilege can assign privileges. However, if the administrator can update administrator privileges, they can assign themselves the `bypass-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 the `privilege-change` privilege to normal administrator users.

4. Create the password policy as one of the password policy administrators:

   ```bash
   $ 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.

5. Check the password policy works appropriately.

   The following example shows a rejected password modification:

   ```bash
   $ 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:

   ```bash
   $ 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:

1. Create the new password policy:

   ```bash
   $ 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.

2. Check your work:

   ```bash
   $ 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
   ```

3. Change the user's password policy after the password is successfully updated.

   For instructions on assigning a per-server password policy, refer to [Assign a password policy to a user](pwp-assign.html#assign-pwp-to-individual).
