| | |
| | | package org.opends.server.workflowelement.localbackend; |
| | | |
| | | import java.util.List; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1; |
| | | import org.forgerock.i18n.LocalizableMessageDescriptor.Arg2; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn; |
| | | import org.opends.server.api.AuthenticationPolicyState; |
| | | import org.opends.server.api.Backend; |
| | |
| | | import org.opends.server.api.plugin.PluginResult; |
| | | import org.opends.server.controls.*; |
| | | import org.opends.server.core.*; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.opends.server.types.*; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.opends.server.types.operation.PostOperationBindOperation; |
| | | import org.opends.server.types.operation.PostResponseBindOperation; |
| | | import org.opends.server.types.operation.PreOperationBindOperation; |
| | |
| | | { |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | | /** |
| | | * The backend in which the bind operation should be processed. |
| | | */ |
| | | protected Backend<?> backend; |
| | | /** The backend in which the bind operation should be processed. */ |
| | | private Backend<?> backend; |
| | | |
| | | /** |
| | | * Indicates whether the bind response should include the first warning |
| | | * for an upcoming password expiration. |
| | | */ |
| | | protected boolean isFirstWarning; |
| | | private boolean isFirstWarning; |
| | | /** Indicates whether this bind is using a grace login for the user. */ |
| | | private boolean isGraceLogin; |
| | | |
| | | /** |
| | | * Indicates whether this bind is using a grace login for the user. |
| | | */ |
| | | protected boolean isGraceLogin; |
| | | |
| | | /** |
| | | * Indicates whether the user must change his/her password before doing |
| | | * anything else. |
| | | */ |
| | | /** Indicates whether the user must change his/her password before doing anything else. */ |
| | | private boolean mustChangePassword; |
| | | |
| | | /** Indicates whether the user requested the password policy control. */ |
| | |
| | | */ |
| | | private boolean returnAuthzID; |
| | | |
| | | /** |
| | | * Indicates whether to execute post-operation plugins. |
| | | */ |
| | | protected boolean executePostOpPlugins; |
| | | /** Indicates whether to execute post-operation plugins. */ |
| | | private boolean executePostOpPlugins; |
| | | |
| | | /** The client connection associated with this bind operation. */ |
| | | private ClientConnection clientConnection; |
| | | |
| | | /** |
| | | * The bind DN provided by the client. |
| | | */ |
| | | protected DN bindDN; |
| | | |
| | | /** The lookthrough limit that should be enforced for the user. */ |
| | | private int lookthroughLimit; |
| | | /** The bind DN provided by the client. */ |
| | | private DN bindDN; |
| | | |
| | | /** The value to use for the password policy warning. */ |
| | | private int pwPolicyWarningValue; |
| | | |
| | | /** The lookthrough limit that should be enforced for the user. */ |
| | | private int lookthroughLimit; |
| | | /** The size limit that should be enforced for the user. */ |
| | | private int sizeLimit; |
| | | |
| | | /** The time limit that should be enforced for the user. */ |
| | | private int timeLimit; |
| | | |
| | | /** The idle time limit that should be enforced for the user. */ |
| | | private long idleTimeLimit; |
| | | |
| | |
| | | |
| | | /** The password policy error type for this bind operation. */ |
| | | private PasswordPolicyErrorType pwPolicyErrorType; |
| | | |
| | | /** The password policy warning type for this bind operation. */ |
| | | private PasswordPolicyWarningType pwPolicyWarningType; |
| | | |
| | | /** |
| | | * The plugin config manager for the Directory Server. |
| | | */ |
| | | protected PluginConfigManager pluginConfigManager; |
| | | /** The plugin config manager for the Directory Server. */ |
| | | private PluginConfigManager pluginConfigManager; |
| | | |
| | | /** The SASL mechanism used for this bind operation. */ |
| | | private String saslMechanism; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new operation that may be used to bind where |
| | | * the bound user entry is stored in a local backend of the Directory Server. |
| | | * |
| | | * @param bind The operation to enhance. |
| | | */ |
| | | public LocalBackendBindOperation(BindOperation bind) |
| | | LocalBackendBindOperation(BindOperation bind) |
| | | { |
| | | super(bind); |
| | | LocalBackendWorkflowElement.attachLocalOperation (bind, this); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Process this bind operation in a local backend. |
| | | * |
| | | * @param wfe |
| | | * The local backend work-flow element. |
| | | * |
| | | */ |
| | | public void processLocalBind(LocalBackendWorkflowElement wfe) |
| | | { |
| | |
| | | setResponseData(de); |
| | | } |
| | | |
| | | |
| | | // Invoke the post-operation bind plugins. |
| | | if (executePostOpPlugins) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | // Update the authentication information for the user. |
| | | AuthenticationInfo authInfo = getAuthenticationInfo(); |
| | | if (getResultCode() == ResultCode.SUCCESS && authInfo != null) |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | // See if we need to send a password policy control to the client. If so, |
| | | // then add it to the response. |
| | | if (getResultCode() == ResultCode.SUCCESS) |
| | | if (pwPolicyControlRequested) |
| | | { |
| | | if (pwPolicyControlRequested) |
| | | { |
| | | PasswordPolicyResponseControl pwpControl = |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType); |
| | | addResponseControl(pwpControl); |
| | | } |
| | | else |
| | | addResponseControl(new PasswordPolicyResponseControl( |
| | | pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType)); |
| | | } |
| | | else |
| | | { |
| | | if (getResultCode() == ResultCode.SUCCESS) |
| | | { |
| | | if (pwPolicyErrorType == PasswordPolicyErrorType.PASSWORD_EXPIRED) |
| | | { |
| | | addResponseControl(new PasswordExpiredControl()); |
| | | } |
| | | else if (pwPolicyWarningType == |
| | | PasswordPolicyWarningType.TIME_BEFORE_EXPIRATION) |
| | | else if (pwPolicyWarningType == PasswordPolicyWarningType.TIME_BEFORE_EXPIRATION) |
| | | { |
| | | addResponseControl(new PasswordExpiringControl(pwPolicyWarningValue)); |
| | | } |
| | |
| | | addResponseControl(new PasswordExpiredControl()); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (pwPolicyControlRequested) |
| | | { |
| | | PasswordPolicyResponseControl pwpControl = |
| | | new PasswordPolicyResponseControl(pwPolicyWarningType, |
| | | pwPolicyWarningValue, |
| | | pwPolicyErrorType); |
| | | addResponseControl(pwpControl); |
| | | } |
| | | else |
| | | { |
| | | if (pwPolicyErrorType == PasswordPolicyErrorType.PASSWORD_EXPIRED) |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Performs the checks and processing necessary for the current bind operation |
| | | * (simple or SASL). |
| | | */ |
| | | private void processBind() |
| | | { |
| | | // Check to see if the client has permission to perform the |
| | | // bind. |
| | | // Check to see if the client has permission to perform the bind. |
| | | |
| | | // FIXME: for now assume that this will check all permission |
| | | // pertinent to the operation. This includes any controls |
| | | // specified. |
| | | // pertinent to the operation. This includes any controls specified. |
| | | try |
| | | { |
| | | if (!AccessControlConfigManager.getInstance().getAccessControlHandler() |
| | | .isAllowed(this)) |
| | | if (!AccessControlConfigManager.getInstance().getAccessControlHandler().isAllowed(this)) |
| | | { |
| | | setResultCode(ResultCode.INVALID_CREDENTIALS); |
| | | setAuthFailureReason(ERR_BIND_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get()); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Performs the processing necessary for a simple bind operation. |
| | | * |
| | |
| | | * @throws DirectoryException If a problem occurs that should cause the bind |
| | | * operation to fail. |
| | | */ |
| | | protected boolean processSimpleBind() |
| | | throws DirectoryException |
| | | private boolean processSimpleBind() throws DirectoryException |
| | | { |
| | | // See if this is an anonymous bind. If so, then determine whether |
| | | // to allow it. |
| | |
| | | |
| | | if (de.getResultCode() == ResultCode.REFERRAL) |
| | | { |
| | | // Re-throw referral exceptions - these should be passed back |
| | | // to the client. |
| | | // Re-throw referral exceptions - these should be passed back to the client. |
| | | throw de; |
| | | } |
| | | else |
| | | { |
| | | // Replace other exceptions in case they expose any sensitive |
| | | // information. |
| | | throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, |
| | | de.getMessageObject()); |
| | | // Replace other exceptions in case they expose any sensitive information. |
| | | throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, de.getMessageObject()); |
| | | } |
| | | } |
| | | |
| | |
| | | throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, |
| | | ERR_BIND_OPERATION_UNKNOWN_USER.get()); |
| | | } |
| | | else |
| | | { |
| | | setUserEntryDN(userEntry.getName()); |
| | | } |
| | | |
| | | setUserEntryDN(userEntry.getName()); |
| | | |
| | | // Check to see if the user has a password. If not, then fail. |
| | | // FIXME -- We need to have a way to enable/disable debugging. |
| | |
| | | if (authPolicyState.isPasswordPolicy()) |
| | | { |
| | | // Account is managed locally. |
| | | PasswordPolicyState pwPolicyState = |
| | | (PasswordPolicyState) authPolicyState; |
| | | PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; |
| | | PasswordPolicy policy = pwPolicyState.getAuthenticationPolicy(); |
| | | |
| | | AttributeType pwType = policy.getPasswordAttribute(); |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Performs the processing necessary for an anonymous simple bind. |
| | | * |
| | |
| | | * @throws DirectoryException If a problem occurs that should cause the bind |
| | | * operation to fail. |
| | | */ |
| | | protected boolean processAnonymousSimpleBind() throws DirectoryException |
| | | private boolean processAnonymousSimpleBind() throws DirectoryException |
| | | { |
| | | // If the server is in lockdown mode, then fail. |
| | | if (DirectoryServer.lockdownMode()) |
| | |
| | | ERR_BIND_DN_BUT_NO_PASSWORD.get()); |
| | | } |
| | | |
| | | |
| | | // Invoke pre-operation plugins. |
| | | if (!invokePreOpPlugins()) |
| | | { |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Performs the processing necessary for a SASL bind operation. |
| | | * |
| | |
| | | saslMechanism)); |
| | | } |
| | | |
| | | |
| | | // Check to see if the client has sufficient permission to perform the bind. |
| | | // NYI |
| | | |
| | | |
| | | // Invoke pre-operation plugins. |
| | | if (!invokePreOpPlugins()) |
| | | { |
| | |
| | | // Actually process the SASL bind. |
| | | saslHandler.processSASLBind(this); |
| | | |
| | | |
| | | // If the server is operating in lockdown mode, then we will need to |
| | | // ensure that the authentication was successful and performed as a |
| | | // root user to continue. |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | // Determine whether the authentication was successful and perform |
| | | // any remaining password policy processing accordingly. |
| | | ResultCode resultCode = getResultCode(); |
| | |
| | | { |
| | | if (authPolicyState != null && authPolicyState.isPasswordPolicy()) |
| | | { |
| | | PasswordPolicyState pwPolicyState = |
| | | (PasswordPolicyState) authPolicyState; |
| | | PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; |
| | | |
| | | if (saslHandler.isPasswordBased(saslMechanism) |
| | | && pwPolicyState.getAuthenticationPolicy().getLockoutFailureCount() > 0) |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | private void generateAccountStatusNotificationForLockedBindAccount( |
| | | Entry userEntry, PasswordPolicyState pwPolicyState) |
| | | { |
| | |
| | | int lockoutDuration = pwPolicyState.getSecondsUntilUnlock(); |
| | | if (lockoutDuration > -1) |
| | | { |
| | | notificationType = |
| | | AccountStatusNotificationType.ACCOUNT_TEMPORARILY_LOCKED; |
| | | notificationType = AccountStatusNotificationType.ACCOUNT_TEMPORARILY_LOCKED; |
| | | tempLocked = true; |
| | | m = |
| | | ERR_BIND_ACCOUNT_TEMPORARILY_LOCKED |
| | |
| | | } |
| | | else |
| | | { |
| | | notificationType = |
| | | AccountStatusNotificationType.ACCOUNT_PERMANENTLY_LOCKED; |
| | | notificationType = AccountStatusNotificationType.ACCOUNT_PERMANENTLY_LOCKED; |
| | | tempLocked = false; |
| | | m = ERR_BIND_ACCOUNT_PERMANENTLY_LOCKED.get(); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | private boolean invokePreOpPlugins() |
| | | { |
| | | executePostOpPlugins = true; |
| | |
| | | setReferralURLs(preOpResult.getReferralURLs()); |
| | | return false; |
| | | } |
| | | else |
| | | { |
| | | return true; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Validates a number of password policy state constraints for the user. This |
| | | * will be called before the offered credentials are checked. |
| | |
| | | * @throws DirectoryException |
| | | * If a problem occurs that should cause the bind to fail. |
| | | */ |
| | | protected void checkUnverifiedPasswordPolicyState( |
| | | private void checkUnverifiedPasswordPolicyState( |
| | | Entry userEntry, SASLMechanismHandler<?> saslHandler) |
| | | throws DirectoryException |
| | | { |
| | | PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; |
| | | PasswordPolicy policy = pwPolicyState.getAuthenticationPolicy(); |
| | | |
| | | boolean isSASLBind = saslHandler != null; |
| | | |
| | | // If the password policy is configured to track authentication failures or |
| | | // keep the last login time and the associated backend is disabled, then we |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | // Check to see if the authentication must be done in a secure |
| | | // manner. If so, then the client connection must be secure. |
| | | if (policy.isRequireSecureAuthentication() |
| | | && !clientConnection.isSecure()) |
| | | { |
| | | boolean isSASLBind = saslHandler != null; |
| | | if (isSASLBind) |
| | | { |
| | | if (! saslHandler.isSecure(saslMechanism)) |
| | |
| | | * @throws DirectoryException |
| | | * If a problem occurs that should cause the bind to fail. |
| | | */ |
| | | protected void checkVerifiedPasswordPolicyState( |
| | | private void checkVerifiedPasswordPolicyState( |
| | | Entry userEntry, SASLMechanismHandler<?> saslHandler) |
| | | throws DirectoryException |
| | | { |
| | | PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; |
| | | PasswordPolicy policy = pwPolicyState.getAuthenticationPolicy(); |
| | | |
| | | boolean isSASLBind = saslHandler != null; |
| | | |
| | | // Check to see if the user is administratively disabled or locked. |
| | | if (pwPolicyState.isDisabled()) |
| | | { |
| | |
| | | throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, m); |
| | | } |
| | | |
| | | |
| | | // If it's a simple bind, or if it's a password-based SASL bind, then |
| | | // perform a number of password-based checks. |
| | | boolean isSASLBind = saslHandler != null; |
| | | if (!isSASLBind || saslHandler.isPasswordBased(saslMechanism)) |
| | | { |
| | | // Check to see if the account is locked due to the maximum reset age. |
| | |
| | | throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, m); |
| | | } |
| | | |
| | | |
| | | // Determine whether the password is expired, or whether the user |
| | | // should be warned about an upcoming expiration. |
| | | if (pwPolicyState.isPasswordExpired()) |
| | |
| | | |
| | | if (pwPolicyWarningType == null) |
| | | { |
| | | pwPolicyWarningType = |
| | | PasswordPolicyWarningType.TIME_BEFORE_EXPIRATION; |
| | | pwPolicyWarningType = PasswordPolicyWarningType.TIME_BEFORE_EXPIRATION; |
| | | pwPolicyWarningValue = numSeconds; |
| | | } |
| | | |
| | | isFirstWarning = pwPolicyState.isFirstWarning(); |
| | | } |
| | | |
| | | |
| | | // Check to see if the user's password has been reset. |
| | | if (pwPolicyState.mustChangePassword()) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets resource limits for the authenticated user. |
| | | * |
| | | * @param userEntry The entry for the authenticated user. |
| | | */ |
| | | protected void setResourceLimits(Entry userEntry) |
| | | private void setResourceLimits(Entry userEntry) |
| | | { |
| | | // See if the user's entry contains a custom size limit. |
| | | Integer customSizeLimit = |