Configuring Password Policy Password policy If you want to synchronize password policy across your organization and your applications go to the directory for authentication, then the directory can be a good place to enforce your password policy uniformly. Even if you do not depend on the directory for all your password policy, you no doubt still want to consider directory password policy if only to choose the appropriate password storage scheme. This chapter covers password policy, including examples of how to configure password policies for common use cases.
About OpenDJ Password Policies OpenDJ password policies govern not only passwords, but also account lockout, and how OpenDJ provides notification about account status. OpenDJ supports password policies as part of the server configuration, and also subentry password policies as part of the (replicated) user data.
Server Based Password Policies You manage server based password policies in the OpenDJ configuration by using the dsconfig command. As they are part of the server configuration, such password policies are not replicated. You must instead apply password policy configuration updates to each replica in your deployment. By default, OpenDJ includes two password policy configurations, one default for all users, and another for directory root DN users, such as cn=Directory Manager. You can see all the default password policy settings using the dsconfig command as follows. $ dsconfig get-password-policy-prop --port 4444 --hostname opendj.example.com --bindDN "cn=Directory Manager" --bindPassword password --policy-name "Default Password Policy" --advanced 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 : Salted SHA-1 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 : 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 skip-validation-for-administrators : false state-update-failure-policy : reactive See the OpenDJ Configuration Reference page on Password Policy for detailed descriptions of each property. Here you notice that many capabilities are not set by default: no lockout, no password expiration, no multiple passwords, no password validator to check that passwords contain the appropriate mix of characters. This means that if you decide to use the directory to enforce password policy, you must configure at least the default password policy to meet your needs. Yet a few basic protections are configured by default. When you import LDIF with userPassword values, OpenDJ hashes the values before storing them. When a user provides a password value during a bind for example, the server hashes the value provided to compared it with the stored value. Even the directory manager cannot see the plain text value of a user's password. $ ldapsearch --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --baseDN dc=example,dc=com uid=bjensen userpassword dn: uid=bjensen,ou=People,dc=example,dc=com userpassword: {SSHA}QWAtw8ch/9850HNFRRqLNMIQc1YhxCnOoGmk1g== In addition, users can change their passwords provided you have granted them access to do so. OpenDJ uses the userPassword attribute to store passwords by default, rather than the authPassword attribute, which is designed to store passwords hashed by the client application.
Subentry Based Password Policies Replication Password policy You manage subentry password policies by adding the subentries alongside the user data. Thus OpenDJ can replicate subentry password policies across servers. Password policy Behera Internet-Draft Subentry password policies support the Internet-Draft Password Policy for LDAP Directories (version 09). A subentry password policy effectively overrides settings in the default password policy defined in the OpenDJ configuration. Settings not supported or not included in the subentry password policy are thus inherited from the default password policy. As a result, the following Internet-Draft password policy attributes override the default password policy when you set them in the subentry. pwdAllowUserChange, corresponding to the OpenDJ password policy property allow-user-password-changes pwdMustChange, corresponding to the OpenDJ password policy property force-change-on-reset pwdGraceAuthNLimit, corresponding to the OpenDJ password policy property grace-login-count pwdLockoutDuration, corresponding to the OpenDJ password policy property lockout-duration pwdMaxFailure, corresponding to the OpenDJ password policy property lockout-failure-count pwdFailureCountInterval, corresponding to the OpenDJ password policy property lockout-failure-expiration-interval pwdMaxAge, corresponding to the OpenDJ password policy property max-password-age pwdMinAge, corresponding to the OpenDJ password policy property min-password-age pwdAttribute, corresponding to the OpenDJ password policy property password-attribute pwdSafeModify, corresponding to the OpenDJ password policy property password-change-requires-current-password pwdExpireWarning, corresponding to the OpenDJ password policy property password-expiration-warning-interval pwdInHistory, corresponding to the OpenDJ password policy property password-history-count The following Internet-Draft password policy attributes are not taken into account by OpenDJ. pwdCheckQuality, as OpenDJ has password validators. You can set password validators to use in the default password policy. pwdMinLength, as this is handled by the Length Based Password Validator. You can configure this as part of the default password policy. pwdLockout, as OpenDJ can deduce whether lockout is configured based on the values of other lockout-related password policy attributes. Values of the following properties are inherited from the default password policy for Internet-Draft based password policies. 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
Which Password Policy Applies The password policy that applies to a user is identified by the operational attribute, pwdPolicySubentry. $ ldapsearch --port 1389 --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
Configuring Password Policies You configure server based password policies using the dsconfig command. Notice that server based password policies are part of the server configuration, and therefore not replicated. Alternatively, you can configure a subset of password policy features using subentry based password policies that are stored with the replicated server data. This section covers both server based and subentry based password policies. To Adjust the Default Password Policy Password policy Default You can reconfigure the default password policy for example to enforce password expiration, check that passwords do not match dictionary words, and prevent password reuse. This default policy is a server based password policy. Enable the appropriate password validator. $ dsconfig set-password-validator-prop --port 4444 --hostname opendj.example.com --bindDN "cn=Directory Manager" --bindPassword password --validator-name Dictionary --set enabled:true --set check-substrings:true --set min-substring-length:4 --trustAll --no-prompt Apply the changes to the default password policy. $ dsconfig set-password-policy-prop --port 4444 --hostname opendj.example.com --bindDN "cn=Directory Manager" --bindPassword password --policy-name "Default Password Policy" --set max-password-age:90d --set min-password-age:4w --set password-history-count:7 --set password-validator:Dictionary --trustAll --no-prompt Check your work. $ dsconfig get-password-policy-prop --port 4444 --hostname opendj.example.com --bindDN "cn=Directory Manager" --bindPassword password --policy-name "Default Password Policy" Property : Value(s) ------------------------------------------:-------------------------- account-status-notification-handler : - allow-expired-password-changes : false allow-user-password-changes : true default-password-storage-scheme : Salted SHA-1 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 : 12 w 6 d max-password-reset-age : 0 s min-password-age : 4 w 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 : Dictionary previous-last-login-time-format : - require-change-by-time : - require-secure-authentication : false require-secure-password-changes : false To Create a Server Based Password Policy You can add a password policy for example for new users who have not yet used their credentials to bind. Create the new password policy. $ dsconfig create-password-policy --port 4444 --hostname opendj.example.com --bindDN "cn=Directory Manager" --bindPassword password --policy-name "New Account Password Policy" --set default-password-storage-scheme:"Salted SHA-1" --set force-change-on-add:true --set password-attribute:userPassword --type password-policy --trustAll --no-prompt Check your work. $ dsconfig get-password-policy-prop --port 4444 --hostname opendj.example.com --bindDN "cn=Directory Manager" --bindPassword password --policy-name "New Account Password Policy" Property : Value(s) ------------------------------------------:------------- account-status-notification-handler : - allow-expired-password-changes : false allow-user-password-changes : true default-password-storage-scheme : Salted SHA-1 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 If you use a password policy like this, you might want to change the user's policy again when the new user successfully updates the password. To Create a Subentry Based Password Policy You can add a subentry to configure a password policy that applies to Directory Administrators. Create the entry that specifies the password policy. $ cat /path/to/subentry-pwp.ldif dn: cn=Subentry Password Policy,dc=example,dc=com objectClass: top objectClass: subentry objectClass: pwdPolicy cn: Subentry Password Policy pwdAttribute: userPassword pwdLockout: TRUE pwdMaxFailure: 3 pwdFailureCountInterval: 300 pwdLockoutDuration: 300 pwdAllowUserChange: TRUE pwdSafeModify: TRUE subtreeSpecification: {base "ou=people", specificationFilter "(isMemberOf=cn=Directory Administrators,ou=Groups,dc=example,dc=com)" } Add the policy to the directory. $ ldapmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --defaultAdd --filename /path/to/subentry-pwp.ldif Processing ADD request for cn=Subentry Password Policy,dc=example,dc=com ADD operation successful for DN cn=Subentry Password Policy,dc=example,dc=com Check that the policy applies as specified. In the example, the policy should apply to a Directory Administrator, while a normal user has the default password policy. Here, Kirsten Vaughan is a member of the Directory Administrators group, and Babs Jensen is not a member. $ ldapsearch --port 1389 --baseDN dc=example,dc=com uid=kvaughan pwdPolicySubentry dn: uid=kvaughan,ou=People,dc=example,dc=com pwdPolicySubentry: cn=Subentry Password Policy,dc=example,dc=com $ ldapsearch --port 1389 --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
Assigning Password Policies You assign subentry based password policies for a subtree of the DIT by adding the policy to an LDAP subentry whose immediate superior is the root of the subtree. In other words you can add the subtree based password policy under ou=People,dc=example,dc=com, to have it apply to all entries under ou=People,dc=example,dc=com. You can further use the capabilities of LDAP subentries to refine the scope of application. You assign server based password policies by using the ds-pwp-password-policy-dn attribute. To Assign a Password Policy to a User Prevent users from selecting their own password policy. $ cat protectpwp.ldif dn: ou=People,dc=example,dc=com changetype: modify add: aci aci: (target ="ldap:///uid=*,ou=People,dc=example,dc=com")(targetattr = "ds-pwp-password-policy-dn")(version 3.0;acl "Cannot choose own pass word policy";deny (write)(userdn = "ldap:///self");) $ ldapmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --filename protectpwp.ldif Processing MODIFY request for ou=People,dc=example,dc=com MODIFY operation successful for DN ou=People,dc=example,dc=com Update the user's ds-pwp-password-policy-dn attribute. $ cat newuser.ldif 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: changeme ds-pwp-password-policy-dn: cn=New Account Password Policy,cn=Password Policies, cn=config $ ldapmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --defaultAdd --filename newuser.ldif Processing ADD request for uid=newuser,ou=People,dc=example,dc=com ADD operation successful for DN uid=newuser,ou=People,dc=example,dc=com Check your work. $ ldapsearch --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --baseDN dc=example,dc=com uid=newuser pwdPolicySubentry dn: uid=newuser,ou=People,dc=example,dc=com pwdPolicySubentry: cn=New Account Password Policy,cn=Password Policies,cn=config To Assign a Password Policy to a Group Create a subentry defining the collective attribute that sets the ds-pwp-password-policy-dn attribute for group members' entries. $ cat pwp-coll.ldif 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=Pass word Policies,cn=config subtreeSpecification: { base "ou=People", specificationFilter "(isMemberOf= cn=Directory Administrators,ou=Groups,dc=example,dc=com)"} $ ldapmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --defaultAdd --filename pwp-coll.ldif Processing ADD request for cn=Password Policy for Dir Admins,dc=example,dc=com ADD operation successful for DN cn=Password Policy for Dir Admins,dc=example,dc=com Check your work. $ ldapsearch --port 1389 --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
Configuring Password Generation Passwords Generating Password generators are used by OpenDJ during the LDAP password modify extended operation to construct a new password for the user. In other words, a directory administrator resetting a user's password can have OpenDJ directory server generate the new password. $ ldappasswordmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --authzID "u:bjensen" The LDAP password modify operation was successful Generated Password: eak77qdi The default password policy shown in uses the Random Password Generator. $ dsconfig get-password-policy-prop --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --policy-name "Default Password Policy" --property password-generator Property : Value(s) -------------------:-------------------------- password-generator : Random Password Generator $ dsconfig get-password-generator-prop --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --generator-name "Random Password Generator" --property password-generator Property : Value(s) -----------------------:----------------------------------------------------- enabled : true password-character-set : alpha:abcdefghijklmnopqrstuvwxyz, numeric:0123456789 password-format : "alpha:3,numeric:2,alpha:3" Notice that the default configuration for the Random Password Generator defines two password-character-set values, and then uses those definitions in the password-format so that 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. To set the password generator that OpenDJ employs when constructing a new password for a user, set the password-generator property for the password policy that applies to the user. The following example does not change the password policy, but instead changes the Random Password Generator configuration, and then demonstrates a password being generated upon reset. $ dsconfig set-password-generator-prop --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --generator-name "Random Password Generator" --remove password-character-set:alpha:abcdefghijklmnopqrstuvwxyz --add password-character-set:alpha:ABCDEFGHIJKLMNOPQRSTUVWabcdefghijklmnopqrstuvwxyz --add password-character-set:punct:,./\`!@#\$%^&*:\;[]\"\'\(\)+=-_~\\ --set password-format:alpha:3,punct:1,numeric:2,punct:2,numeric:3,alpha:3,punct:2 --no-prompt $ ldappasswordmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --authzID "u:bjensen" The LDAP password modify operation was successful Generated Password: pld^06:)529HTq$' If you also set up a password validator in the password policy as shown in and further described in , make sure the generated passwords are acceptable to the validator.
Configuring Password Storage Passwords Storage schemes Password storage schemes encode new passwords provided by users so that they are stored in an encoded manner. This makes it difficult or impossible for someone to determine the clear-text passwords from the encoded values. Password storage schemes also determine whether a clear-text password provided by a client matches the encoded value stored in the server. OpenDJ offers a variety of both reversible and one-way password storage schemes. Some schemes make it easy to recover the clear-text password, whereas others aim to make it computationally hard to do so. $ dsconfig list-password-storage-schemes --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password Password Storage Scheme : Type : enabled ------------------------:---------------:-------- 3DES : triple-des : true AES : aes : true Base64 : base64 : true Blowfish : blowfish : true Clear : clear : true CRYPT : crypt : true MD5 : md5 : true PBKDF2 : pbkdf2 : true RC4 : rc4 : true Salted MD5 : salted-md5 : true Salted SHA-1 : salted-sha1 : true Salted SHA-256 : salted-sha256 : true Salted SHA-384 : salted-sha384 : true Salted SHA-512 : salted-sha512 : true SHA-1 : sha1 : true As shown in , the default password storage scheme for users in Salted SHA-1. When you add users or import user entries with userPassword values in clear text, OpenDJ hashes them with the default password storage scheme. Root DN users have a different password policy by default, shown in . The Root Password Policy uses Salted SHA-512 by default. You change the default password policy storage scheme for users by changing the applicable password policy, as shown in the following example. $ dsconfig set-password-policy-prop --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --policy-name "Default Password Policy" --set default-password-storage-scheme:pbkdf2 --no-prompt Notice that the change in default password storage scheme does not cause OpenDJ to update any stored password values. By default, OpenDJ only stores a password with the new storage scheme the next time that the password is changed. OpenDJ prefixes passwords with the scheme used to encode them, which means it is straightforward to see which password storage scheme is in use. After the default password storage scheme is changed to PBKDF2, old user passwords remain encoded with Salted SHA-1. $ ldapsearch --port 1389 --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: {SSHA}Rc3tkAj1qP5zGiRkwDIWDFxrxpGgO8Fwh3aibg== When the password is changed, the new default password storage scheme takes effect, as shown in the following example. $ ldappasswordmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --authzID "u:bjensen" --newPassword changeit The LDAP password modify operation was successful $ ldapsearch --port 1389 --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}10000:O3V6G7y7n7AefOkRGNKQ5ukrMuO5uf+iEQ9ZLg== When you change the password storage scheme for users, realize that the user passwords must change in order for OpenDJ 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, you can use the deprecated-password-storage-scheme property of the password policy to have OpenDJ store the password in the new format after successful authentication. This makes it possible to do password migration for active users without forcing users to change their passwords. $ ldapsearch --port 1389 --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: {SSHA}hDgK44F2GhIIZj913b+29Ak7phb9oU3Lz4ogkg== $ dsconfig set-password-policy-prop --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --policy-name "Default Password Policy" --set deprecated-password-storage-scheme:"Salted SHA-1" --no-prompt $ ldapsearch --port 1389 --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}10000:L4dCYqSsNnf47YZ3a6aC8K2E3DChhHHhpcoUzg== Notice that with deprecated-password-storage-scheme set appropriately, Kirsten Vaughan's password was hashed again after she authenticated successfully.
Configuring Password Validation Passwords Validating Password validators are responsible for determining whether a proposed password is acceptable for use and can run checks like ensuring the password meets minimum length requirements, that it has an appropriate range of characters, or that it is not in the history. OpenDJ directory server provides a variety of password validators. $ dsconfig list-password-validators --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password Password Validator : Type : enabled ------------------------------------:---------------------:-------- Attribute Value : attribute-value : true Character Set : character-set : 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 The password policy for a user specifies the set of password validators that should be used whenever that user provides a new password. By default no password validators are configured. You can see an example setting the Default Password Policy to use the Dictionary validator in . The following example shows how to set up a custom password validator and assign it to the default password policy. The custom password validator ensures passwords meet at least three of the following four criteria. Passwords are composed of: English lowercase characters (a through z) English uppercase characters (A through Z) Base 10 digits (0 through 9) Non-alphabetic characters (for example, !, $, #, %) Notice how the character-set values are constructed. The initial 0: means the set is optional, whereas 1: would mean the set is required. $ dsconfig create-password-validator --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --validator-name "Custom Character Set Password Validator" --set allow-unclassified-characters:true --set enabled:true --set character-set:0:abcdefghijklmnopqrstuvwxyz --set character-set:0:ABCDEFGHIJKLMNOPQRSTUVWXYZ --set character-set:0:0123456789 --set character-set:0:!\"#\$%&\'\(\)*+,-./:\;\\<=\>?@[\\]^_\`{\|}~ --set min-character-sets:3 --type character-set --no-prompt $ dsconfig set-password-policy-prop --hostname opendj.example.com --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --policy-name "Default Password Policy" --set password-validator:"Custom Character Set Password Validator" --no-prompt $ ldappasswordmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --authzID "u:bjensen" --newPassword '!ABcd$%^' In the preceding example, the character set of ASCII punctuation, !\"#\$%&\'\(\)*+,-./:\;\\<=\>?@[\\]^_\`{\|}~, is hard to read because of all the escape characters. In practice it can be easier to enter sequences like that by using dsconfig in interactive mode, and letting it do the escaping for you. You can also use the option to save the result of your interactive session to a file for use in scripts later. An attempt to set an invalid password fails as shown in the following example. $ ldappasswordmodify --port 1389 --bindDN "cn=Directory Manager" --bindPassword password --authzID "u:bjensen" --newPassword hifalutin The LDAP password modify operation failed with result code 19 Error Message: 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: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', '!"#$%&'()*+,-./:;<=\>?@[\]^_`{|}~', '0123456789', 'abcdefghijklmnopqrstuvwxyz' Validation does not affect existing passwords, but only takes effect when the password is updated.