Update the extended operation handler API to provide the ability for custom
extended operations to handle their own controls. The password modify extended
operation has been updated to support the LDAP no-op control and the password
policy control.
OpenDS Issue Number: 597
| | |
| | | |
| | | |
| | | |
| | | import java.util.HashSet; |
| | | import java.util.Set; |
| | | |
| | | import org.opends.server.config.ConfigEntry; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.ExtendedOperation; |
| | |
| | | |
| | | |
| | | |
| | | // The default set of supported control OIDs for this extended |
| | | // operation. |
| | | private Set<String> supportedControlOIDs = new HashSet<String>(0); |
| | | |
| | | // The default set of supported feature OIDs for this extended |
| | | // operation. |
| | | private Set<String> supportedFeatureOIDs = new HashSet<String>(0); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Initializes this extended operation handler based on the |
| | | * information in the provided configuration entry. It should also |
| | |
| | | */ |
| | | public abstract void processExtendedOperation(ExtendedOperation |
| | | operation); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the OIDs of the controls that may be supported by this |
| | | * extended operation handler. It should be overridden by any |
| | | * extended operation handler which provides special support for one |
| | | * or more controls. |
| | | * |
| | | * @return The OIDs of the controls that may be supported by this |
| | | * extended operation handler. |
| | | */ |
| | | public Set<String> getSupportedControls() |
| | | { |
| | | assert debugEnter(CLASS_NAME, "getSupportedControls"); |
| | | |
| | | return supportedControlOIDs; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether this extended operation handler supports the |
| | | * specified control. |
| | | * |
| | | * @param controlOID The OID of the control for which to make the |
| | | * determination. |
| | | * |
| | | * @return {@code true} if this extended operation handler does |
| | | * support the requested control, or {@code false} if not. |
| | | */ |
| | | public final boolean supportsControl(String controlOID) |
| | | { |
| | | assert debugEnter(CLASS_NAME, "supportsControl", |
| | | String.valueOf(controlOID)); |
| | | |
| | | return getSupportedControls().contains(controlOID); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the OIDs of the features that may be supported by this |
| | | * extended operation handler. |
| | | * |
| | | * @return The OIDs of the features that may be supported by this |
| | | * extended operation handler. |
| | | */ |
| | | public Set<String> getSupportedFeatures() |
| | | { |
| | | assert debugEnter(CLASS_NAME, "getSupportedFeatures"); |
| | | |
| | | return supportedFeatureOIDs; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether this extended operation handler supports the |
| | | * specified feature. |
| | | * |
| | | * @param featureOID The OID of the feature for which to make the |
| | | * determination. |
| | | * |
| | | * @return {@code true} if this extended operation handler does |
| | | * support the requested feature, or {@code false} if not. |
| | | */ |
| | | public final boolean supportsFeature(String featureOID) |
| | | { |
| | | assert debugEnter(CLASS_NAME, "supportsFeature", |
| | | String.valueOf(featureOID)); |
| | | |
| | | return getSupportedFeatures().contains(featureOID); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | // Check the set of controls included in the request. If there are any, |
| | | // see if any special processing is required. This should also include |
| | | // taking care of any synchronization that might be needed. |
| | | // NYI |
| | | // Look at the controls included in the request and ensure that all |
| | | // critical controls are supported by the handler. |
| | | List<Control> requestControls = getRequestControls(); |
| | | if ((requestControls != null) && (! requestControls.isEmpty())) |
| | | { |
| | | for (Control c : requestControls) |
| | | { |
| | | if (! c.isCritical()) |
| | | { |
| | | // The control isn't critical, so we don't care if it's supported |
| | | // or not. |
| | | } |
| | | else if (! handler.supportsControl(c.getOID())) |
| | | { |
| | | setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION); |
| | | |
| | | int msgID = MSGID_EXTENDED_UNSUPPORTED_CRITICAL_CONTROL; |
| | | appendErrorMessage(getMessage(msgID, String.valueOf(requestOID), |
| | | c.getOID())); |
| | | |
| | | break extendedProcessing; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Check to see if the client has permission to perform the |
| | |
| | | import java.util.Iterator; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | import org.opends.server.api.ConfigAddListener; |
| | |
| | | } |
| | | |
| | | |
| | | // If the extended operation handler defines any supported controls and/or |
| | | // features, then register them with the server. |
| | | Set<String> controlOIDs = handler.getSupportedControls(); |
| | | if (controlOIDs != null) |
| | | { |
| | | for (String oid : controlOIDs) |
| | | { |
| | | DirectoryServer.registerSupportedControl(oid); |
| | | } |
| | | } |
| | | |
| | | Set<String> featureOIDs = handler.getSupportedFeatures(); |
| | | if (featureOIDs != null) |
| | | { |
| | | for (String oid : featureOIDs) |
| | | { |
| | | DirectoryServer.registerSupportedFeature(oid); |
| | | } |
| | | } |
| | | |
| | | |
| | | handlers.put(configEntryDN, handler); |
| | | return new ConfigChangeResult(resultCode, adminActionRequired, messages); |
| | | } |
| | |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.HashSet; |
| | | import java.util.Set; |
| | | import java.util.concurrent.locks.Lock; |
| | | |
| | | import org.opends.server.api.ClientConnection; |
| | |
| | | import org.opends.server.config.ConfigEntry; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.config.DNConfigAttribute; |
| | | import org.opends.server.controls.PasswordPolicyResponseControl; |
| | | import org.opends.server.controls.PasswordPolicyWarningType; |
| | | import org.opends.server.controls.PasswordPolicyErrorType; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.ExtendedOperation; |
| | | import org.opends.server.core.ModifyOperation; |
| | |
| | | import org.opends.server.types.AuthenticationInfo; |
| | | import org.opends.server.types.ByteString; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.Control; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | |
| | | // The reference to the identity mapper. |
| | | private IdentityMapper identityMapper; |
| | | |
| | | // The set of OIDs for the supported controls. |
| | | private Set<String> supportedControlOIDs; |
| | | |
| | | |
| | | |
| | | /** |
| | |
| | | throw new InitializationException(msgID, message, e); |
| | | } |
| | | |
| | | |
| | | supportedControlOIDs = new HashSet<String>(); |
| | | supportedControlOIDs.add(OID_LDAP_NOOP_OPENLDAP_ASSIGNED); |
| | | supportedControlOIDs.add(OID_PASSWORD_POLICY_CONTROL); |
| | | |
| | | |
| | | DirectoryServer.registerConfigurableComponent(this); |
| | | |
| | | DirectoryServer.registerSupportedExtension(OID_PASSWORD_MODIFY_REQUEST, |
| | |
| | | ByteString newPassword = null; |
| | | |
| | | |
| | | // Look at the set of controls included in the request, if there are any. |
| | | boolean noOpRequested = false; |
| | | boolean pwPolicyRequested = false; |
| | | int pwPolicyWarningValue = 0; |
| | | PasswordPolicyErrorType pwPolicyErrorType = null; |
| | | PasswordPolicyWarningType pwPolicyWarningType = null; |
| | | List<Control> controls = operation.getRequestControls(); |
| | | if (controls != null) |
| | | { |
| | | for (Control c : controls) |
| | | { |
| | | String oid = c.getOID(); |
| | | if (oid.equals(OID_LDAP_NOOP_OPENLDAP_ASSIGNED)) |
| | | { |
| | | noOpRequested = true; |
| | | } |
| | | else if (oid.equals(OID_PASSWORD_POLICY_CONTROL)) |
| | | { |
| | | pwPolicyRequested = true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Parse the encoded request, if there is one. |
| | | ByteString requestValue = operation.getRequestValue(); |
| | | if (requestValue != null) |
| | |
| | | userDN.equals(requestorDN)); |
| | | |
| | | |
| | | // See if the account is locked. If so, then reject the request. |
| | | if (pwPolicyState.isDisabled()) |
| | | { |
| | | if (pwPolicyRequested) |
| | | { |
| | | pwPolicyErrorType = |
| | | PasswordPolicyErrorType.ACCOUNT_LOCKED; |
| | | operation.addResponseControl( |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType)); |
| | | } |
| | | |
| | | int msgID = MSGID_EXTOP_PASSMOD_ACCOUNT_DISABLED; |
| | | String message = getMessage(msgID); |
| | | |
| | | if (oldPassword == null) |
| | | { |
| | | operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); |
| | | operation.appendErrorMessage(message); |
| | | } |
| | | else |
| | | { |
| | | operation.setResultCode(ResultCode.INVALID_CREDENTIALS); |
| | | operation.appendAdditionalLogMessage(message); |
| | | } |
| | | |
| | | return; |
| | | } |
| | | else if (selfChange && |
| | | (pwPolicyState.lockedDueToFailures() || |
| | | pwPolicyState.lockedDueToIdleInterval() || |
| | | pwPolicyState.lockedDueToMaximumResetAge())) |
| | | { |
| | | if (pwPolicyRequested) |
| | | { |
| | | pwPolicyErrorType = |
| | | PasswordPolicyErrorType.ACCOUNT_LOCKED; |
| | | operation.addResponseControl( |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType)); |
| | | } |
| | | |
| | | int msgID = MSGID_EXTOP_PASSMOD_ACCOUNT_LOCKED; |
| | | String message = getMessage(msgID); |
| | | |
| | | if (oldPassword == null) |
| | | { |
| | | operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); |
| | | operation.appendErrorMessage(message); |
| | | } |
| | | else |
| | | { |
| | | operation.setResultCode(ResultCode.INVALID_CREDENTIALS); |
| | | operation.appendAdditionalLogMessage(message); |
| | | } |
| | | |
| | | return; |
| | | } |
| | | |
| | | |
| | | // If the current password was provided, then we'll need to verify whether |
| | | // it was correct. If it wasn't provided but this is a self change, then |
| | | // make sure that's OK. |
| | |
| | | |
| | | int msgID = MSGID_EXTOP_PASSMOD_REQUIRE_CURRENT_PW; |
| | | operation.appendErrorMessage(getMessage(msgID)); |
| | | |
| | | if (pwPolicyRequested) |
| | | { |
| | | pwPolicyErrorType = |
| | | PasswordPolicyErrorType.MUST_SUPPLY_OLD_PASSWORD; |
| | | operation.addResponseControl( |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType)); |
| | | } |
| | | |
| | | return; |
| | | } |
| | | } |
| | |
| | | // the request. |
| | | if (selfChange && (! pwPolicyState.allowUserPasswordChanges())) |
| | | { |
| | | if (pwPolicyRequested) |
| | | { |
| | | pwPolicyErrorType = |
| | | PasswordPolicyErrorType.PASSWORD_MOD_NOT_ALLOWED; |
| | | operation.addResponseControl( |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType)); |
| | | } |
| | | |
| | | if (oldPassword == null) |
| | | { |
| | | operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); |
| | |
| | | // then reject it. |
| | | if (selfChange && pwPolicyState.isWithinMinimumAge()) |
| | | { |
| | | if (pwPolicyRequested) |
| | | { |
| | | pwPolicyErrorType = |
| | | PasswordPolicyErrorType.PASSWORD_TOO_YOUNG; |
| | | operation.addResponseControl( |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType)); |
| | | } |
| | | |
| | | if (oldPassword == null) |
| | | { |
| | | operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); |
| | |
| | | if ((selfChange && pwPolicyState.isPasswordExpired() && |
| | | (! pwPolicyState.allowExpiredPasswordChanges()))) |
| | | { |
| | | if (pwPolicyRequested) |
| | | { |
| | | pwPolicyErrorType = |
| | | PasswordPolicyErrorType.PASSWORD_EXPIRED; |
| | | operation.addResponseControl( |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType)); |
| | | } |
| | | |
| | | if (oldPassword == null) |
| | | { |
| | | operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); |
| | |
| | | clearPasswords, |
| | | invalidReason)) |
| | | { |
| | | if (pwPolicyRequested) |
| | | { |
| | | pwPolicyErrorType = |
| | | PasswordPolicyErrorType.INSUFFICIENT_PASSWORD_QUALITY; |
| | | operation.addResponseControl( |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType)); |
| | | } |
| | | |
| | | if (oldPassword == null) |
| | | { |
| | | operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); |
| | |
| | | modList.addAll(pwPolicyState.getModifications()); |
| | | |
| | | |
| | | // Get an internal connection and use it to perform the modification. |
| | | boolean isRoot = DirectoryServer.isRootDN(requestorDN); |
| | | AuthenticationInfo authInfo = new AuthenticationInfo(requestorDN, isRoot); |
| | | InternalClientConnection internalConnection = new |
| | | InternalClientConnection(authInfo); |
| | | |
| | | ModifyOperation modifyOperation = |
| | | internalConnection.processModify(userDN, modList); |
| | | ResultCode resultCode = modifyOperation.getResultCode(); |
| | | if (resultCode != resultCode.SUCCESS) |
| | | // If the LDAP no-op control was included in the request, then set the |
| | | // appropriate response. Otherwise, process the operation. |
| | | if (noOpRequested) |
| | | { |
| | | operation.setResultCode(resultCode); |
| | | operation.setErrorMessage(modifyOperation.getErrorMessage()); |
| | | operation.setReferralURLs(modifyOperation.getReferralURLs()); |
| | | return; |
| | | operation.appendErrorMessage(getMessage(MSGID_EXTOP_PASSMOD_NOOP)); |
| | | |
| | | // FIXME -- We must set a result code other than SUCCESS. |
| | | operation.setResultCode(ResultCode.SUCCESS); |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then everything is OK, so indicate that the |
| | | // operation was successful. If a password was generated, then include |
| | | // it in the response. |
| | | operation.setResultCode(ResultCode.SUCCESS); |
| | | |
| | | if (generatedPassword) |
| | | else |
| | | { |
| | | ArrayList<ASN1Element> valueElements = new ArrayList<ASN1Element>(1); |
| | | // Get an internal connection and use it to perform the modification. |
| | | boolean isRoot = DirectoryServer.isRootDN(requestorDN); |
| | | AuthenticationInfo authInfo = new AuthenticationInfo(requestorDN, |
| | | isRoot); |
| | | InternalClientConnection internalConnection = new |
| | | InternalClientConnection(authInfo); |
| | | |
| | | ASN1OctetString newPWString = |
| | | new ASN1OctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD, |
| | | newPassword.value()); |
| | | valueElements.add(newPWString); |
| | | |
| | | ASN1Sequence valueSequence = new ASN1Sequence(valueElements); |
| | | operation.setResponseValue(new ASN1OctetString(valueSequence.encode())); |
| | | } |
| | | ModifyOperation modifyOperation = |
| | | internalConnection.processModify(userDN, modList); |
| | | ResultCode resultCode = modifyOperation.getResultCode(); |
| | | if (resultCode != resultCode.SUCCESS) |
| | | { |
| | | operation.setResultCode(resultCode); |
| | | operation.setErrorMessage(modifyOperation.getErrorMessage()); |
| | | operation.setReferralURLs(modifyOperation.getReferralURLs()); |
| | | return; |
| | | } |
| | | |
| | | |
| | | // If this was a self password change, and the client is authenticated as |
| | | // the user whose password was changed, then clear the "must change |
| | | // password" flag in the client connection. Note that we're using the |
| | | // authentication DN rather than the authorization DN in this case to |
| | | // avoid mistakenly clearing the flag for the wrong user. |
| | | if (selfChange && (authInfo.getAuthenticationDN() != null) && |
| | | (authInfo.getAuthenticationDN().equals(userDN))) |
| | | { |
| | | operation.getClientConnection().setMustChangePassword(false); |
| | | // If we've gotten here, then everything is OK, so indicate that the |
| | | // operation was successful. If a password was generated, then include |
| | | // it in the response. |
| | | operation.setResultCode(ResultCode.SUCCESS); |
| | | |
| | | if (generatedPassword) |
| | | { |
| | | ArrayList<ASN1Element> valueElements = new ArrayList<ASN1Element>(1); |
| | | |
| | | ASN1OctetString newPWString = |
| | | new ASN1OctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD, |
| | | newPassword.value()); |
| | | valueElements.add(newPWString); |
| | | |
| | | ASN1Sequence valueSequence = new ASN1Sequence(valueElements); |
| | | operation.setResponseValue(new ASN1OctetString( |
| | | valueSequence.encode())); |
| | | } |
| | | |
| | | |
| | | // If this was a self password change, and the client is authenticated |
| | | // as the user whose password was changed, then clear the "must change |
| | | // password" flag in the client connection. Note that we're using the |
| | | // authentication DN rather than the authorization DN in this case to |
| | | // avoid mistakenly clearing the flag for the wrong user. |
| | | if (selfChange && (authInfo.getAuthenticationDN() != null) && |
| | | (authInfo.getAuthenticationDN().equals(userDN))) |
| | | { |
| | | operation.getClientConnection().setMustChangePassword(false); |
| | | } |
| | | |
| | | |
| | | // If the password policy control was requested, then add the |
| | | // appropriate response control. |
| | | if (pwPolicyRequested) |
| | | { |
| | | operation.addResponseControl( |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType)); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Set<String> getSupportedControls() |
| | | { |
| | | assert debugEnter(CLASS_NAME, "getSupportedControls"); |
| | | |
| | | return supportedControlOIDs; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the DN of the configuration entry with which this component is |
| | | * associated. |
| | | * |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an extended operation |
| | | * cannot be processed because it contains an unsupported critical control. |
| | | * This takes two arguments, which are the OID of the extended request and the |
| | | * OID of the unsupported control. |
| | | */ |
| | | public static final int MSGID_EXTENDED_UNSUPPORTED_CRITICAL_CONTROL = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 570; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined |
| | | * in this class. |
| | | */ |
| | |
| | | "There is no extended operation handler registered with " + |
| | | "the Directory Server for handling extended operations " + |
| | | "with a request OID of %s."); |
| | | registerMessage(MSGID_EXTENDED_UNSUPPORTED_CRITICAL_CONTROL, |
| | | "Unable to process the request for extended operation %s " + |
| | | "because it contained an unsupported critical control " + |
| | | "with OID %s."); |
| | | |
| | | |
| | | registerMessage(MSGID_CONNHANDLER_CLOSED_BY_SHUTDOWN, |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a password change is |
| | | * not actually performed because the request contained the LDAP no-op |
| | | * control. This does not take any arguments. |
| | | */ |
| | | public static final int MSGID_EXTOP_PASSMOD_NOOP = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_WARNING | 380; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the user's account is |
| | | * disabled. This does not take any arguments. |
| | | */ |
| | | public static final int MSGID_EXTOP_PASSMOD_ACCOUNT_DISABLED = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 381; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the user's account is |
| | | * locked. This does not take any arguments. |
| | | */ |
| | | public static final int MSGID_EXTOP_PASSMOD_ACCOUNT_LOCKED = |
| | | CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 382; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | registerMessage(MSGID_EXTOP_PASSMOD_CANNOT_GET_PW_POLICY, |
| | | "An error occurred while attempting to get the " + |
| | | "password policy for user %s: %s."); |
| | | registerMessage(MSGID_EXTOP_PASSMOD_ACCOUNT_DISABLED, |
| | | "The user account has been administratively disabled."); |
| | | registerMessage(MSGID_EXTOP_PASSMOD_ACCOUNT_LOCKED, |
| | | "The user account is locked."); |
| | | registerMessage(MSGID_EXTOP_PASSMOD_REQUIRE_CURRENT_PW, |
| | | "The current password must be provided for self password " + |
| | | "changes."); |
| | |
| | | registerMessage(MSGID_EXTOP_PASSMOD_CANNOT_ENCODE_PASSWORD, |
| | | "Unable to encode the provided password using the " + |
| | | "default scheme(s): %s."); |
| | | registerMessage(MSGID_EXTOP_PASSMOD_NOOP, |
| | | "The password modify operation was not actually " + |
| | | "performed in the Directory Server because the LDAP " + |
| | | "no-op control was present in the request."); |
| | | |
| | | |
| | | registerMessage(MSGID_NULL_KEYMANAGER_NO_MANAGER, |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used to display warning |
| | | * information included in the password policy response control. This takes |
| | | * two arguments, which are the string representation of the warning type and |
| | | * the integer warning value. |
| | | */ |
| | | public static final int MSGID_LDAPPWMOD_PWPOLICY_WARNING = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 786; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used to display error |
| | | * information included in the password policy response control. This takes |
| | | * a single argument, which is the string representation of the error type. |
| | | */ |
| | | public static final int MSGID_LDAPPWMOD_PWPOLICY_ERROR = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 787; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an error occurs while |
| | | * trying to decode the password policy response control. This takes a |
| | | * single argument, which is a string representation of the exception that was |
| | | * caught. |
| | | */ |
| | | public static final int MSGID_LDAPPWMOD_CANNOT_DECODE_PWPOLICY_CONTROL = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 788; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | "The LDAP password modify operation was successful."); |
| | | registerMessage(MSGID_LDAPPWMOD_ADDITIONAL_INFO, |
| | | "Additional Info: %s."); |
| | | registerMessage(MSGID_LDAPPWMOD_PWPOLICY_WARNING, |
| | | "Password Policy Warning: %s = %d."); |
| | | registerMessage(MSGID_LDAPPWMOD_PWPOLICY_ERROR, |
| | | "Password Policy Error: %s."); |
| | | registerMessage(MSGID_LDAPPWMOD_CANNOT_DECODE_PWPOLICY_CONTROL, |
| | | "Unable to decode the password policy response control: " + |
| | | "%s."); |
| | | registerMessage(MSGID_LDAPPWMOD_GENERATED_PASSWORD, |
| | | "Generated Password: %s."); |
| | | registerMessage(MSGID_LDAPPWMOD_UNRECOGNIZED_VALUE_TYPE, |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | import org.opends.server.controls.PasswordPolicyErrorType; |
| | | import org.opends.server.controls.PasswordPolicyResponseControl; |
| | | import org.opends.server.controls.PasswordPolicyWarningType; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.protocols.asn1.ASN1Element; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | |
| | | } |
| | | |
| | | |
| | | // See if the response included any controls that we recognize, and if so |
| | | // then handle them. |
| | | ArrayList<LDAPControl> responseControls = responseMessage.getControls(); |
| | | if (responseControls != null) |
| | | { |
| | | for (LDAPControl c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL)) |
| | | { |
| | | try |
| | | { |
| | | PasswordPolicyResponseControl pwPolicyControl = |
| | | PasswordPolicyResponseControl.decodeControl(c.getControl()); |
| | | |
| | | PasswordPolicyWarningType pwPolicyWarningType = |
| | | pwPolicyControl.getWarningType(); |
| | | if (pwPolicyWarningType != null) |
| | | { |
| | | int msgID = MSGID_LDAPPWMOD_PWPOLICY_WARNING; |
| | | String message = getMessage(msgID, pwPolicyWarningType.toString(), |
| | | pwPolicyControl.getWarningValue()); |
| | | out.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | } |
| | | |
| | | PasswordPolicyErrorType pwPolicyErrorType = |
| | | pwPolicyControl.getErrorType(); |
| | | if (pwPolicyErrorType != null) |
| | | { |
| | | int msgID = MSGID_LDAPPWMOD_PWPOLICY_ERROR; |
| | | String message = getMessage(msgID, pwPolicyErrorType.toString()); |
| | | out.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_LDAPPWMOD_CANNOT_DECODE_PWPOLICY_CONTROL; |
| | | String message = getMessage(msgID, String.valueOf(e)); |
| | | err.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // See if the response included a generated password. |
| | | ASN1OctetString responseValue = extendedResponse.getValue(); |
| | | if (responseValue != null) |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSelfChangeCurrentPasswordNewPassword() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSelfChangeNoCurrentPasswordNewPassword() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSelfChangeCurrentPasswordNoNewPassword() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSelfChangeNoCurrentPasswordNoNewPassword() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testAuthenticatedSelfExplicitAuthzIDCurrentNew() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testAuthenticatedSelfImplicitAuthzIDCurrentNew() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testAuthenticatedSelfImplicitAuthzIDNoCurrentNew() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testUnauthenticatedSelfChangeNewPassword() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testUnauthenticatedSelfChangeNoNewPassword() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testAdminResetNewPassword() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testAdminResetNoNewPassword() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSSLBlindTrust() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSSLTrustStore() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testStartTLSBlindTrust() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testStartTLSTrustStore() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testBindAndNewPasswordsFromFile() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testCurrentAndNewPasswordsFromFile() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testResetWithInvalidAuthzDN() |
| | | throws Exception |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testResetOnNonExistentUser() |
| | | throws Exception |
| | | { |
| | |
| | | |
| | | |
| | | /** |
| | | * Tests a failure when attempting an administrative reset on a user entry |
| | | * that has been disabled. Also include the password policy control in the |
| | | * request. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testResetOnDisabledUser() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | Entry e = 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: password", |
| | | "ds-pwp-account-disabled: true"); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | AddOperation addOperation = |
| | | conn.processAdd(e.getDN(), e.getObjectClasses(), |
| | | e.getUserAttributes(), e.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-a", "dn:uid=test.user,o=test", |
| | | "-n", "newPassword", |
| | | "-J", "pwpolicy:true" |
| | | }; |
| | | |
| | | assertFalse(LDAPPasswordModify.mainPasswordModify(args, false, null, |
| | | null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the password modify extended operation in conjunction with a control |
| | | * that is marked critical but that is not supported by the server. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testLDAPNoOpUnsupportedCriticalControl() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | Entry e = 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: password"); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | AddOperation addOperation = |
| | | conn.processAdd(e.getDN(), e.getObjectClasses(), |
| | | e.getUserAttributes(), e.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-a", "dn:uid=test.user,o=test", |
| | | "-n", "newPassword", |
| | | "-J", "1.2.3.4:true" |
| | | }; |
| | | |
| | | assertFalse(LDAPPasswordModify.mainPasswordModify(args, false, null, null) |
| | | == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the password modify extended operation in conjunction with the LDAP |
| | | * no-op control using the explicit OID for that control. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testLDAPNoOpExplicitOID() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | Entry e = 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: password"); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | AddOperation addOperation = |
| | | conn.processAdd(e.getDN(), e.getObjectClasses(), |
| | | e.getUserAttributes(), e.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-a", "dn:uid=test.user,o=test", |
| | | "-n", "newPassword", |
| | | "-J", OID_LDAP_NOOP_OPENLDAP_ASSIGNED + ":true" |
| | | }; |
| | | |
| | | // FIXME -- Change this whenever the real LDAP No-Op result code is assigned |
| | | assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), |
| | | 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the password modify extended operation in conjunction with the LDAP |
| | | * no-op control using a more user-friendly name instead of an OID. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testLDAPNoOpImplicitOID() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | Entry e = 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: password"); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | AddOperation addOperation = |
| | | conn.processAdd(e.getDN(), e.getObjectClasses(), |
| | | e.getUserAttributes(), e.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-a", "dn:uid=test.user,o=test", |
| | | "-n", "newPassword", |
| | | "-J", "noop:true" |
| | | }; |
| | | |
| | | // FIXME -- Change this whenever the real LDAP No-Op result code is assigned |
| | | assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), |
| | | 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the password modify extended operation in conjunction with multiple |
| | | * request controls. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testLDAPMultipleControls() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | Entry e = 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: password"); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | AddOperation addOperation = |
| | | conn.processAdd(e.getDN(), e.getObjectClasses(), |
| | | e.getUserAttributes(), e.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-a", "dn:uid=test.user,o=test", |
| | | "-n", "newPassword", |
| | | "-J", OID_LDAP_NOOP_OPENLDAP_ASSIGNED + ":true", |
| | | "-J", OID_PASSWORD_POLICY_CONTROL + ":true" |
| | | }; |
| | | |
| | | // FIXME -- Change this whenever the real LDAP No-Op result code is assigned |
| | | assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), |
| | | 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the LDAPModify tool with the "--help" option. |
| | | */ |
| | | @Test() |