LocalBackendBindOperation.java revision ca669ae54f86dbeea277280690584d9f591c7571
/*
* 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 legal-notices/CDDLv1_0.txt
* 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 legal-notices/CDDLv1_0.txt.
* 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
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS.
*/
/**
* This class defines an operation used to bind against the Directory Server,
* with the bound user entry within a local backend.
*/
public class LocalBackendBindOperation
extends BindOperationWrapper
implements PreOperationBindOperation, PostOperationBindOperation,
{
/**
* The backend in which the bind operation should be processed.
*/
/**
* Indicates whether the bind response should include the first warning
* for an upcoming password expiration.
*/
protected boolean isFirstWarning;
/**
* Indicates whether this bind is using a grace login for the user.
*/
protected boolean isGraceLogin;
/**
* anything else.
*/
private boolean mustChangePassword;
/** Indicates whether the user requested the password policy control. */
private boolean pwPolicyControlRequested;
/**
* Indicates whether the server should return the authorization ID as a
* control in the bind response.
*/
private boolean returnAuthzID;
/**
* Indicates whether to execute post-operation plugins.
*/
protected boolean executePostOpPlugins;
/** The client connection associated with this bind operation. */
private ClientConnection clientConnection;
/**
* The bind DN provided by the client.
*/
/** The lookthrough limit that should be enforced for the user. */
private int lookthroughLimit;
/** The value to use for the password policy warning. */
private int pwPolicyWarningValue;
/** 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;
/** Authentication policy state. */
private AuthenticationPolicyState authPolicyState;
/** The password policy error type for this bind operation. */
private PasswordPolicyErrorType pwPolicyErrorType;
/** The password policy warning type for this bind operation. */
/**
* The plugin config manager for the Directory Server.
*/
protected 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.
*/
{
super(bind);
}
/**
* Process this bind operation in a local backend.
*
* @param wfe
* The local backend work-flow element.
*
*/
{
// Initialize a number of variables for use during the bind processing.
returnAuthzID = false;
executePostOpPlugins = false;
pwPolicyControlRequested = false;
isGraceLogin = false;
isFirstWarning = false;
mustChangePassword = false;
pwPolicyWarningValue = -1 ;
processBind();
// Update the user's account with any password policy changes that may be
// required.
try
{
if (authPolicyState != null)
{
}
}
catch (DirectoryException de)
{
}
// Invoke the post-operation bind plugins.
if (executePostOpPlugins)
{
if (!postOpResult.continueProcessing())
{
}
}
// Update the authentication information for the user.
{
if (returnAuthzID)
{
}
}
// See if we need to send a password policy control to the client. If so,
// then add it to the response.
{
{
}
else
{
{
}
else if (pwPolicyWarningType ==
{
}
else if (mustChangePassword)
{
}
}
}
else
{
{
}
else
{
{
}
}
}
}
/**
* 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.
// FIXME: for now assume that this will check all permission
// pertinent to the operation. This includes any controls
// specified.
try
{
.isAllowed(this))
{
return;
}
}
catch (DirectoryException e)
{
setResultCode(e.getResultCode());
return;
}
// Check to see if there are any controls in the request. If so, then see
// if there is any special processing required.
try
{
}
catch (DirectoryException de)
{
return;
}
// Check to see if this is a simple bind or a SASL bind and process
// accordingly.
try
{
switch (getAuthenticationType())
{
case SIMPLE:
break;
case SASL:
break;
default:
// Send a protocol error response to the client and disconnect.
// We should never come here.
}
}
catch (DirectoryException de)
{
{
}
else
{
}
}
}
/**
* Handles request control processing for this bind operation.
*
* @throws DirectoryException If there is a problem with any of the
* controls.
*/
private void handleRequestControls() throws DirectoryException
{
{
{
{
returnAuthzID = true;
}
{
pwPolicyControlRequested = true;
}
// NYI -- Add support for additional controls.
else if (c.isCritical())
{
throw new DirectoryException(
}
}
}
}
/**
* Performs the processing necessary for a simple bind operation.
*
* @return {@code true} if processing should continue for the operation, or
* {@code false} if not.
*
* @throws DirectoryException If a problem occurs that should cause the bind
* operation to fail.
*/
protected boolean processSimpleBind()
throws DirectoryException
{
// See if this is an anonymous bind. If so, then determine whether
// to allow it.
{
return processAnonymousSimpleBind();
}
// See if the bind DN is actually one of the alternate root DNs
// defined in the server. If so, then replace it with the actual DN
// for that user.
if (actualRootDN != null)
{
}
// Get the user entry based on the bind DN. If it does not exist,
// then fail.
{
}
try
{
try
{
}
catch (DirectoryException de)
{
{
// 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.
de.getMessageObject());
}
}
{
}
else
{
}
// Check to see if the user has a password. If not, then fail.
if (authPolicyState.isPasswordPolicy())
{
// Account is managed locally.
{
}
// Perform a number of password policy state checks for the
// non-authenticated user.
// Invoke pre-operation plugins.
if (!invokePreOpPlugins())
{
return false;
}
// Determine whether the provided password matches any of the stored
// passwords for the user.
{
if (DirectoryServer.lockdownMode()
{
}
// Set resource limits for the authenticated user.
// Perform any remaining processing for a successful simple
// authentication.
if (isFirstWarning)
{
}
if (isGraceLogin)
{
}
}
else
{
{
}
}
}
else
{
// Check to see if the user is administratively disabled or locked.
if (authPolicyState.isDisabled())
{
}
// Invoke pre-operation plugins.
if (!invokePreOpPlugins())
{
return false;
}
{
if (DirectoryServer.lockdownMode()
{
}
// Set resource limits for the authenticated user.
}
else
{
}
}
return true;
}
finally
{
// No matter what, make sure to unlock the user's entry.
}
}
/**
* Performs the processing necessary for an anonymous simple bind.
*
* @return {@code true} if processing should continue for the operation, or
* {@code false} if not.
* @throws DirectoryException If a problem occurs that should cause the bind
* operation to fail.
*/
protected boolean processAnonymousSimpleBind() throws DirectoryException
{
// If the server is in lockdown mode, then fail.
if (DirectoryServer.lockdownMode())
{
}
// If there is a bind DN, then see whether that is acceptable.
{
}
// Invoke pre-operation plugins.
if (!invokePreOpPlugins())
{
return false;
}
return true;
}
/**
* Performs the processing necessary for a SASL bind operation.
*
* @return {@code true} if processing should continue for the operation, or
* {@code false} if not.
*
* @throws DirectoryException If a problem occurs that should cause the bind
* operation to fail.
*/
private boolean processSASLBind() throws DirectoryException
{
// Get the appropriate authentication handler for this request based
// on the SASL mechanism. If there is none, then fail.
if (saslHandler == null)
{
}
// Check to see if the client has sufficient permission to perform the bind.
// NYI
// Invoke pre-operation plugins.
if (!invokePreOpPlugins())
{
return false;
}
// 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.
if (DirectoryServer.lockdownMode())
{
|| saslAuthUserEntry == null
{
}
}
// Create the password policy state object.
if (saslAuthUserEntry != null)
{
// FIXME -- Need to have a way to enable debugging.
saslAuthUserEntry, false);
if (authPolicyState.isPasswordPolicy())
{
// Account is managed locally: perform password policy checks that can
// be completed before we have checked authentication was successful.
}
}
// Determine whether the authentication was successful and perform
// any remaining password policy processing accordingly.
{
{
{
mustChangePassword = true;
}
if (isFirstWarning)
{
}
if (isGraceLogin)
{
}
}
// Set appropriate resource limits for the user (note that SASL ANONYMOUS
// does not have a user).
if (saslAuthUserEntry != null)
{
}
}
{
// FIXME -- Is any special processing needed here?
return false;
}
else
{
{
{
}
}
}
return true;
}
private void generateAccountStatusNotificationForLockedBindAccount(
{
if (pwPolicyState.lockedDueToFailures())
{
boolean tempLocked;
if (lockoutDuration > -1)
{
tempLocked = true;
m =
}
else
{
tempLocked = false;
}
}
}
private boolean invokePreOpPlugins()
{
executePostOpPlugins = true;
.invokePreOperationBindPlugins(this);
if (!preOpResult.continueProcessing())
{
return false;
}
else
{
return true;
}
}
/**
* Validates a number of password policy state constraints for the user. This
* will be called before the offered credentials are checked.
*
* @param userEntry
* The entry for the user that is authenticating.
* @param saslHandler
* The SASL mechanism handler if this is a SASL bind, or {@code null}
* for a simple bind.
* @throws DirectoryException
* If a problem occurs that should cause the bind to fail.
*/
protected void checkUnverifiedPasswordPolicyState(
throws DirectoryException
{
// If the password policy is configured to track authentication failures or
// keep the last login time and the associated backend is disabled, then we
// may need to reject the bind immediately.
if ((policy.getStateUpdateFailurePolicy() ==
{
// This policy isn't applicable to root users, so if it's a root
// user then ignore it.
{
}
}
// Check to see if the authentication must be done in a secure
// manner. If so, then the client connection must be secure.
&& (!clientConnection.isSecure()))
{
if (isSASLBind)
{
{
}
}
else
{
}
}
}
/**
* Perform policy checks for accounts when the credentials are correct.
*
* @param userEntry
* The entry for the user that is authenticating.
* @param saslHandler
* The SASL mechanism handler if this is a SASL bind, or {@code null}
* for a simple bind.
* @throws DirectoryException
* If a problem occurs that should cause the bind to fail.
*/
protected void checkVerifiedPasswordPolicyState(
throws DirectoryException
{
// Check to see if the user is administratively disabled or locked.
if (pwPolicyState.isDisabled())
{
}
else if (pwPolicyState.isAccountExpired())
{
}
else if (pwPolicyState.lockedDueToFailures())
{
if (pwPolicyErrorType == null)
{
}
}
else if (pwPolicyState.lockedDueToIdleInterval())
{
if (pwPolicyErrorType == null)
{
}
}
// If it's a simple bind, or if it's a password-based SASL bind, then
// perform a number of password-based checks.
{
// Check to see if the account is locked due to the maximum reset age.
{
if (pwPolicyErrorType == null)
{
}
}
// Determine whether the password is expired, or whether the user
// should be warned about an upcoming expiration.
if (pwPolicyState.isPasswordExpired())
{
if (pwPolicyErrorType == null)
{
}
{
if ((graceLoginTimes == null) ||
{
isGraceLogin = true;
mustChangePassword = true;
if (pwPolicyWarningType == null)
{
}
}
else
{
false, -1, null,
null));
}
}
else
{
}
}
else if (pwPolicyState.shouldWarn())
{
if (pwPolicyWarningType == null)
{
}
}
// Check to see if the user's password has been reset.
if (pwPolicyState.mustChangePassword())
{
mustChangePassword = true;
if (pwPolicyErrorType == null)
{
}
}
}
}
/**
* Sets resource limits for the authenticated user.
*
* @param userEntry The entry for the authenticated user.
*/
{
// See if the user's entry contains a custom size limit.
if (customSizeLimit != null)
{
}
// See if the user's entry contains a custom time limit.
if (customTimeLimit != null)
{
}
// See if the user's entry contains a custom idle time limit.
// idleTimeLimit = 1000L * Long.parseLong(v.toString());
if (customIdleTimeLimitInSec != null)
{
}
// See if the user's entry contains a custom lookthrough limit.
if (customLookthroughLimit != null)
{
}
}
{
{
if (a.size() == 1)
{
try
{
}
catch (Exception e)
{
logger.traceException(e);
}
}
else if (a.size() > 1)
{
}
}
return null;
}
}