opends/resource/config/config.ldif
@@ -55,6 +55,26 @@ objectClass: ds-cfg-branch cn: Account Status Notification Handlers dn: cn=Error Log Handler,cn=Account Status Notification Handlers,cn=config objectClass: top objectClass: ds-cfg-account-status-notification-handler objectClass: ds-cfg-error-log-account-status-notification-handler cn: Error Log Handler ds-cfg-account-status-notification-handler-class: org.opends.server.extensions.ErrorLogAccountStatusNotificationHandler ds-cfg-account-status-notification-handler-enabled: true ds-cfg-account-status-notification-type: account-temporarily-locked ds-cfg-account-status-notification-type: account-permanently-locked ds-cfg-account-status-notification-type: account-unlocked ds-cfg-account-status-notification-type: account-idle-locked ds-cfg-account-status-notification-type: account-reset-locked ds-cfg-account-status-notification-type: account-disabled ds-cfg-account-status-notification-type: account-enabled ds-cfg-account-status-notification-type: account-expired ds-cfg-account-status-notification-type: password-expired ds-cfg-account-status-notification-type: password-expiring ds-cfg-account-status-notification-type: password-reset ds-cfg-account-status-notification-type: password-changed dn: cn=Alert Handlers,cn=config objectClass: top objectClass: ds-cfg-branch opends/resource/schema/02-config.ldif
@@ -967,6 +967,9 @@ NAME 'ds-cfg-account-status-notification-handler-enabled' 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.283 NAME 'ds-cfg-account-status-notification-type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.1 NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled ) @@ -1322,7 +1325,13 @@ X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.75 NAME 'ds-cfg-account-status-notification-handler' SUP top STRUCTURAL MUST ( ds-cfg-account-status-notification-handler-class $ MUST ( cn $ ds-cfg-account-status-notification-handler-class $ ds-cfg-account-status-notification-handler-enabled ) X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.76 NAME 'ds-cfg-error-log-account-status-notification-handler' SUP ds-cfg-account-status-notification-handler STRUCTURAL MUST ds-cfg-account-status-notification-type X-ORIGIN 'OpenDS Directory Server' ) opends/src/server/org/opends/server/api/AccountStatusNotificationHandler.java
@@ -33,6 +33,7 @@ import org.opends.server.core.InitializationException; import org.opends.server.types.AccountStatusNotification; import org.opends.server.types.AccountStatusNotificationType; import org.opends.server.types.DN; import static org.opends.server.loggers.Debug.*; @@ -99,6 +100,8 @@ * * @param notificationType The type for this account status * notification. * @param userDN The DN of the user entry to which this * notification applies. * @param messageID The unique ID for this notification. * @param message The human-readable message for this * notification. @@ -106,7 +109,7 @@ public abstract void handleStatusNotification( AccountStatusNotificationType notificationType, int messageID, String message); DN userDN, int messageID, String message); @@ -124,6 +127,7 @@ String.valueOf(notification)); handleStatusNotification(notification.getNotificationType(), notification.getUserDN(), notification.getMessageID(), notification.getMessage()); } opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -124,6 +124,15 @@ /** * The name of the configuration attribute that specifies the set of account * status notification types that should trigger notifications. */ public static final String ATTR_ACCT_NOTIFICATION_TYPE = NAME_PREFIX_CFG + "account-status-notification-type"; /** * The name of the configuration attribute that indicates whether to * automatically add missing RDN attributes or to return an error response to * the client. opends/src/server/org/opends/server/core/BindOperation.java
@@ -46,6 +46,7 @@ import org.opends.server.controls.PasswordPolicyResponseControl; import org.opends.server.controls.PasswordPolicyWarningType; import org.opends.server.protocols.asn1.ASN1OctetString; import org.opends.server.types.AccountStatusNotificationType; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; @@ -128,6 +129,9 @@ // The bind DN used for this bind operation. private DN bindDN; // The DN of the user entry that is attempting to authenticate. private DN userEntryDN; // The DN of the user as whom a SASL authentication was attempted (regardless // of whether the authentication was successful) for the purpose of updating // password policy state information. @@ -205,6 +209,7 @@ this.saslCredentials = null; bindDN = null; userEntryDN = null; responseControls = new ArrayList<Control>(0); authFailureID = 0; authFailureReason = null; @@ -261,6 +266,7 @@ this.simplePassword = null; bindDN = null; userEntryDN = null; responseControls = new ArrayList<Control>(0); authFailureID = 0; authFailureReason = null; @@ -324,6 +330,7 @@ pwPolicyErrorType = null; pwPolicyWarningType = null; pwPolicyWarningValue = -1; userEntryDN = null; } @@ -379,6 +386,7 @@ authFailureID = 0; authFailureReason = null; saslAuthUserEntry = null; userEntryDN = null; } @@ -701,6 +709,24 @@ /** * Retrieves the user entry DN for this bind operation. It will only be * available if the bind processing has proceeded far enough to identify the * user attempting to authenticate or if the user DN could not be determined. * * @return The user entry DN for this bind operation, or <CODE>null</CODE> if * the bind processing has not progressed far enough to identify the * user or if the user DN could not be determined. */ public DN getUserEntryDN() { assert debugEnter(CLASS_NAME, "getUserEntryDN"); return userEntryDN; } /** * Retrieves the time that processing started for this operation. * * @return The time that processing started for this operation. @@ -1122,6 +1148,10 @@ setAuthFailureReason(msgID, message); break bindProcessing; } else { userEntryDN = userEntry.getDN(); } // Check to see if the user has a password. If not, then fail. @@ -1172,6 +1202,11 @@ setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(msgID, message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.ACCOUNT_EXPIRED, bindDN, msgID, message); break bindProcessing; } else if (pwPolicyState.lockedDueToFailures()) @@ -1200,6 +1235,11 @@ setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(msgID, message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.ACCOUNT_RESET_LOCKED, bindDN, msgID, message); break bindProcessing; } else if (pwPolicyState.lockedDueToIdleInterval()) @@ -1214,6 +1254,11 @@ setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(msgID, message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.ACCOUNT_IDLE_LOCKED, bindDN, msgID, message); break bindProcessing; } @@ -1252,6 +1297,11 @@ setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(msgID, message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRED, bindDN, msgID, message); break bindProcessing; } } @@ -1262,17 +1312,28 @@ setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(msgID, message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRED, bindDN, msgID, message); break bindProcessing; } } else if (pwPolicyState.shouldWarn()) { int numSeconds = pwPolicyState.getSecondsUntilExpiration(); String timeToExpiration = secondsToTimeString(numSeconds); int msgID = MSGID_BIND_PASSWORD_EXPIRING; String message = getMessage(msgID, timeToExpiration); appendErrorMessage(message); if (pwPolicyWarningType == null) { pwPolicyWarningType = PasswordPolicyWarningType.TIME_BEFORE_EXPIRATION; pwPolicyWarningValue = pwPolicyState.getSecondsUntilExpiration(); pwPolicyWarningValue = numSeconds; } isFirstWarning = pwPolicyState.isFirstWarning(); @@ -1418,6 +1479,16 @@ if (isFirstWarning) { pwPolicyState.setWarnedTime(); int numSeconds = pwPolicyState.getSecondsUntilExpiration(); String timeToExpiration = secondsToTimeString(numSeconds); int msgID = MSGID_BIND_PASSWORD_EXPIRING; String message = getMessage(msgID, timeToExpiration); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRING, bindDN, msgID, message); } if (isGraceLogin) @@ -1439,10 +1510,32 @@ if (maxAllowedFailures > 0) { pwPolicyState.updateAuthFailureTimes(); if (pwPolicyState.getAuthFailureTimes().size() > if (pwPolicyState.getAuthFailureTimes().size() >= maxAllowedFailures) { pwPolicyState.lockDueToFailures(); AccountStatusNotificationType notificationType; int lockoutDuration = pwPolicyState.getLockoutDuration(); if (lockoutDuration > 0) { notificationType = AccountStatusNotificationType. ACCOUNT_TEMPORARILY_LOCKED; msgID = MSGID_BIND_ACCOUNT_TEMPORARILY_LOCKED; message = getMessage(msgID, secondsToTimeString(lockoutDuration)); } else { notificationType = AccountStatusNotificationType. ACCOUNT_PERMANENTLY_LOCKED; msgID = MSGID_BIND_ACCOUNT_PERMANENTLY_LOCKED; message = getMessage(msgID); } pwPolicyState.generateAccountStatusNotification( notificationType, userEntryDN, msgID, message); } } } @@ -1532,7 +1625,8 @@ // FIXME -- Need to have a way to enable debugging. pwPolicyState = new PasswordPolicyState(saslAuthUserEntry, false, false); userDNString = String.valueOf(saslAuthUserEntry.getDN()); userEntryDN = saslAuthUserEntry.getDN(); userDNString = String.valueOf(userEntryDN); } catch (DirectoryException de) { @@ -1561,7 +1655,13 @@ setResultCode(ResultCode.INVALID_CREDENTIALS); int msgID = MSGID_BIND_OPERATION_ACCOUNT_EXPIRED; appendErrorMessage(getMessage(msgID, userDNString)); String message = getMessage(msgID, userDNString); appendErrorMessage(message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.ACCOUNT_EXPIRED, bindDN, msgID, message); break bindProcessing; } @@ -1601,7 +1701,13 @@ } int msgID = MSGID_BIND_OPERATION_ACCOUNT_IDLE_LOCKED; appendErrorMessage(getMessage(msgID, userDNString)); String message = getMessage(msgID, userDNString); appendErrorMessage(message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.ACCOUNT_IDLE_LOCKED, bindDN, msgID, message); break bindProcessing; } @@ -1618,7 +1724,13 @@ } int msgID = MSGID_BIND_OPERATION_ACCOUNT_RESET_LOCKED; appendErrorMessage(getMessage(msgID, userDNString)); String message = getMessage(msgID, userDNString); appendErrorMessage(message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.ACCOUNT_RESET_LOCKED, bindDN, msgID, message); break bindProcessing; } @@ -1655,6 +1767,11 @@ setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(msgID, message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRED, bindDN, msgID, message); break bindProcessing; } } @@ -1665,17 +1782,28 @@ setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(msgID, message); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRED, bindDN, msgID, message); break bindProcessing; } } else if (pwPolicyState.shouldWarn()) { int numSeconds = pwPolicyState.getSecondsUntilExpiration(); String timeToExpiration = secondsToTimeString(numSeconds); int msgID = MSGID_BIND_PASSWORD_EXPIRING; String message = getMessage(msgID, timeToExpiration); appendErrorMessage(message); if (pwPolicyWarningType == null) { pwPolicyWarningType = PasswordPolicyWarningType.TIME_BEFORE_EXPIRATION; pwPolicyWarningValue = pwPolicyState.getSecondsUntilExpiration(); pwPolicyWarningValue = numSeconds; } isFirstWarning = pwPolicyState.isFirstWarning(); @@ -1701,6 +1829,16 @@ if (isFirstWarning) { pwPolicyState.setWarnedTime(); int numSeconds = pwPolicyState.getSecondsUntilExpiration(); String timeToExpiration = secondsToTimeString(numSeconds); int msgID = MSGID_BIND_PASSWORD_EXPIRING; String message = getMessage(msgID, timeToExpiration); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRING, bindDN, msgID, message); } if (isGraceLogin) @@ -1809,10 +1947,34 @@ if (maxAllowedFailures > 0) { pwPolicyState.updateAuthFailureTimes(); if (pwPolicyState.getAuthFailureTimes().size() > if (pwPolicyState.getAuthFailureTimes().size() >= maxAllowedFailures) { pwPolicyState.lockDueToFailures(); AccountStatusNotificationType notificationType; int msgID; String message; int lockoutDuration = pwPolicyState.getLockoutDuration(); if (lockoutDuration > 0) { notificationType = AccountStatusNotificationType. ACCOUNT_TEMPORARILY_LOCKED; msgID = MSGID_BIND_ACCOUNT_TEMPORARILY_LOCKED; message = getMessage(msgID, secondsToTimeString(lockoutDuration)); } else { notificationType = AccountStatusNotificationType. ACCOUNT_PERMANENTLY_LOCKED; msgID = MSGID_BIND_ACCOUNT_PERMANENTLY_LOCKED; message = getMessage(msgID); } pwPolicyState.generateAccountStatusNotification( notificationType, userEntryDN, msgID, message); } } } opends/src/server/org/opends/server/core/PasswordPolicyState.java
@@ -1770,6 +1770,23 @@ /** * Retrieves the length of time in seconds that a user's account will be * locked due to failed attempts before it will be automatically unlocked. * * @return The length of time in seconds that a user's account will be * locked due to failed attempts before it will be automatically * unlocked, or zero if accounts will not be automatically unlocked. */ public int getLockoutDuration() { assert debugEnter(CLASS_NAME, "getLockoutDuration"); return passwordPolicy.getLockoutDuration(); } /** * Retrieves the length of time in seconds until the user's account is * automatically unlocked. This should only be called after calling * <CODE>lockedDueToFailures</CODE>. @@ -4122,15 +4139,17 @@ * Generates an account status notification for this user. * * @param notificationType The type for the account status notification. * @param userDN The DN of the user entry to which this * notification applies. * @param messageID The unique ID for the notification. * @param message The human-readable message for the notification. */ public void generateAccountStatusNotification( AccountStatusNotificationType notificationType, int messageID, String message) DN userDN, int messageID, String message) { assert debugEnter(CLASS_NAME, "generateAccountStatusNotification", String.valueOf(notificationType), String.valueOf(notificationType), String.valueOf(userDN), String.valueOf(messageID), String.valueOf(message)); @@ -4143,7 +4162,8 @@ for (AccountStatusNotificationHandler handler : handlers) { handler.handleStatusNotification(notificationType, messageID, message); handler.handleStatusNotification(notificationType, userDN, messageID, message); } } opends/src/server/org/opends/server/extensions/ErrorLogAccountStatusNotificationHandler.java
New file @@ -0,0 +1,414 @@ /* * 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 Sun Microsystems, Inc. */ package org.opends.server.extensions; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import org.opends.server.api.AccountStatusNotificationHandler; import org.opends.server.api.ConfigurableComponent; import org.opends.server.config.ConfigAttribute; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.config.MultiChoiceConfigAttribute; import org.opends.server.core.DirectoryServer; import org.opends.server.core.InitializationException; import org.opends.server.types.AccountStatusNotificationType; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.DN; import org.opends.server.types.ErrorLogCategory; import org.opends.server.types.ErrorLogSeverity; import org.opends.server.types.ResultCode; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.Debug.*; import static org.opends.server.loggers.Error.*; import static org.opends.server.messages.ExtensionsMessages.*; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.util.StaticUtils.*; /** * This class defines an account status notification handler that will write * information about status notifications using the Directory Server's error * logging facility. */ public class ErrorLogAccountStatusNotificationHandler extends AccountStatusNotificationHandler implements ConfigurableComponent { /** * The fully-qualified name of this class for debugging purposes. */ private static final String CLASS_NAME = "org.opends.server.extensions.ErrorLogAccountStatusNotificationHandler"; /** * The set of names for the account status notification types that may be * logged by this notification handler. */ private static final HashSet<String> NOTIFICATION_TYPE_NAMES = new HashSet<String>(); // The DN of the configuration entry for this notification handler. private DN configEntryDN; // The set of notification types that should generate log messages. private HashSet<AccountStatusNotificationType> notificationTypes; static { for (AccountStatusNotificationType t : AccountStatusNotificationType.values()) { NOTIFICATION_TYPE_NAMES.add(t.getNotificationTypeName()); } } /** * Initializes this account status notification handler based on the * information in the provided configuration entry. * * @param configEntry The configuration entry that contains the information * to use to initialize this account status notification * handler. * * @throws ConfigException If the provided entry does not contain a valid * configuration for this account status * notification handler. * * @throws InitializationException If a problem occurs during initialization * that is not related to the server * configuration. */ public void initializeStatusNotificationHandler(ConfigEntry configEntry) throws ConfigException, InitializationException { assert debugEnter(CLASS_NAME, "initializeStatusNotificationHandler", String.valueOf(configEntry)); configEntryDN = configEntry.getDN(); // Initialize the set of notification types that should generate log // messages. int msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_DESCRIPTION_NOTIFICATION_TYPES; MultiChoiceConfigAttribute typesStub = new MultiChoiceConfigAttribute(ATTR_ACCT_NOTIFICATION_TYPE, getMessage(msgID), true, true, false, NOTIFICATION_TYPE_NAMES); try { MultiChoiceConfigAttribute typesAttr = (MultiChoiceConfigAttribute) configEntry.getConfigAttribute(typesStub); notificationTypes = new HashSet<AccountStatusNotificationType>(); for (String s : typesAttr.activeValues()) { AccountStatusNotificationType t = AccountStatusNotificationType.typeForName(s); if (t == null) { msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_INVALID_TYPE; String message = getMessage(msgID, String.valueOf(configEntryDN), s); throw new ConfigException(msgID, message); } else { notificationTypes.add(t); } } } catch (Exception e) { assert debugException(CLASS_NAME, "initializeStatusNotificationHandler", e); msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_CANNOT_GET_NOTIFICATION_TYPES; String message = getMessage(msgID, String.valueOf(configEntryDN), stackTraceToSingleLineString(e)); throw new InitializationException(msgID, message, e); } DirectoryServer.registerConfigurableComponent(this); DirectoryServer.registerAccountStatusNotificationHandler(configEntryDN, this); } /** * Performs any processing that may be necessary in conjunction with the * provided account status notification type. * * @param notificationType The type for this account status notification. * @param userDN The DN of the user entry to which this * notification applies. * @param messageID The unique ID for this notification. * @param message The human-readable message for this notification. */ public void handleStatusNotification(AccountStatusNotificationType notificationType, DN userDN, int messageID, String message) { assert debugEnter(CLASS_NAME, "handleStatusNotification", String.valueOf(notificationType), String.valueOf(userDN), String.valueOf(messageID), String.valueOf(message)); if (notificationTypes.contains(notificationType)) { int msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_NOTIFICATION; logError(ErrorLogCategory.PASSWORD_POLICY, ErrorLogSeverity.NOTICE, msgID, notificationType.getNotificationTypeName(), String.valueOf(userDN), messageID, message); } } /** * 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() { assert debugEnter(CLASS_NAME, "getConfigurableComponentEntryDN"); return configEntryDN; } /** * 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() { assert debugEnter(CLASS_NAME, "getConfigurationAttributes"); LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>(); LinkedList<String> typeNames = new LinkedList<String>(); for (AccountStatusNotificationType t : notificationTypes) { typeNames.add(t.getNotificationTypeName()); } int msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_DESCRIPTION_NOTIFICATION_TYPES; attrList.add(new MultiChoiceConfigAttribute(ATTR_ACCT_NOTIFICATION_TYPE, getMessage(msgID), true, true, false, NOTIFICATION_TYPE_NAMES, typeNames)); 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 debugEnter(CLASS_NAME, "hasAcceptableConfiguration", String.valueOf(configEntry), "List<String>"); // Initialize the set of notification types that should generate log // messages. int msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_DESCRIPTION_NOTIFICATION_TYPES; MultiChoiceConfigAttribute typesStub = new MultiChoiceConfigAttribute(ATTR_ACCT_NOTIFICATION_TYPE, getMessage(msgID), true, true, false, NOTIFICATION_TYPE_NAMES); try { MultiChoiceConfigAttribute typesAttr = (MultiChoiceConfigAttribute) configEntry.getConfigAttribute(typesStub); HashSet<AccountStatusNotificationType> types = new HashSet<AccountStatusNotificationType>(); for (String s : typesAttr.activeValues()) { AccountStatusNotificationType t = AccountStatusNotificationType.typeForName(s); if (t == null) { msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_INVALID_TYPE; String message = getMessage(msgID, String.valueOf(configEntryDN), s); unacceptableReasons.add(message); return false; } else { types.add(t); } } } catch (Exception e) { assert debugException(CLASS_NAME, "hasAcceptableConfiguration", e); msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_CANNOT_GET_NOTIFICATION_TYPES; String message = getMessage(msgID, String.valueOf(configEntryDN), stackTraceToSingleLineString(e)); unacceptableReasons.add(message); return false; } // If we've gotten here, then everything is OK. return true; } /** * 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. */ public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry, boolean detailedResults) { assert debugEnter(CLASS_NAME, "applyNewConfiguration", String.valueOf(configEntry), String.valueOf(detailedResults)); ResultCode resultCode = ResultCode.SUCCESS; boolean adminActionRequired = false; ArrayList<String> messages = new ArrayList<String>(); // Initialize the set of notification types that should generate log // messages. HashSet<AccountStatusNotificationType> types = new HashSet<AccountStatusNotificationType>(); int msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_DESCRIPTION_NOTIFICATION_TYPES; MultiChoiceConfigAttribute typesStub = new MultiChoiceConfigAttribute(ATTR_ACCT_NOTIFICATION_TYPE, getMessage(msgID), true, true, false, NOTIFICATION_TYPE_NAMES); try { MultiChoiceConfigAttribute typesAttr = (MultiChoiceConfigAttribute) configEntry.getConfigAttribute(typesStub); for (String s : typesAttr.activeValues()) { AccountStatusNotificationType t = AccountStatusNotificationType.typeForName(s); if (t == null) { resultCode = ResultCode.UNWILLING_TO_PERFORM; msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_INVALID_TYPE; messages.add(getMessage(msgID, String.valueOf(configEntryDN), s)); } else { types.add(t); } } } catch (Exception e) { assert debugException(CLASS_NAME, "hasAcceptableConfiguration", e); resultCode = DirectoryServer.getServerErrorResultCode(); msgID = MSGID_ERRORLOG_ACCTNOTHANDLER_CANNOT_GET_NOTIFICATION_TYPES; messages.add(getMessage(msgID, String.valueOf(configEntryDN), stackTraceToSingleLineString(e))); } if (resultCode == ResultCode.SUCCESS) { this.notificationTypes = types; } return new ConfigChangeResult(resultCode, adminActionRequired, messages); } } opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -5725,6 +5725,37 @@ /** * The message ID for the message that will be used if the user's password is * about to expire. This takes a single argument, which is the length of time * until the password expires. */ public static final int MSGID_BIND_PASSWORD_EXPIRING = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_WARNING | 547; /** * The message ID for the message that will be used if the user's account * becomes temporarily locked due to too many failed attempts. This takes a * single argument, which is a string representation of the length of time * until the account is unlocked. */ public static final int MSGID_BIND_ACCOUNT_TEMPORARILY_LOCKED = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 548; /** * The message ID for the message that will be used if the user's account * becomes permanently locked due to too many failed attempts. This does not * take any arguments. */ public static final int MSGID_BIND_ACCOUNT_PERMANENTLY_LOCKED = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 549; /** * Associates a set of generic messages with the message IDs defined * in this class. */ @@ -6513,9 +6544,19 @@ "The user-specific time limit value %s contained in " + "user entry %s could not be parsed as an integer. The " + "default server time limit will be used."); registerMessage(MSGID_BIND_PASSWORD_EXPIRING, "The user password is about to expire (time to " + "expiration: %s)."); registerMessage(MSGID_BIND_OPERATION_WRONG_PASSWORD, "The password provided by the user did not match any " + "password(s) stored in the user's entry."); registerMessage(MSGID_BIND_ACCOUNT_TEMPORARILY_LOCKED, "The account has been locked as a result of too many " + "failed authentication attempts (time to unlock: %s)."); registerMessage(MSGID_BIND_ACCOUNT_PERMANENTLY_LOCKED, "The account has been locked as a result of too many " + "failed authentication attempts. It may only be " + "unlocked by an administrator."); registerMessage(MSGID_BIND_OPERATION_PASSWORD_VALIDATION_EXCEPTION, "An unexpected error occurred while attempting to " + "validate the provided password: %s."); opends/src/server/org/opends/server/messages/ExtensionsMessages.java
@@ -3928,6 +3928,50 @@ /** * The message ID for the message that will be used as the description for the * notification types configuration attribute. This does not take any * arguments. */ public static final int MSGID_ERRORLOG_ACCTNOTHANDLER_DESCRIPTION_NOTIFICATION_TYPES = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_INFORMATIONAL | 372; /** * The message ID for the message that will be used if an invalid notification * type is specified. This takes two arguments, which are the DN of the * configuration entry and the invalid notification type. */ public static final int MSGID_ERRORLOG_ACCTNOTHANDLER_INVALID_TYPE = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 373; /** * The message ID for the message that will be used if an error occurs while * attempting to determine the account status notification types. This takes * two arguments, which are the DN of the configuration entry and a string * representation of the exception that occurred. */ public static final int MSGID_ERRORLOG_ACCTNOTHANDLER_CANNOT_GET_NOTIFICATION_TYPES = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 374; /** * The message ID for the message that will be written to the error log * whenever an account status notification is generated. This takes four * arguments, which are the name of the account status notification type, the * user DN, the message ID, and the message string. */ public static final int MSGID_ERRORLOG_ACCTNOTHANDLER_NOTIFICATION = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_NOTICE | 375; /** * Associates a set of generic messages with the message IDs defined in this * class. */ @@ -5729,6 +5773,23 @@ "value for configuration attribute " + ATTR_PASSWORD_FORMAT + ", which is used to specify the " + "format for the generated passwords: %s."); registerMessage( MSGID_ERRORLOG_ACCTNOTHANDLER_DESCRIPTION_NOTIFICATION_TYPES, "Specifies the status notification types for which log messages " + "should be generated. It is a multivalued attribute, and changes " + "will take effect immediately."); registerMessage(MSGID_ERRORLOG_ACCTNOTHANDLER_INVALID_TYPE, "Configuration entry %s contains unrecognized account " + "status notification type %s."); registerMessage(MSGID_ERRORLOG_ACCTNOTHANDLER_CANNOT_GET_NOTIFICATION_TYPES, "An error occurred while attempting to determine " + "the account status notification types from " + "configuration entry %s: %s."); registerMessage(MSGID_ERRORLOG_ACCTNOTHANDLER_NOTIFICATION, "Account-Status-Notification type='%s' userdn='%s' " + "id=%d msg='%s'"); } } opends/src/server/org/opends/server/messages/UtilityMessages.java
@@ -2004,7 +2004,7 @@ registerMessage(MSGID_ACCTNOTTYPE_PASSWORD_EXPIRING, "password-expiring"); registerMessage(MSGID_ACCTNOTTYPE_PASSWORD_RESET, "password-reset-by-administrator"); "password-reset"); registerMessage(MSGID_ACCTNOTTYPE_PASSWORD_CHANGED, "password-changed"); } opends/src/server/org/opends/server/tools/LDAPConnection.java
@@ -47,7 +47,8 @@ import static org.opends.server.loggers.Debug.*; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.messages.CoreMessages.*; import static org.opends.server.messages.CoreMessages. MSGID_RESULT_CLIENT_SIDE_CONNECT_ERROR; import static org.opends.server.messages.ToolMessages.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; opends/src/server/org/opends/server/types/AccountStatusNotification.java
@@ -49,6 +49,9 @@ // The notification type for this account status notification. private AccountStatusNotificationType notificationType; // The DN of the user entry to which this notification applies. private DN userDN; // The message ID for the account status notification message. private int messageID; @@ -64,19 +67,22 @@ * * @param notificationType The type for this account status * notification. * @param userDN The DN of the user entry to which * this notification applies. * @param messageID The unique ID for this notification. * @param message The human-readable message for this * notification. */ public AccountStatusNotification( AccountStatusNotificationType notificationType, int messageID, String message) DN userDN, int messageID, String message) { assert debugEnter(CLASS_NAME, String.valueOf(notificationType), String.valueOf(messageID), String.valueOf(message)); this.notificationType = notificationType; this.userDN = userDN; this.messageID = messageID; this.message = message; } @@ -100,6 +106,22 @@ /** * Retrieves the DN of the user entry to which this notification * applies. * * @return The DN of the user entry to which this notification * applies. */ public DN getUserDN() { assert debugEnter(CLASS_NAME, "getUserDN"); return userDN; } /** * Retrieves the message ID for the account status notification * message. * @@ -143,8 +165,8 @@ assert debugEnter(CLASS_NAME, "toString"); return "AccountStatusNotification(type=" + String.valueOf(notificationType) + ",id=" + messageID + ",message=" + message + ")"; notificationType.getNotificationTypeName() + ",dn=" + userDN + ",id=" + messageID + ",message=" + message + ")"; } } opends/src/server/org/opends/server/types/AccountStatusNotificationType.java
@@ -215,6 +215,89 @@ /** * Retrieves the account status notification type with the specified * name. * * @param name The name for the account status notification type * to retrieve. * * @return The requested account status notification type, or * <CODE>null</CODE> if there is no type with the given * name. */ public static AccountStatusNotificationType typeForName(String name) { String lowerName = toLowerCase(name); if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_ACCOUNT_TEMPORARILY_LOCKED))) { return ACCOUNT_TEMPORARILY_LOCKED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_ACCOUNT_PERMANENTLY_LOCKED))) { return ACCOUNT_PERMANENTLY_LOCKED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_ACCOUNT_UNLOCKED))) { return ACCOUNT_UNLOCKED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_ACCOUNT_IDLE_LOCKED))) { return ACCOUNT_IDLE_LOCKED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_ACCOUNT_RESET_LOCKED))) { return ACCOUNT_RESET_LOCKED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_ACCOUNT_DISABLED))) { return ACCOUNT_DISABLED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_ACCOUNT_ENABLED))) { return ACCOUNT_ENABLED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_ACCOUNT_EXPIRED))) { return ACCOUNT_EXPIRED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_PASSWORD_EXPIRED))) { return PASSWORD_EXPIRED; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_PASSWORD_EXPIRING))) { return PASSWORD_EXPIRING; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_PASSWORD_RESET))) { return PASSWORD_RESET; } else if (lowerName.equals(getMessage( MSGID_ACCTNOTTYPE_PASSWORD_CHANGED))) { return PASSWORD_CHANGED; } else { return null; } } /** * Retrieves the notification type identifier for this account * status notification type. * @@ -229,6 +312,18 @@ /** * Retrieves the name for this account status notification type. * * @return The name for this account status notification type. */ public String getNotificationTypeName() { return getMessage(notificationTypeID); } /** * Retrieves a string representation of this account status * notification type. *