PingDS 7.5.1

Configure password policies

Make sure you keep per-server password policy settings aligned across replicated DS servers. When per-server password policy settings differ between replicas, the results can be surprising to end users.

As an example, suppose the user’s password policy depends on a password storage scheme enabled on the replica where the user changes their password and disabled on the replica where they later authenticate:

  • The user changes their password on the first replica.

    The password update succeeds.

    Replication replays the change.

  • The user authenticates on the second replica.

    Authentication fails even though the second replica has the correct password hash. The password storage scheme is disabled in the local per-server configuration.

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:

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

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

    $ 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 and babsjensenspwd 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

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:

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

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

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

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

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

Copyright © 2010-2024 ForgeRock, all rights reserved.