| | |
| | | package org.opends.server.core; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | |
| | | import org.opends.server.api.ConfigurableComponent; |
| | | import org.opends.server.api.PasswordStorageScheme; |
| | | import org.opends.server.config.BooleanConfigAttribute; |
| | | import org.opends.server.config.ConfigAttribute; |
| | | import org.opends.server.config.ConfigEntry; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.server.PasswordPolicyCfg; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.config.DNConfigAttribute; |
| | | import org.opends.server.config.IntegerConfigAttribute; |
| | | import org.opends.server.config.IntegerWithUnitConfigAttribute; |
| | | import org.opends.server.config.StringConfigAttribute; |
| | | import org.opends.server.schema.GeneralizedTimeSyntax; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.InitializationException; |
| | | import org.opends.server.types.ResultCode; |
| | | |
| | | import static org.opends.server.config.ConfigConstants.*; |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugCaught; |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | import static org.opends.server.messages.CoreMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | |
| | | /** |
| | | This class is the interface between the password policy configurable component |
| | |
| | | valiadating any proposed modification and applying an accepted modification. |
| | | */ |
| | | public class PasswordPolicyConfig |
| | | implements ConfigurableComponent |
| | | implements ConfigurationChangeListener<PasswordPolicyCfg> |
| | | { |
| | | |
| | | /** |
| | |
| | | public PasswordPolicyConfig(PasswordPolicy policy) |
| | | { |
| | | this.currentPolicy = policy; |
| | | DirectoryServer.registerConfigurableComponent(this); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Finalize a password policy configuration handler. |
| | | * {@inheritDoc} |
| | | */ |
| | | public void finalizePasswordPolicyConfig() |
| | | public boolean isConfigurationChangeAcceptable( |
| | | PasswordPolicyCfg configuration, List<String> unacceptableReasons) |
| | | { |
| | | DirectoryServer.deregisterConfigurableComponent(this); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the DN of the configuration entry with which this component is |
| | | * associated. |
| | | * |
| | | * @return The DN of the configuration entry with which this component is |
| | | * associated. |
| | | */ |
| | | public DN getConfigurableComponentEntryDN() |
| | | { |
| | | return currentPolicy.getConfigEntryDN(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the set of configuration attributes that are associated with this |
| | | * configurable component. |
| | | * |
| | | * @return The set of configuration attributes that are associated with this |
| | | * configurable component. |
| | | */ |
| | | public List<ConfigAttribute> getConfigurationAttributes() |
| | | { |
| | | // Create a list of units and values that we can use to represent time |
| | | // periods. |
| | | LinkedHashMap<String,Double> timeUnits = new LinkedHashMap<String,Double>(); |
| | | timeUnits.put(TIME_UNIT_SECONDS_ABBR, 1D); |
| | | timeUnits.put(TIME_UNIT_SECONDS_FULL, 1D); |
| | | timeUnits.put(TIME_UNIT_MINUTES_ABBR, 60D); |
| | | timeUnits.put(TIME_UNIT_MINUTES_FULL, 60D); |
| | | timeUnits.put(TIME_UNIT_HOURS_ABBR, (double) (60 * 60)); |
| | | timeUnits.put(TIME_UNIT_HOURS_FULL, (double) (60 * 60)); |
| | | timeUnits.put(TIME_UNIT_DAYS_ABBR, (double) (60 * 60 * 24)); |
| | | timeUnits.put(TIME_UNIT_DAYS_FULL, (double) (60 * 60 * 24)); |
| | | timeUnits.put(TIME_UNIT_WEEKS_ABBR, (double) (60 * 60 * 24 * 7)); |
| | | timeUnits.put(TIME_UNIT_WEEKS_FULL, (double) (60 * 60 * 24 * 7)); |
| | | |
| | | |
| | | PasswordPolicy policy = this.currentPolicy; // this field is volatile |
| | | |
| | | LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>(); |
| | | |
| | | int msgID = MSGID_PWPOLICY_DESCRIPTION_PW_ATTR; |
| | | String pwAttr = (policy.getPasswordAttribute() == null) |
| | | ? null |
| | | : policy.getPasswordAttribute().getNameOrOID(); |
| | | attrList.add(new StringConfigAttribute(ATTR_PWPOLICY_PASSWORD_ATTRIBUTE, |
| | | getMessage(msgID), false, false, |
| | | false, pwAttr)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_DEFAULT_STORAGE_SCHEMES; |
| | | ArrayList<String> schemes = new ArrayList<String>(); |
| | | for (PasswordStorageScheme s : policy.getDefaultStorageSchemes()) |
| | | { |
| | | schemes.add(s.getStorageSchemeName()); |
| | | } |
| | | attrList.add(new StringConfigAttribute(ATTR_PWPOLICY_DEFAULT_SCHEME, |
| | | getMessage(msgID), false, true, |
| | | false, schemes)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_DEPRECATED_STORAGE_SCHEMES; |
| | | ArrayList<String> deprecatedSchemes = new ArrayList<String>(); |
| | | deprecatedSchemes.addAll(policy.getDeprecatedStorageSchemes()); |
| | | attrList.add(new StringConfigAttribute(ATTR_PWPOLICY_DEPRECATED_SCHEME, |
| | | getMessage(msgID), false, true, |
| | | false, deprecatedSchemes)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_PASSWORD_VALIDATORS; |
| | | ArrayList<DN> validatorDNs = new ArrayList<DN>(); |
| | | validatorDNs.addAll(policy.getPasswordValidators().keySet()); |
| | | attrList.add(new DNConfigAttribute(ATTR_PWPOLICY_PASSWORD_VALIDATOR, |
| | | getMessage(msgID), false, true, false, |
| | | validatorDNs)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_NOTIFICATION_HANDLERS; |
| | | ArrayList<DN> handlerDNs = new ArrayList<DN>(); |
| | | handlerDNs.addAll(policy.getAccountStatusNotificationHandlers().keySet()); |
| | | attrList.add(new DNConfigAttribute(ATTR_PWPOLICY_NOTIFICATION_HANDLER, |
| | | getMessage(msgID), false, true, false, |
| | | handlerDNs)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_ALLOW_USER_PW_CHANGES; |
| | | attrList.add(new BooleanConfigAttribute(ATTR_PWPOLICY_ALLOW_USER_CHANGE, |
| | | getMessage(msgID), false, |
| | | policy.allowUserPasswordChanges())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_REQUIRE_CURRENT_PW; |
| | | attrList.add(new BooleanConfigAttribute( |
| | | ATTR_PWPOLICY_REQUIRE_CURRENT_PASSWORD, |
| | | getMessage(msgID), false, |
| | | policy.requireCurrentPassword())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_FORCE_CHANGE_ON_ADD; |
| | | attrList.add(new BooleanConfigAttribute(ATTR_PWPOLICY_FORCE_CHANGE_ON_ADD, |
| | | getMessage(msgID), false, |
| | | policy.forceChangeOnAdd())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_FORCE_CHANGE_ON_RESET; |
| | | attrList.add(new BooleanConfigAttribute(ATTR_PWPOLICY_FORCE_CHANGE_ON_RESET, |
| | | getMessage(msgID), false, |
| | | policy.forceChangeOnReset())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_SKIP_ADMIN_VALIDATION; |
| | | attrList.add(new BooleanConfigAttribute( |
| | | ATTR_PWPOLICY_SKIP_ADMIN_VALIDATION, |
| | | getMessage(msgID), false, |
| | | policy.skipValidationForAdministrators())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_PASSWORD_GENERATOR; |
| | | attrList.add(new DNConfigAttribute(ATTR_PWPOLICY_PASSWORD_GENERATOR, |
| | | getMessage(msgID), false, false, false, |
| | | policy.getPasswordGeneratorDN())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_REQUIRE_SECURE_AUTH; |
| | | attrList.add(new BooleanConfigAttribute( |
| | | ATTR_PWPOLICY_REQUIRE_SECURE_AUTHENTICATION, |
| | | getMessage(msgID), false, |
| | | policy.requireSecureAuthentication())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_REQUIRE_SECURE_CHANGES; |
| | | attrList.add(new BooleanConfigAttribute( |
| | | ATTR_PWPOLICY_REQUIRE_SECURE_PASSWORD_CHANGES, |
| | | getMessage(msgID), false, |
| | | policy.requireSecurePasswordChanges())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_ALLOW_MULTIPLE_PW_VALUES; |
| | | attrList.add(new BooleanConfigAttribute( |
| | | ATTR_PWPOLICY_ALLOW_MULTIPLE_PW_VALUES, |
| | | getMessage(msgID), false, |
| | | policy.allowMultiplePasswordValues())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_ALLOW_PREENCODED; |
| | | attrList.add(new BooleanConfigAttribute( |
| | | ATTR_PWPOLICY_ALLOW_PRE_ENCODED_PASSWORDS, |
| | | getMessage(msgID), false, |
| | | policy.allowPreEncodedPasswords())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_MIN_AGE; |
| | | attrList.add(new IntegerWithUnitConfigAttribute( |
| | | ATTR_PWPOLICY_MINIMUM_PASSWORD_AGE, |
| | | getMessage(msgID), false, timeUnits, true, 0, true, |
| | | Integer.MAX_VALUE, policy.getMinimumPasswordAge(), |
| | | TIME_UNIT_SECONDS_FULL)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_MAX_AGE; |
| | | attrList.add(new IntegerWithUnitConfigAttribute( |
| | | ATTR_PWPOLICY_MAXIMUM_PASSWORD_AGE, |
| | | getMessage(msgID), false, timeUnits, true, 0, true, |
| | | Integer.MAX_VALUE, policy.getMaximumPasswordAge(), |
| | | TIME_UNIT_SECONDS_FULL)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_MAX_RESET_AGE; |
| | | attrList.add(new IntegerWithUnitConfigAttribute( |
| | | ATTR_PWPOLICY_MAXIMUM_PASSWORD_RESET_AGE, |
| | | getMessage(msgID), false, timeUnits, true, 0, true, |
| | | Integer.MAX_VALUE, |
| | | policy.getMaximumPasswordResetAge(), |
| | | TIME_UNIT_SECONDS_FULL)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_WARNING_INTERVAL; |
| | | attrList.add(new IntegerWithUnitConfigAttribute( |
| | | ATTR_PWPOLICY_WARNING_INTERVAL, getMessage(msgID), |
| | | false, timeUnits, true, 0, true, Integer.MAX_VALUE, |
| | | policy.getWarningInterval(), TIME_UNIT_SECONDS_FULL)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_EXPIRE_WITHOUT_WARNING; |
| | | attrList.add(new BooleanConfigAttribute( |
| | | ATTR_PWPOLICY_EXPIRE_WITHOUT_WARNING, |
| | | getMessage(msgID), false, |
| | | policy.expirePasswordsWithoutWarning())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_ALLOW_EXPIRED_CHANGES; |
| | | attrList.add(new BooleanConfigAttribute( |
| | | ATTR_PWPOLICY_ALLOW_EXPIRED_CHANGES, |
| | | getMessage(msgID), false, |
| | | policy.allowExpiredPasswordChanges())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_GRACE_LOGIN_COUNT; |
| | | attrList.add(new IntegerConfigAttribute(ATTR_PWPOLICY_GRACE_LOGIN_COUNT, |
| | | getMessage(msgID), false, false, |
| | | false, true, 0, true, |
| | | Integer.MAX_VALUE, |
| | | policy.getGraceLoginCount())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_LOCKOUT_FAILURE_COUNT; |
| | | attrList.add(new IntegerConfigAttribute(ATTR_PWPOLICY_LOCKOUT_FAILURE_COUNT, |
| | | getMessage(msgID), false, false, |
| | | false, true, 0, true, |
| | | Integer.MAX_VALUE, |
| | | policy.getLockoutFailureCount())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_LOCKOUT_DURATION; |
| | | attrList.add(new IntegerWithUnitConfigAttribute( |
| | | ATTR_PWPOLICY_LOCKOUT_DURATION, getMessage(msgID), |
| | | false, timeUnits, true, 0, true, Integer.MAX_VALUE, |
| | | policy.getLockoutDuration(), TIME_UNIT_SECONDS_FULL)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_FAILURE_EXPIRATION; |
| | | attrList.add(new IntegerWithUnitConfigAttribute( |
| | | ATTR_PWPOLICY_LOCKOUT_FAILURE_EXPIRATION_INTERVAL, |
| | | getMessage(msgID), false, timeUnits, true, 0, true, |
| | | Integer.MAX_VALUE, |
| | | policy.getLockoutFailureExpirationInterval(), |
| | | TIME_UNIT_SECONDS_FULL)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_REQUIRE_CHANGE_BY_TIME; |
| | | String timeStr = null; |
| | | if (policy.getRequireChangeByTime() > 0) |
| | | { |
| | | timeStr = GeneralizedTimeSyntax.createGeneralizedTimeValue( |
| | | policy.getRequireChangeByTime()).getStringValue(); |
| | | } |
| | | attrList.add(new StringConfigAttribute(ATTR_PWPOLICY_REQUIRE_CHANGE_BY_TIME, |
| | | getMessage(msgID), false, false, |
| | | false, timeStr)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_LAST_LOGIN_TIME_ATTR; |
| | | String loginTimeAttr = (policy.getLastLoginTimeAttribute() == null) |
| | | ? null |
| | | : policy.getLastLoginTimeAttribute().getNameOrOID(); |
| | | attrList.add(new StringConfigAttribute( |
| | | ATTR_PWPOLICY_LAST_LOGIN_TIME_ATTRIBUTE, |
| | | getMessage(msgID), false, false, false, |
| | | loginTimeAttr)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_LAST_LOGIN_TIME_FORMAT; |
| | | attrList.add(new StringConfigAttribute(ATTR_PWPOLICY_LAST_LOGIN_TIME_FORMAT, |
| | | getMessage(msgID), false, false, |
| | | false, |
| | | policy.getLastLoginTimeFormat())); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_PREVIOUS_LAST_LOGIN_TIME_FORMAT; |
| | | ArrayList<String> previousFormats = new ArrayList<String>(); |
| | | previousFormats.addAll(policy.getPreviousLastLoginTimeFormats()); |
| | | attrList.add(new StringConfigAttribute( |
| | | ATTR_PWPOLICY_PREVIOUS_LAST_LOGIN_TIME_FORMAT, |
| | | getMessage(msgID), false, false, false, |
| | | previousFormats)); |
| | | |
| | | |
| | | msgID = MSGID_PWPOLICY_DESCRIPTION_IDLE_LOCKOUT_INTERVAL; |
| | | attrList.add(new IntegerWithUnitConfigAttribute( |
| | | ATTR_PWPOLICY_IDLE_LOCKOUT_INTERVAL, |
| | | getMessage(msgID), false, timeUnits, true, 0, true, |
| | | Integer.MAX_VALUE, policy.getIdleLockoutInterval(), |
| | | TIME_UNIT_SECONDS_FULL)); |
| | | |
| | | return attrList; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether the provided configuration entry has an acceptable |
| | | * configuration for this component. If it does not, then detailed |
| | | * information about the problem(s) should be added to the provided list. |
| | | * |
| | | * @param configEntry The configuration entry for which to make the |
| | | * determination. |
| | | * @param unacceptableReasons A list that can be used to hold messages about |
| | | * why the provided entry does not have an |
| | | * acceptable configuration. |
| | | * |
| | | * @return <CODE>true</CODE> if the provided entry has an acceptable |
| | | * configuration for this component, or <CODE>false</CODE> if not. |
| | | */ |
| | | public boolean hasAcceptableConfiguration(ConfigEntry configEntry, |
| | | List<String> unacceptableReasons) |
| | | { |
| | | assert configEntry.getDN().equals(this.currentPolicy.getConfigEntryDN() ) |
| | | assert configuration.dn().equals(this.currentPolicy.getConfigEntryDN() ) |
| | | : "Internal Error: mismatch between DN of configuration entry and" |
| | | + "DN of current password policy." ; |
| | | |
| | | try |
| | | { |
| | | new PasswordPolicy(configEntry); |
| | | new PasswordPolicy(configuration); |
| | | } |
| | | catch (ConfigException ce) |
| | | { |
| | |
| | | |
| | | |
| | | /** |
| | | * Makes a best-effort attempt to apply the configuration contained in the |
| | | * provided entry. Information about the result of this processing should be |
| | | * added to the provided message list. Information should always be added to |
| | | * this list if a configuration change could not be applied. If detailed |
| | | * results are requested, then information about the changes applied |
| | | * successfully (and optionally about parameters that were not changed) should |
| | | * also be included. |
| | | * |
| | | * @param configEntry The entry containing the new configuration to |
| | | * apply for this component. |
| | | * @param detailedResults Indicates whether detailed information about the |
| | | * processing should be added to the list. |
| | | * |
| | | * @return Information about the result of the configuration update. |
| | | * {@inheritDoc} |
| | | */ |
| | | public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry, |
| | | boolean detailedResults) |
| | | public ConfigChangeResult applyConfigurationChange( |
| | | PasswordPolicyCfg configuration) |
| | | { |
| | | assert configEntry.getDN().equals(this.currentPolicy.getConfigEntryDN() ) |
| | | assert configuration.dn().equals(this.currentPolicy.getConfigEntryDN() ) |
| | | : "Internal Error: mismatch between DN of configuration entry and" |
| | | + "DN of current password policy." ; |
| | | |
| | |
| | | |
| | | try |
| | | { |
| | | p = new PasswordPolicy(configEntry); |
| | | p = new PasswordPolicy(configuration); |
| | | } |
| | | catch (ConfigException ce) |
| | | { |
| | |
| | | // If we've made it here, then everything is acceptable. Apply the new |
| | | // configuration. |
| | | ArrayList<String> messages = new ArrayList<String>(); |
| | | if (detailedResults) |
| | | { |
| | | int msgID = MSGID_PWPOLICY_UPDATED_POLICY; |
| | | messages.add(getMessage(msgID, String.valueOf(p.getConfigEntryDN()))); |
| | | } |
| | | int msgID = MSGID_PWPOLICY_UPDATED_POLICY; |
| | | messages.add(getMessage(msgID, String.valueOf(p.getConfigEntryDN()))); |
| | | |
| | | this.currentPolicy = p; |
| | | |
| | |
| | | /*adminActionRequired*/ false, messages); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Retrieves the PasswordPolicy object representing the configuration entry |
| | | * managed by this object. |