Add support for two new password validators:
- Issue #338: Prevent users from selecting a password that matches the value
of any attribute (or a specified set of attributes) in that user's entry.
- Issue #341: Prevent users from selecting a password that matches a value
contained in a dictionary.
Both validators support both forward and reverse matching, and for the
dictionary password validator I have compiled a dictionary from public domain
word lists.
7 files added
3 files modified
| | |
| | | objectClass: ds-cfg-branch |
| | | cn: Password Validators |
| | | |
| | | dn: cn=Attribute Value,cn=Password Validators,cn=config |
| | | objectClass: top |
| | | objectClass: ds-cfg-password-validator |
| | | objectClass: ds-cfg-attribute-value-password-validator |
| | | cn: Attribute Value |
| | | ds-cfg-password-validator-class: org.opends.server.extensions.AttributeValuePasswordValidator |
| | | ds-cfg-password-validator-enabled: true |
| | | ds-cfg-test-reversed-password: true |
| | | |
| | | dn: cn=Dictionary,cn=Password Validators,cn=config |
| | | objectClass: top |
| | | objectClass: ds-cfg-password-validator |
| | | objectClass: ds-cfg-dictionary-password-validator |
| | | cn: Dictionary |
| | | ds-cfg-password-validator-class: org.opends.server.extensions.DictionaryPasswordValidator |
| | | ds-cfg-password-validator-enabled: false |
| | | ds-cfg-dictionary-file: config/wordlist.txt |
| | | ds-cfg-case-sensitive-validation: false |
| | | ds-cfg-test-reversed-password: true |
| | | |
| | | dn: cn=Length-Based Password Validator,cn=Password Validators,cn=config |
| | | objectClass: top |
| | | objectClass: ds-cfg-password-validator |
| | |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.321 |
| | | NAME 'ds-cfg-minimum-password-difference' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE |
| | | NAME 'ds-cfg-minimum-password-difference' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.322 |
| | | NAME 'ds-cfg-minimum-unique-characters' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE |
| | | NAME 'ds-cfg-minimum-unique-characters' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.323 |
| | | NAME 'ds-cfg-maximum-consecutive-length' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE |
| | | NAME 'ds-cfg-maximum-consecutive-length' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.324 |
| | | NAME 'ds-cfg-case-sensitive-validation' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE |
| | | NAME 'ds-cfg-case-sensitive-validation' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.325 |
| | | NAME 'ds-cfg-virtual-attribute-class' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | |
| | | NAME 'ds-cfg-virtual-attribute-conflict-behavior' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.336 |
| | | NAME 'ds-cfg-dictionary-file' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.337 |
| | | NAME 'ds-cfg-test-reversed-password' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 |
| | | SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.340 |
| | | NAME 'ds-task-rebuild-base-dn' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE |
| | |
| | | ds-cfg-virtual-attribute-conflict-behavior ) |
| | | MAY ( ds-cfg-virtual-attribute-base-dn $ ds-cfg-virtual-attribute-group-dn $ |
| | | ds-cfg-virtual-attribute-filter ) X-ORIGIN 'OpenDS Directory Server' ) |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.95 |
| | | NAME 'ds-cfg-dictionary-password-validator' SUP ds-cfg-password-validator |
| | | STRUCTURAL MUST ( ds-cfg-dictionary-file $ ds-cfg-case-sensitive-validation $ |
| | | ds-cfg-test-reversed-password ) X-ORIGIN 'OpenDS Directory Server' ) |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.96 |
| | | NAME 'ds-cfg-attribute-value-password-validator' |
| | | SUP ds-cfg-password-validator STRUCTURAL MUST ds-cfg-test-reversed-password |
| | | MAY ds-cfg-match-attribute X-ORIGIN 'OpenDS Directory Server' ) |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.98 |
| | | NAME 'ds-task-rebuild' SUP ds-task |
| | | MUST ( ds-task-rebuild-base-dn $ ds-task-rebuild-index ) |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <adm:managed-object name="attribute-value-password-validator" |
| | | plural-name="attribute-value-password-validators" |
| | | package="org.opends.server.admin.std" extends="password-validator" |
| | | xmlns:adm="http://www.opends.org/admin" |
| | | xmlns:ldap="http://www.opends.org/admin-ldap"> |
| | | <adm:synopsis> |
| | | The |
| | | <adm:user-friendly-name /> |
| | | is used to determine whether a proposed password is acceptable based on |
| | | whether the given password value appears the user's entry. |
| | | </adm:synopsis> |
| | | <adm:profile name="ldap"> |
| | | <ldap:object-class> |
| | | <ldap:oid>1.3.6.1.4.1.26027.1.2.95</ldap:oid> |
| | | <ldap:name>ds-cfg-attribute-value-password-validator</ldap:name> |
| | | <ldap:superior>ds-cfg-password-validator</ldap:superior> |
| | | </ldap:object-class> |
| | | </adm:profile> |
| | | |
| | | <adm:property name="match-attribute" mandatory="false" multi-valued="true"> |
| | | <adm:synopsis> |
| | | Specifies the name(s) of the attribute(s) whose values should be checked |
| | | to determine whether they match the provided password. If this is not |
| | | provided, then all attributes in the user's entry will be checked. |
| | | </adm:synopsis> |
| | | <adm:default-behavior> |
| | | <adm:alias> |
| | | <adm:synopsis> |
| | | All attributes in the user entry will be checked. |
| | | </adm:synopsis> |
| | | </adm:alias> |
| | | </adm:default-behavior> |
| | | <adm:syntax> |
| | | <adm:attribute-type /> |
| | | </adm:syntax> |
| | | <adm:profile name="ldap"> |
| | | <ldap:attribute> |
| | | <ldap:oid>1.3.6.1.4.1.26027.1.1.146</ldap:oid> |
| | | <ldap:name>ds-cfg-match-attribute</ldap:name> |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | |
| | | <adm:property name="test-reversed-password" mandatory="true"> |
| | | <adm:synopsis> |
| | | Indicates whether this password validator should test the reversed value |
| | | of the provided password as well as the order in which it was given. |
| | | </adm:synopsis> |
| | | <adm:syntax> |
| | | <adm:boolean /> |
| | | </adm:syntax> |
| | | <adm:profile name="ldap"> |
| | | <ldap:attribute> |
| | | <ldap:oid>1.3.6.1.4.1.26027.1.1.337</ldap:oid> |
| | | <ldap:name>ds-cfg-test-reversed-password</ldap:name> |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | </adm:managed-object> |
| | | |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <adm:managed-object name="dictionary-password-validator" |
| | | plural-name="dictionary-password-validators" |
| | | package="org.opends.server.admin.std" extends="password-validator" |
| | | xmlns:adm="http://www.opends.org/admin" |
| | | xmlns:ldap="http://www.opends.org/admin-ldap"> |
| | | <adm:synopsis> |
| | | The |
| | | <adm:user-friendly-name /> |
| | | is used to determine whether a proposed password is acceptable based on |
| | | whether the given password value appears in a provided dictionary file. |
| | | </adm:synopsis> |
| | | <adm:profile name="ldap"> |
| | | <ldap:object-class> |
| | | <ldap:oid>1.3.6.1.4.1.26027.1.2.94</ldap:oid> |
| | | <ldap:name>ds-cfg-dictionary-password-validator</ldap:name> |
| | | <ldap:superior>ds-cfg-password-validator</ldap:superior> |
| | | </ldap:object-class> |
| | | </adm:profile> |
| | | |
| | | <adm:property name="dictionary-file" mandatory="true"> |
| | | <adm:synopsis> |
| | | Specifies the path to the file containing a list of words that may not be |
| | | used as passwords. It should be formatted with one word per line. The |
| | | value may be an absolute path, or a path that is relative to the |
| | | <adm:product-name /> |
| | | instance root. |
| | | </adm:synopsis> |
| | | <adm:syntax> |
| | | <adm:string /> |
| | | </adm:syntax> |
| | | <adm:profile name="ldap"> |
| | | <ldap:attribute> |
| | | <ldap:oid>1.3.6.1.4.1.26027.1.1.336</ldap:oid> |
| | | <ldap:name>ds-cfg-dictionary-file</ldap:name> |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | |
| | | <adm:property name="case-sensitive-validation" mandatory="true"> |
| | | <adm:synopsis> |
| | | Indicates whether this password validator should treat password characters |
| | | in a case-sensitive manner. |
| | | </adm:synopsis> |
| | | <adm:description> |
| | | Indicates whether this password validator should treat password characters |
| | | in a case-sensitive manner. A value of false indicates that any |
| | | differences in capitalization should be ignored when looking for |
| | | consecutive characters in the password. A value of true indicates that |
| | | a character should only be considered repeating if all consecutive |
| | | occurrences use the same capitalization. |
| | | </adm:description> |
| | | <adm:syntax> |
| | | <adm:boolean /> |
| | | </adm:syntax> |
| | | <adm:profile name="ldap"> |
| | | <ldap:attribute> |
| | | <ldap:oid>1.3.6.1.4.1.26027.1.1.324</ldap:oid> |
| | | <ldap:name>ds-cfg-case-sensitive-validation</ldap:name> |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | |
| | | <adm:property name="test-reversed-password" mandatory="true"> |
| | | <adm:synopsis> |
| | | Indicates whether this password validator should test the reversed value |
| | | of the provided password as well as the order in which it was given. |
| | | </adm:synopsis> |
| | | <adm:syntax> |
| | | <adm:boolean /> |
| | | </adm:syntax> |
| | | <adm:profile name="ldap"> |
| | | <ldap:attribute> |
| | | <ldap:oid>1.3.6.1.4.1.26027.1.1.337</ldap:oid> |
| | | <ldap:name>ds-cfg-test-reversed-password</ldap:name> |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | </adm:managed-object> |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.server.AttributeValuePasswordValidatorCfg; |
| | | import org.opends.server.api.PasswordValidator; |
| | | import org.opends.server.core.Operation; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.ByteString; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.ResultCode; |
| | | |
| | | import static org.opends.server.messages.ExtensionsMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class provides an OpenDS password validator that may be used to ensure |
| | | * that proposed passwords are not contained in another attribute in the user's |
| | | * entry. |
| | | */ |
| | | public class AttributeValuePasswordValidator |
| | | extends PasswordValidator<AttributeValuePasswordValidatorCfg> |
| | | implements ConfigurationChangeListener< |
| | | AttributeValuePasswordValidatorCfg> |
| | | { |
| | | // The current configuration for this password validator. |
| | | private AttributeValuePasswordValidatorCfg currentConfig; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new instance of this attribute value password validator. |
| | | */ |
| | | public AttributeValuePasswordValidator() |
| | | { |
| | | super(); |
| | | |
| | | // No implementation is required here. All initialization should be |
| | | // performed in the initializePasswordValidator() method. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public void initializePasswordValidator( |
| | | AttributeValuePasswordValidatorCfg configuration) |
| | | { |
| | | configuration.addAttributeValueChangeListener(this); |
| | | currentConfig = configuration; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public void finalizePasswordValidator() |
| | | { |
| | | currentConfig.removeAttributeValueChangeListener(this); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public boolean passwordIsAcceptable(ByteString newPassword, |
| | | Set<ByteString> currentPasswords, |
| | | Operation operation, Entry userEntry, |
| | | StringBuilder invalidReason) |
| | | { |
| | | // Get a handle to the current configuration. |
| | | AttributeValuePasswordValidatorCfg config = currentConfig; |
| | | |
| | | |
| | | // Get the string representation (both forward and reversed) for the |
| | | // password. |
| | | String password = newPassword.stringValue(); |
| | | String reversed = new StringBuilder(password).reverse().toString(); |
| | | |
| | | |
| | | // If we should check a specific set of attributes, then do that now. |
| | | // Otherwise, check all user attributes. |
| | | Set<AttributeType> matchAttributes = config.getMatchAttribute(); |
| | | if ((matchAttributes == null) || matchAttributes.isEmpty()) |
| | | { |
| | | matchAttributes = userEntry.getUserAttributes().keySet(); |
| | | } |
| | | |
| | | for (AttributeType t : matchAttributes) |
| | | { |
| | | List<Attribute> attrList = userEntry.getAttribute(t); |
| | | if ((attrList == null) || attrList.isEmpty()) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | AttributeValue vf = new AttributeValue(t, password); |
| | | AttributeValue vr = new AttributeValue(t, reversed); |
| | | |
| | | for (Attribute a : attrList) |
| | | { |
| | | if (a.hasValue(vf) || |
| | | (config.isTestReversedPassword() && a.hasValue(vr))) |
| | | { |
| | | int msgID = MSGID_ATTRVALUE_VALIDATOR_PASSWORD_IN_ENTRY; |
| | | invalidReason.append(getMessage(msgID)); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then the password is acceptable. |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isConfigurationChangeAcceptable( |
| | | AttributeValuePasswordValidatorCfg configuration, |
| | | List<String> unacceptableReasons) |
| | | { |
| | | // If we've gotten this far, then we'll accept the change. |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ConfigChangeResult applyConfigurationChange( |
| | | AttributeValuePasswordValidatorCfg configuration) |
| | | { |
| | | ResultCode resultCode = ResultCode.SUCCESS; |
| | | boolean adminActionRequired = false; |
| | | ArrayList<String> messages = new ArrayList<String>(); |
| | | |
| | | |
| | | currentConfig = configuration; |
| | | |
| | | return new ConfigChangeResult(resultCode, adminActionRequired, messages); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.File; |
| | | import java.io.FileReader; |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.server.DictionaryPasswordValidatorCfg; |
| | | import org.opends.server.api.PasswordValidator; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.Operation; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.ByteString; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | import org.opends.server.types.DirectoryConfig; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.InitializationException; |
| | | import org.opends.server.types.ResultCode; |
| | | |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | import static org.opends.server.messages.ExtensionsMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class provides an OpenDS password validator that may be used to ensure |
| | | * that proposed passwords are not contained in a specified dictionary. |
| | | */ |
| | | public class DictionaryPasswordValidator |
| | | extends PasswordValidator<DictionaryPasswordValidatorCfg> |
| | | implements ConfigurationChangeListener<DictionaryPasswordValidatorCfg> |
| | | { |
| | | // The current configuration for this password validator. |
| | | private DictionaryPasswordValidatorCfg currentConfig; |
| | | |
| | | // The current dictionary that we should use when performing the validation. |
| | | private HashSet<String> dictionary; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new instance of this dictionary password validator. |
| | | */ |
| | | public DictionaryPasswordValidator() |
| | | { |
| | | super(); |
| | | |
| | | // No implementation is required here. All initialization should be |
| | | // performed in the initializePasswordValidator() method. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public void initializePasswordValidator( |
| | | DictionaryPasswordValidatorCfg configuration) |
| | | throws ConfigException, InitializationException |
| | | { |
| | | configuration.addDictionaryChangeListener(this); |
| | | currentConfig = configuration; |
| | | |
| | | dictionary = loadDictionary(configuration); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public void finalizePasswordValidator() |
| | | { |
| | | currentConfig.removeDictionaryChangeListener(this); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public boolean passwordIsAcceptable(ByteString newPassword, |
| | | Set<ByteString> currentPasswords, |
| | | Operation operation, Entry userEntry, |
| | | StringBuilder invalidReason) |
| | | { |
| | | // Get a handle to the current configuration. |
| | | DictionaryPasswordValidatorCfg config = currentConfig; |
| | | HashSet<String> dictionary = this.dictionary; |
| | | |
| | | |
| | | // Check to see if the provided password is in the dictionary in the order |
| | | // that it was provided. |
| | | String password = newPassword.stringValue(); |
| | | if (! config.isCaseSensitiveValidation()) |
| | | { |
| | | password = toLowerCase(password); |
| | | } |
| | | |
| | | if (dictionary.contains(password)) |
| | | { |
| | | int msgID = MSGID_DICTIONARY_VALIDATOR_PASSWORD_IN_DICTIONARY; |
| | | invalidReason.append(getMessage(msgID)); |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // If we should try the reversed value, then do that as well. |
| | | if (config.isTestReversedPassword()) |
| | | { |
| | | if (dictionary.contains(new StringBuilder(password).reverse().toString())) |
| | | { |
| | | int msgID = MSGID_DICTIONARY_VALIDATOR_PASSWORD_IN_DICTIONARY; |
| | | invalidReason.append(getMessage(msgID)); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then the password is acceptable. |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Loads the configured dictionary and returns it as a hash set. |
| | | * |
| | | * @param configuration the configuration for this password validator. |
| | | * |
| | | * @return The hash set containing the loaded dictionary data. |
| | | * |
| | | * @throws ConfigException If the configured dictionary file does not exist. |
| | | * |
| | | * @throws InitializationException If a problem occurs while attempting to |
| | | * read from the dictionary file. |
| | | */ |
| | | private HashSet<String> loadDictionary( |
| | | DictionaryPasswordValidatorCfg configuration) |
| | | throws ConfigException, InitializationException |
| | | { |
| | | // Get the path to the dictionary file and make sure it exists. |
| | | File dictionaryFile = getFileForPath(configuration.getDictionaryFile()); |
| | | if (! dictionaryFile.exists()) |
| | | { |
| | | int msgID = MSGID_DICTIONARY_VALIDATOR_NO_SUCH_FILE; |
| | | String message = getMessage(msgID, configuration.getDictionaryFile()); |
| | | throw new ConfigException(msgID, message); |
| | | } |
| | | |
| | | |
| | | // Read the contents of file into the dictionary as per the configuration. |
| | | BufferedReader reader = null; |
| | | HashSet<String> dictionary = new HashSet<String>(); |
| | | try |
| | | { |
| | | reader = new BufferedReader(new FileReader(dictionaryFile)); |
| | | String line = reader.readLine(); |
| | | while (line != null) |
| | | { |
| | | if (! configuration.isCaseSensitiveValidation()) |
| | | { |
| | | line = line.toLowerCase(); |
| | | } |
| | | |
| | | dictionary.add(line); |
| | | line = reader.readLine(); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | int msgID = MSGID_DICTIONARY_VALIDATOR_CANNOT_READ_FILE; |
| | | String message = getMessage(msgID, configuration.getDictionaryFile(), |
| | | String.valueOf(e)); |
| | | throw new InitializationException(msgID, message); |
| | | } |
| | | finally |
| | | { |
| | | if (reader != null) |
| | | { |
| | | try |
| | | { |
| | | reader.close(); |
| | | } catch (Exception e) {} |
| | | } |
| | | } |
| | | |
| | | return dictionary; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isConfigurationChangeAcceptable( |
| | | DictionaryPasswordValidatorCfg configuration, |
| | | List<String> unacceptableReasons) |
| | | { |
| | | // Make sure that we can load the dictionary. If so, then we'll accept the |
| | | // new configuration. |
| | | try |
| | | { |
| | | loadDictionary(configuration); |
| | | } |
| | | catch (ConfigException ce) |
| | | { |
| | | unacceptableReasons.add(ce.getMessage()); |
| | | return false; |
| | | } |
| | | catch (InitializationException ie) |
| | | { |
| | | unacceptableReasons.add(ie.getMessage()); |
| | | return false; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | unacceptableReasons.add(stackTraceToSingleLineString(e)); |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ConfigChangeResult applyConfigurationChange( |
| | | DictionaryPasswordValidatorCfg configuration) |
| | | { |
| | | ResultCode resultCode = ResultCode.SUCCESS; |
| | | boolean adminActionRequired = false; |
| | | ArrayList<String> messages = new ArrayList<String>(); |
| | | |
| | | |
| | | // Make sure we can load the dictionary. If we can, then activate the new |
| | | // configuration. |
| | | try |
| | | { |
| | | dictionary = loadDictionary(configuration); |
| | | currentConfig = configuration; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | resultCode = DirectoryConfig.getServerErrorResultCode(); |
| | | messages.add(stackTraceToSingleLineString(e)); |
| | | } |
| | | |
| | | return new ConfigChangeResult(resultCode, adminActionRequired, messages); |
| | | } |
| | | } |
| | | |
| | |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 459; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided password |
| | | * is contained in the server's dictionary. This does not take any arguments. |
| | | */ |
| | | public static final int MSGID_DICTIONARY_VALIDATOR_PASSWORD_IN_DICTIONARY = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 460; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided password |
| | | * dictionary file does not exist. This takes a single argument, which is the |
| | | * path to the dictionary file. |
| | | */ |
| | | public static final int MSGID_DICTIONARY_VALIDATOR_NO_SUCH_FILE = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 461; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an error occurs while |
| | | * trying to read the password file. This takes two arguments, which is the |
| | | * path to the dictionary file and a string representation of the exception |
| | | * that was caught. |
| | | */ |
| | | public static final int MSGID_DICTIONARY_VALIDATOR_CANNOT_READ_FILE = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 462; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided password |
| | | * is contained in another attribute in the user's entry. This does not take |
| | | * any arguments. |
| | | */ |
| | | public static final int MSGID_ATTRVALUE_VALIDATOR_PASSWORD_IN_ENTRY = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 463; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided password |
| | | * contains a character not included in any of the defined character sets. |
| | | * This takes a single argument, which is the illegal character. |
| | | */ |
| | | public static final int MSGID_CHARSET_VALIDATOR_ILLEGAL_CHARACTER = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 464; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided password |
| | | * contains too few passwords from a given character set. This takes two |
| | | * arguments, which is a string of the characters from that set and the |
| | | * minimum number of characters from that set which must be used in passwords. |
| | | */ |
| | | public static final int MSGID_CHARSET_VALIDATOR_TOO_FEW_CHARS_FROM_SET = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 465; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided character |
| | | * set definition does not contain a colon to separate the count from the |
| | | * character set. This takes a single argument, which is the provided |
| | | * definition string. |
| | | */ |
| | | public static final int MSGID_CHARSET_VALIDATOR_NO_COLON = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 466; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided character |
| | | * set definition does not contain any characters after the colon. This takes |
| | | * a single argument, which is the provided definition string. |
| | | */ |
| | | public static final int MSGID_CHARSET_VALIDATOR_NO_CHARS = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 467; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided character |
| | | * set definition is invalid because the value before the colon could not be |
| | | * parsed as positive integer. This takes a single argument, which is the |
| | | * provided definition string. |
| | | */ |
| | | public static final int MSGID_CHARSET_VALIDATOR_INVALID_COUNT = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 468; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided character |
| | | * set definition contains a character that has already been used. This takes |
| | | * two arguments, which are the provided definition string and the duplicate |
| | | * character. |
| | | */ |
| | | public static final int MSGID_CHARSET_VALIDATOR_DUPLICATE_CHAR = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 469; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | |
| | | registerMessage(MSGID_SUBSCHEMASUBENTRY_VATTR_NOT_SEARCHABLE, |
| | | "The %s attribute is not searchable and should not be " + |
| | | "included in otherwise unindexed search filters."); |
| | | |
| | | |
| | | registerMessage(MSGID_DICTIONARY_VALIDATOR_PASSWORD_IN_DICTIONARY, |
| | | "The provided password was found in the server's " + |
| | | "dictionary."); |
| | | registerMessage(MSGID_DICTIONARY_VALIDATOR_NO_SUCH_FILE, |
| | | "The specified dictionary file %s does not exist."); |
| | | registerMessage(MSGID_DICTIONARY_VALIDATOR_CANNOT_READ_FILE, |
| | | "An error occurred while attempting to load the " + |
| | | "dictionary from file %s: %s."); |
| | | |
| | | |
| | | registerMessage(MSGID_ATTRVALUE_VALIDATOR_PASSWORD_IN_ENTRY, |
| | | "The provided password was found in another attribute " + |
| | | "in the user entry."); |
| | | |
| | | |
| | | registerMessage(MSGID_CHARSET_VALIDATOR_ILLEGAL_CHARACTER, |
| | | "The provided password contained character '%s' which is " + |
| | | "not allowed for use in passwords."); |
| | | registerMessage(MSGID_CHARSET_VALIDATOR_TOO_FEW_CHARS_FROM_SET, |
| | | "The provided password did not contain enough " + |
| | | "characters from the character set '%s'. The minimum " + |
| | | "number of characters from that set that must be present " + |
| | | "in user passwords is %d."); |
| | | registerMessage(MSGID_CHARSET_VALIDATOR_NO_COLON, |
| | | "The provided character set definition '%s' is invalid " + |
| | | "because it does not contain a colon to separate the " + |
| | | "minimum count from the character set."); |
| | | registerMessage(MSGID_CHARSET_VALIDATOR_NO_CHARS, |
| | | "The provided character set definition '%s' is invalid " + |
| | | "because the provided character set is empty."); |
| | | registerMessage(MSGID_CHARSET_VALIDATOR_INVALID_COUNT, |
| | | "The provided character set definition '%s' is invalid " + |
| | | "because the value before the colon must be an integer " + |
| | | "greater than zero."); |
| | | registerMessage(MSGID_CHARSET_VALIDATOR_DUPLICATE_CHAR, |
| | | "The provided character set definition '%s' is invalid " + |
| | | "because it contains character '%s' which has already " + |
| | | "been used."); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Portions Copyright 2006-2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.std.meta.AttributeValuePasswordValidatorCfgDefn; |
| | | import org.opends.server.admin.std.server.AttributeValuePasswordValidatorCfg; |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.config.ConfigEntry; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.ModifyOperation; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.ByteString; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.Control; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.InitializationException; |
| | | import org.opends.server.types.Modification; |
| | | import org.opends.server.types.ModificationType; |
| | | import org.opends.server.types.ResultCode; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * A set of test cases for the attribute value password validator. |
| | | */ |
| | | public class AttributeValuePasswordValidatorTestCase |
| | | extends ExtensionsTestCase |
| | | { |
| | | /** |
| | | * Ensures that the Directory Server is running. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @BeforeClass() |
| | | public void startServer() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a set of valid configuration entries that may be used to |
| | | * initialize the validator. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @DataProvider(name = "validConfigs") |
| | | public Object[][] getValidConfigs() |
| | | throws Exception |
| | | { |
| | | List<Entry> entries = TestCaseUtils.makeEntries( |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-test-reversed-password: true", |
| | | "", |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-match-attribute: uid", |
| | | "ds-cfg-test-reversed-password: true", |
| | | "", |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-match-attribute: uid", |
| | | "ds-cfg-match-attribute: cn", |
| | | "ds-cfg-match-attribute: givenName", |
| | | "ds-cfg-match-attribute: sn", |
| | | "ds-cfg-test-reversed-password: true", |
| | | "", |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-test-reversed-password: false"); |
| | | |
| | | Object[][] array = new Object[entries.size()][1]; |
| | | for (int i=0; i < array.length; i++) |
| | | { |
| | | array[i] = new Object[] { entries.get(i) }; |
| | | } |
| | | |
| | | return array; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the process of initializing the server with valid configurations. |
| | | * |
| | | * @param entry The configuration entry to use for the initialization. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "validConfigs", groups= { "slow" }) |
| | | public void testInitializeWithValidConfigs(Entry e) |
| | | throws Exception |
| | | { |
| | | AttributeValuePasswordValidatorCfg configuration = |
| | | AdminTestCaseUtils.getConfiguration( |
| | | AttributeValuePasswordValidatorCfgDefn.getInstance(), e); |
| | | |
| | | AttributeValuePasswordValidator validator = |
| | | new AttributeValuePasswordValidator(); |
| | | validator.initializePasswordValidator(configuration); |
| | | validator.finalizePasswordValidator(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a set of invalid configuration entries. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @DataProvider(name = "invalidConfigs") |
| | | public Object[][] getInvalidConfigs() |
| | | throws Exception |
| | | { |
| | | List<Entry> entries = TestCaseUtils.makeEntries( |
| | | // Invalid test-reversed-password |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-test-reversed-password: invalid", |
| | | "", |
| | | // Invalid match attribute. |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-match-attribute: nosuchattribute", |
| | | "ds-cfg-test-reversed-password: true"); |
| | | |
| | | Object[][] array = new Object[entries.size()][1]; |
| | | for (int i=0; i < array.length; i++) |
| | | { |
| | | array[i] = new Object[] { entries.get(i) }; |
| | | } |
| | | |
| | | return array; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the process of initializing the server with invalid configurations. |
| | | * |
| | | * @param entry The configuration entry to use for the initialization. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "invalidConfigs", |
| | | expectedExceptions = { ConfigException.class, |
| | | InitializationException.class }) |
| | | public void testInitializeWithInvalidConfigs(Entry e) |
| | | throws Exception |
| | | { |
| | | AttributeValuePasswordValidatorCfg configuration = |
| | | AdminTestCaseUtils.getConfiguration( |
| | | AttributeValuePasswordValidatorCfgDefn.getInstance(), e); |
| | | |
| | | AttributeValuePasswordValidator validator = |
| | | new AttributeValuePasswordValidator(); |
| | | validator.initializePasswordValidator(configuration); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a set of data to use when testing a given password with a |
| | | * provided configuration. Each element of the returned array should be an |
| | | * array of a configuration entry, a test password string, and an indication |
| | | * as to whether the provided password should be acceptable. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @DataProvider(name = "testData") |
| | | public Object[][] getTestData() |
| | | throws Exception |
| | | { |
| | | return new Object[][] |
| | | { |
| | | // Default configuration, with a password that does not match an existing |
| | | // attribute value. |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "password", |
| | | true |
| | | }, |
| | | |
| | | // Default configuration, with a password that matches an existing |
| | | // attribute value. |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "test", |
| | | false |
| | | }, |
| | | |
| | | // Default configuration, with a password that matches the reverse of an |
| | | // existing attribute value with reverwse matching enabled |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "tset", |
| | | false |
| | | }, |
| | | |
| | | // Default configuration, with a password that matches the reverse of an |
| | | // existing attribute value with reverwse matching disabled |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-test-reversed-password: false"), |
| | | "tset", |
| | | true |
| | | }, |
| | | |
| | | // Default configuration, with a password that matches one of the values |
| | | // of a specified set of attributes. |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-match-attribute: cn", |
| | | "ds-cfg-match-attribute: sn", |
| | | "ds-cfg-match-attribute: givenName", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "test", |
| | | false |
| | | }, |
| | | |
| | | // Default configuration, with a password that doesn't match any of the |
| | | // values of a specified set of attributes but does match the value of |
| | | // another attribute in the entry. |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Attribute Value,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-attribute-value-password-validator", |
| | | "cn: Attribute Value", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "AttributeValuePasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-match-attribute: cn", |
| | | "ds-cfg-match-attribute: sn", |
| | | "ds-cfg-match-attribute: givenName", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "test.user", |
| | | true |
| | | }, |
| | | }; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the {@code passwordIsAcceptable} method using the provided |
| | | * information. |
| | | * |
| | | * @param configEntry The configuration entry to use for the password |
| | | * validator. |
| | | * @param password The password to test with the validator. |
| | | * @param acceptable Indicates whether the provided password should be |
| | | * considered acceptable. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "testData") |
| | | public void testPasswordIsAcceptable(Entry configEntry, String password, |
| | | boolean acceptable) |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=test.user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: test.user", |
| | | "givenName: Test", |
| | | "sn: User", |
| | | "cn: Test User", |
| | | "userPassword: doesntmatter"); |
| | | |
| | | AttributeValuePasswordValidatorCfg configuration = |
| | | AdminTestCaseUtils.getConfiguration( |
| | | AttributeValuePasswordValidatorCfgDefn.getInstance(), |
| | | configEntry); |
| | | |
| | | AttributeValuePasswordValidator validator = |
| | | new AttributeValuePasswordValidator(); |
| | | validator.initializePasswordValidator(configuration); |
| | | |
| | | ASN1OctetString pwOS = new ASN1OctetString(password); |
| | | ArrayList<Modification> mods = new ArrayList<Modification>(); |
| | | mods.add(new Modification(ModificationType.REPLACE, |
| | | new Attribute("userpassword", password))); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | ModifyOperation modifyOperation = |
| | | new ModifyOperation(conn, conn.nextOperationID(), conn.nextMessageID(), |
| | | new ArrayList<Control>(), |
| | | DN.decode("uid=test.user,o=test"), mods); |
| | | |
| | | StringBuilder invalidReason = new StringBuilder(); |
| | | assertEquals(validator.passwordIsAcceptable(pwOS, |
| | | new HashSet<ByteString>(0), modifyOperation, |
| | | userEntry, invalidReason), |
| | | acceptable, invalidReason.toString()); |
| | | |
| | | validator.finalizePasswordValidator(); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Portions Copyright 2006-2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | |
| | | import java.io.BufferedWriter; |
| | | import java.io.File; |
| | | import java.io.FileWriter; |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.std.meta.DictionaryPasswordValidatorCfgDefn; |
| | | import org.opends.server.admin.std.server.DictionaryPasswordValidatorCfg; |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.config.ConfigEntry; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.ModifyOperation; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.ByteString; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.Control; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.InitializationException; |
| | | import org.opends.server.types.Modification; |
| | | import org.opends.server.types.ModificationType; |
| | | import org.opends.server.types.ResultCode; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * A set of test cases for the dictionary password validator. |
| | | */ |
| | | public class DictionaryPasswordValidatorTestCase |
| | | extends ExtensionsTestCase |
| | | { |
| | | /** |
| | | * The path to the dictionary file that we have created for the purposes of |
| | | * this test case. |
| | | */ |
| | | private static String dictionaryFile; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Ensures that the Directory Server is running. Also, create a very small |
| | | * test dictionary file to use for the test cases so we don't suffer from |
| | | * loading the real word list every time. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @BeforeClass() |
| | | public void startServer() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | |
| | | dictionaryFile = TestCaseUtils.createTempFile( |
| | | "love", |
| | | "sex", |
| | | "secret", |
| | | "god", |
| | | "password" |
| | | ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a set of valid configuration entries that may be used to |
| | | * initialize the validator. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @DataProvider(name = "validConfigs") |
| | | public Object[][] getValidConfigs() |
| | | throws Exception |
| | | { |
| | | List<Entry> entries = TestCaseUtils.makeEntries( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true", |
| | | "", |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: true", |
| | | "ds-cfg-test-reversed-password: true", |
| | | "", |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true"); |
| | | |
| | | Object[][] array = new Object[entries.size()][1]; |
| | | for (int i=0; i < array.length; i++) |
| | | { |
| | | array[i] = new Object[] { entries.get(i) }; |
| | | } |
| | | |
| | | return array; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the process of initializing the server with valid configurations. |
| | | * |
| | | * @param entry The configuration entry to use for the initialization. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "validConfigs") |
| | | public void testInitializeWithValidConfigs(Entry e) |
| | | throws Exception |
| | | { |
| | | DictionaryPasswordValidatorCfg configuration = |
| | | AdminTestCaseUtils.getConfiguration( |
| | | DictionaryPasswordValidatorCfgDefn.getInstance(), e); |
| | | |
| | | DictionaryPasswordValidator validator = |
| | | new DictionaryPasswordValidator(); |
| | | validator.initializePasswordValidator(configuration); |
| | | validator.finalizePasswordValidator(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a set of invalid configuration entries. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @DataProvider(name = "invalidConfigs") |
| | | public Object[][] getInvalidConfigs() |
| | | throws Exception |
| | | { |
| | | List<Entry> entries = TestCaseUtils.makeEntries( |
| | | // Invalid dictionary file |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: invalid", |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true", |
| | | "", |
| | | // Dictionary file not a file. |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: config", |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true", |
| | | "", |
| | | // Invalid case-sensitive-validation |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: invalid", |
| | | "ds-cfg-test-reversed-password: true", |
| | | "", |
| | | // Invalid test-reversed-password |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: invalid"); |
| | | |
| | | Object[][] array = new Object[entries.size()][1]; |
| | | for (int i=0; i < array.length; i++) |
| | | { |
| | | array[i] = new Object[] { entries.get(i) }; |
| | | } |
| | | |
| | | return array; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the process of initializing the server with invalid configurations. |
| | | * |
| | | * @param entry The configuration entry to use for the initialization. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "invalidConfigs", |
| | | expectedExceptions = { ConfigException.class, |
| | | InitializationException.class }) |
| | | public void testInitializeWithInvalidConfigs(Entry e) |
| | | throws Exception |
| | | { |
| | | DictionaryPasswordValidatorCfg configuration = |
| | | AdminTestCaseUtils.getConfiguration( |
| | | DictionaryPasswordValidatorCfgDefn.getInstance(), e); |
| | | |
| | | DictionaryPasswordValidator validator = |
| | | new DictionaryPasswordValidator(); |
| | | validator.initializePasswordValidator(configuration); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a set of data to use when testing a given password with a |
| | | * provided configuration. Each element of the returned array should be an |
| | | * array of a configuration entry, a test password string, and an indication |
| | | * as to whether the provided password should be acceptable. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @DataProvider(name = "testData") |
| | | public Object[][] getTestData() |
| | | throws Exception |
| | | { |
| | | return new Object[][] |
| | | { |
| | | // Default configuration with a word not in the dictionary. |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "notindictionary", |
| | | true |
| | | }, |
| | | |
| | | // Default configuration with a word in the dictionary |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "password", |
| | | false |
| | | }, |
| | | |
| | | // Default configuration with a word in the dictionary, case-insensitive |
| | | // matching enabled |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "PaSsWoRd", |
| | | false |
| | | }, |
| | | |
| | | // Default configuration with a word in the dictionary, case-insensitive |
| | | // matching disabled |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: true", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "PaSsWoRd", |
| | | true |
| | | }, |
| | | |
| | | // Default configuration with a reverse of a word in the dictionary, |
| | | // reversed matching enabled |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "drowssap", |
| | | false |
| | | }, |
| | | |
| | | // Default configuration with a reverse of a word in the dictionary, |
| | | // reversed matching disabled |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: false"), |
| | | "drowssap", |
| | | true |
| | | }, |
| | | |
| | | // Default configuration with a reverse of a word in the dictionary, |
| | | // reversed matching enabled and case-insensitive matching enabled |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: false", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "dRoWsSaP", |
| | | false |
| | | }, |
| | | |
| | | // Default configuration with a reverse of a word in the dictionary, |
| | | // reversed matching enabled and case-insensitive matching disabled |
| | | new Object[] |
| | | { |
| | | TestCaseUtils.makeEntry( |
| | | "dn: cn=Dictionary,cn=Password Validators,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-password-validator", |
| | | "objectClass: ds-cfg-dictionary-password-validator", |
| | | "cn: Dictionary", |
| | | "ds-cfg-password-validator-class: org.opends.server.extensions." + |
| | | "DictionaryPasswordValidator", |
| | | "ds-cfg-password-validator-enabled: true", |
| | | "ds-cfg-dictionary-file: " + dictionaryFile, |
| | | "ds-cfg-case-sensitive-validation: true", |
| | | "ds-cfg-test-reversed-password: true"), |
| | | "dRoWsSaP", |
| | | true |
| | | }, |
| | | }; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the {@code passwordIsAcceptable} method using the provided |
| | | * information. |
| | | * |
| | | * @param configEntry The configuration entry to use for the password |
| | | * validator. |
| | | * @param password The password to test with the validator. |
| | | * @param acceptable Indicates whether the provided password should be |
| | | * considered acceptable. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "testData") |
| | | public void testPasswordIsAcceptable(Entry configEntry, String password, |
| | | boolean acceptable) |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=test.user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: test.user", |
| | | "givenName: Test", |
| | | "sn: User", |
| | | "cn: Test User", |
| | | "userPassword: doesntmatter"); |
| | | |
| | | DictionaryPasswordValidatorCfg configuration = |
| | | AdminTestCaseUtils.getConfiguration( |
| | | DictionaryPasswordValidatorCfgDefn.getInstance(), |
| | | configEntry); |
| | | |
| | | DictionaryPasswordValidator validator = |
| | | new DictionaryPasswordValidator(); |
| | | validator.initializePasswordValidator(configuration); |
| | | |
| | | ASN1OctetString pwOS = new ASN1OctetString(password); |
| | | ArrayList<Modification> mods = new ArrayList<Modification>(); |
| | | mods.add(new Modification(ModificationType.REPLACE, |
| | | new Attribute("userpassword", password))); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | ModifyOperation modifyOperation = |
| | | new ModifyOperation(conn, conn.nextOperationID(), conn.nextMessageID(), |
| | | new ArrayList<Control>(), |
| | | DN.decode("uid=test.user,o=test"), mods); |
| | | |
| | | StringBuilder invalidReason = new StringBuilder(); |
| | | assertEquals(validator.passwordIsAcceptable(pwOS, |
| | | new HashSet<ByteString>(0), modifyOperation, |
| | | userEntry, invalidReason), |
| | | acceptable, invalidReason.toString()); |
| | | |
| | | validator.finalizePasswordValidator(); |
| | | } |
| | | } |
| | | |