/** * Process this search operation against a local backend. * * @param wfe The local backend work-flow element. * @throws CanceledOperationException if this operation should be cancelled */ public void processLocalSearch(LocalBackendWorkflowElement wfe) throws CanceledOperationException { this.backend = wfe.getBackend(); this.clientConnection = getClientConnection(); // Check for a request to cancel this operation. checkIfCanceled(false); try { BooleanHolder executePostOpPlugins = new BooleanHolder(false); processSearch(executePostOpPlugins); // Check for a request to cancel this operation. checkIfCanceled(false); // Invoke the post-operation search plugins. if (executePostOpPlugins.value) { PluginResult.PostOperation postOpResult = DirectoryServer.getPluginConfigManager().invokePostOperationSearchPlugins(this); if (!postOpResult.continueProcessing()) { setResultCode(postOpResult.getResultCode()); appendErrorMessage(postOpResult.getErrorMessage()); setMatchedDN(postOpResult.getMatchedDN()); setReferralURLs(postOpResult.getReferralURLs()); } } } finally { LocalBackendWorkflowElement.filterNonDisclosableMatchedDN(this); } }
/** * 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( 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 // may need to reject the bind immediately. if ((policy.getStateUpdateFailurePolicy() == PasswordPolicyCfgDefn.StateUpdateFailurePolicy.PROACTIVE) && ((policy.getLockoutFailureCount() > 0) || ((policy.getLastLoginTimeAttribute() != null) && (policy.getLastLoginTimeFormat() != null))) && ((DirectoryServer.getWritabilityMode() == WritabilityMode.DISABLED) || (backend.getWritabilityMode() == WritabilityMode.DISABLED))) { // This policy isn't applicable to root users, so if it's a root // user then ignore it. if (!DirectoryServer.isRootDN(userEntry.getName())) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_OPERATION_WRITABILITY_DISABLED.get(userEntry.getName())); } } // 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()) { if (isSASLBind) { if (!saslHandler.isSecure(saslMechanism)) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_OPERATION_INSECURE_SASL_BIND.get(saslMechanism, userEntry.getName())); } } else { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_OPERATION_INSECURE_SIMPLE_BIND.get()); } } }
/** * 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()) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_REJECTED_LOCKDOWN_MODE.get()); } // If there is a bind DN, then see whether that is acceptable. if (DirectoryServer.bindWithDNRequiresPassword() && bindDN != null && !bindDN.isRootDN()) { throw new DirectoryException( ResultCode.UNWILLING_TO_PERFORM, ERR_BIND_DN_BUT_NO_PASSWORD.get()); } // Invoke pre-operation plugins. if (!invokePreOpPlugins()) { return false; } setResultCode(ResultCode.SUCCESS); setAuthenticationInfo(new AuthenticationInfo()); return true; }
private Integer getIntegerUserAttribute( Entry userEntry, String attributeTypeName, Arg1<Object> nonUniqueAttributeMessage, Arg2<Object, Object> cannotProcessAttributeMessage) { AttributeType attrType = DirectoryServer.getAttributeTypeOrDefault(attributeTypeName); List<Attribute> attrList = userEntry.getAttribute(attrType); if (attrList != null && attrList.size() == 1) { Attribute a = attrList.get(0); if (a.size() == 1) { ByteString v = a.iterator().next(); try { return Integer.valueOf(v.toString()); } catch (Exception e) { logger.traceException(e); logger.error(cannotProcessAttributeMessage.get(v, userEntry.getName())); } } else if (a.size() > 1) { logger.error(nonUniqueAttributeMessage.get(userEntry.getName())); } } return null; }
/** * Handles any controls contained in the request. * * @throws DirectoryException If there is a problem with any of the request controls. */ private void handleRequestControls() throws DirectoryException { LocalBackendWorkflowElement.removeAllDisallowedControls(baseDN, this); List<Control> requestControls = getRequestControls(); if (requestControls != null && !requestControls.isEmpty()) { for (Control c : requestControls) { String oid = c.getOID(); if (OID_LDAP_ASSERTION.equals(oid)) { LDAPAssertionRequestControl assertControl = getRequestControl(LDAPAssertionRequestControl.DECODER); SearchFilter assertionFilter; try { assertionFilter = assertControl.getSearchFilter(); } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } throw new DirectoryException( de.getResultCode(), ERR_SEARCH_CANNOT_PROCESS_ASSERTION_FILTER.get(de.getMessageObject()), de); } Entry entry; try { entry = DirectoryServer.getEntry(baseDN); } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } throw new DirectoryException( de.getResultCode(), ERR_SEARCH_CANNOT_GET_ENTRY_FOR_ASSERTION.get(de.getMessageObject())); } if (entry == null) { throw new DirectoryException( ResultCode.NO_SUCH_OBJECT, ERR_SEARCH_NO_SUCH_ENTRY_FOR_ASSERTION.get()); } // Check if the current user has permission to make // this determination. if (!AccessControlConfigManager.getInstance() .getAccessControlHandler() .isAllowed(this, entry, assertionFilter)) { throw new DirectoryException( ResultCode.INSUFFICIENT_ACCESS_RIGHTS, ERR_CONTROL_INSUFFICIENT_ACCESS_RIGHTS.get(oid)); } try { if (!assertionFilter.matchesEntry(entry)) { throw new DirectoryException( ResultCode.ASSERTION_FAILED, ERR_SEARCH_ASSERTION_FAILED.get()); } } catch (DirectoryException de) { if (de.getResultCode() == ResultCode.ASSERTION_FAILED) { throw de; } if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } throw new DirectoryException( de.getResultCode(), ERR_SEARCH_CANNOT_PROCESS_ASSERTION_FILTER.get(de.getMessageObject()), de); } } else if (OID_PROXIED_AUTH_V1.equals(oid)) { // Log usage of legacy proxy authz V1 control. addAdditionalLogItem( AdditionalLogItem.keyOnly(getClass(), "obsoleteProxiedAuthzV1Control")); // The requester must have the PROXIED_AUTH privilege in order to be // able to use this control. if (!clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this)) { throw new DirectoryException( ResultCode.AUTHORIZATION_DENIED, ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get()); } ProxiedAuthV1Control proxyControl = getRequestControl(ProxiedAuthV1Control.DECODER); Entry authorizationEntry = proxyControl.getAuthorizationEntry(); setAuthorizationEntry(authorizationEntry); setProxiedAuthorizationDN(getDN(authorizationEntry)); } else if (OID_PROXIED_AUTH_V2.equals(oid)) { // The requester must have the PROXIED_AUTH privilege in order to be // able to use this control. if (!clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this)) { throw new DirectoryException( ResultCode.AUTHORIZATION_DENIED, ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get()); } ProxiedAuthV2Control proxyControl = getRequestControl(ProxiedAuthV2Control.DECODER); Entry authorizationEntry = proxyControl.getAuthorizationEntry(); setAuthorizationEntry(authorizationEntry); setProxiedAuthorizationDN(getDN(authorizationEntry)); } else if (OID_PERSISTENT_SEARCH.equals(oid)) { final PersistentSearchControl ctrl = getRequestControl(PersistentSearchControl.DECODER); persistentSearch = new PersistentSearch( this, ctrl.getChangeTypes(), ctrl.getChangesOnly(), ctrl.getReturnECs()); } else if (OID_LDAP_SUBENTRIES.equals(oid)) { SubentriesControl subentriesControl = getRequestControl(SubentriesControl.DECODER); setReturnSubentriesOnly(subentriesControl.getVisibility()); } else if (OID_LDUP_SUBENTRIES.equals(oid)) { // Support for legacy draft-ietf-ldup-subentry. addAdditionalLogItem(AdditionalLogItem.keyOnly(getClass(), "obsoleteSubentryControl")); setReturnSubentriesOnly(true); } else if (OID_MATCHED_VALUES.equals(oid)) { MatchedValuesControl matchedValuesControl = getRequestControl(MatchedValuesControl.DECODER); setMatchedValuesControl(matchedValuesControl); } else if (OID_ACCOUNT_USABLE_CONTROL.equals(oid)) { setIncludeUsableControl(true); } else if (OID_REAL_ATTRS_ONLY.equals(oid)) { setRealAttributesOnly(true); } else if (OID_VIRTUAL_ATTRS_ONLY.equals(oid)) { setVirtualAttributesOnly(true); } else if (OID_GET_EFFECTIVE_RIGHTS.equals(oid) && DirectoryServer.isSupportedControl(OID_GET_EFFECTIVE_RIGHTS)) { // Do nothing here and let AciHandler deal with it. } // NYI -- Add support for additional controls. else if (c.isCritical() && !backendSupportsControl(oid)) { throw new DirectoryException( ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, ERR_SEARCH_UNSUPPORTED_CRITICAL_CONTROL.get(oid)); } } } }
private void processSearch(BooleanHolder executePostOpPlugins) throws CanceledOperationException { // Process the search base and filter to convert them from their raw forms // as provided by the client to the forms required for the rest of the // search processing. baseDN = getBaseDN(); filter = getFilter(); if (baseDN == null || filter == null) { return; } // Check to see if there are any controls in the request. If so, then // see if there is any special processing required. try { handleRequestControls(); } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } setResponseData(de); return; } // Check to see if the client has permission to perform the // search. // FIXME: for now assume that this will check all permission // pertinent to the operation. This includes proxy authorization // and any other controls specified. try { if (!AccessControlConfigManager.getInstance().getAccessControlHandler().isAllowed(this)) { setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS); appendErrorMessage(ERR_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String.valueOf(baseDN))); return; } } catch (DirectoryException e) { setResultCode(e.getResultCode()); appendErrorMessage(e.getMessageObject()); return; } // Check for a request to cancel this operation. checkIfCanceled(false); // Invoke the pre-operation search plugins. executePostOpPlugins.value = true; PluginResult.PreOperation preOpResult = DirectoryServer.getPluginConfigManager().invokePreOperationSearchPlugins(this); if (!preOpResult.continueProcessing()) { setResultCode(preOpResult.getResultCode()); appendErrorMessage(preOpResult.getErrorMessage()); setMatchedDN(preOpResult.getMatchedDN()); setReferralURLs(preOpResult.getReferralURLs()); return; } // Check for a request to cancel this operation. checkIfCanceled(false); // Get the backend that should hold the search base. If there is none, // then fail. if (backend == null) { setResultCode(ResultCode.NO_SUCH_OBJECT); appendErrorMessage(ERR_SEARCH_BASE_DOESNT_EXIST.get(String.valueOf(baseDN))); return; } // We'll set the result code to "success". If a problem occurs, then it // will be overwritten. setResultCode(ResultCode.SUCCESS); try { // If there's a persistent search, then register it with the server. boolean processSearchNow = true; if (persistentSearch != null) { // If we're only interested in changes, then we do not actually want // to process the search now. processSearchNow = !persistentSearch.isChangesOnly(); // The Core server maintains the count of concurrent persistent searches // so that all the backends (Remote and Local) are aware of it. Verify // with the core if we have already reached the threshold. if (!DirectoryServer.allowNewPersistentSearch()) { setResultCode(ResultCode.ADMIN_LIMIT_EXCEEDED); appendErrorMessage(ERR_MAX_PSEARCH_LIMIT_EXCEEDED.get()); return; } backend.registerPersistentSearch(persistentSearch); persistentSearch.enable(); } if (processSearchNow) { // Process the search in the backend and all its subordinates. backend.search(this); } } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.VERBOSE, de); } setResponseData(de); if (persistentSearch != null) { persistentSearch.cancel(); setSendResponse(true); } return; } catch (CanceledOperationException coe) { if (persistentSearch != null) { persistentSearch.cancel(); setSendResponse(true); } throw coe; } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } setResultCode(DirectoryServer.getServerErrorResultCode()); appendErrorMessage(ERR_SEARCH_BACKEND_EXCEPTION.get(getExceptionMessage(e))); if (persistentSearch != null) { persistentSearch.cancel(); setSendResponse(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. SASLMechanismHandler<?> saslHandler = DirectoryServer.getSASLMechanismHandler(saslMechanism); if (saslHandler == null) { throw new DirectoryException( ResultCode.AUTH_METHOD_NOT_SUPPORTED, ERR_BIND_OPERATION_UNKNOWN_SASL_MECHANISM.get(saslMechanism)); } // 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. Entry saslAuthUserEntry = getSASLAuthUserEntry(); if (DirectoryServer.lockdownMode()) { ResultCode resultCode = getResultCode(); if (resultCode != ResultCode.SASL_BIND_IN_PROGRESS && (resultCode != ResultCode.SUCCESS || saslAuthUserEntry == null || !ClientConnection.hasPrivilege(saslAuthUserEntry, BYPASS_LOCKDOWN))) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_REJECTED_LOCKDOWN_MODE.get()); } } // Create the password policy state object. if (saslAuthUserEntry != null) { setUserEntryDN(saslAuthUserEntry.getName()); // FIXME -- Need to have a way to enable debugging. authPolicyState = AuthenticationPolicyState.forUser(saslAuthUserEntry, false); if (authPolicyState.isPasswordPolicy()) { // Account is managed locally: perform password policy checks that can // be completed before we have checked authentication was successful. checkUnverifiedPasswordPolicyState(saslAuthUserEntry, saslHandler); } } // Determine whether the authentication was successful and perform // any remaining password policy processing accordingly. ResultCode resultCode = getResultCode(); if (resultCode == ResultCode.SUCCESS) { if (authPolicyState != null && authPolicyState.isPasswordPolicy()) { checkVerifiedPasswordPolicyState(saslAuthUserEntry, saslHandler); PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; if (saslHandler.isPasswordBased(saslMechanism) && pwPolicyState.mustChangePassword()) { mustChangePassword = true; } if (isFirstWarning) { pwPolicyState.setWarnedTime(); int numSeconds = pwPolicyState.getSecondsUntilExpiration(); LocalizableMessage m = WARN_BIND_PASSWORD_EXPIRING.get(secondsToTimeString(numSeconds)); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRING, saslAuthUserEntry, m, AccountStatusNotification.createProperties( pwPolicyState, false, numSeconds, null, null)); } if (isGraceLogin) { pwPolicyState.updateGraceLoginTimes(); } pwPolicyState.setLastLoginTime(); } // Set appropriate resource limits for the user (note that SASL ANONYMOUS // does not have a user). if (saslAuthUserEntry != null) { setResourceLimits(saslAuthUserEntry); } } else if (resultCode == ResultCode.SASL_BIND_IN_PROGRESS) { // FIXME -- Is any special processing needed here? return false; } else { if (authPolicyState != null && authPolicyState.isPasswordPolicy()) { PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; if (saslHandler.isPasswordBased(saslMechanism) && pwPolicyState.getAuthenticationPolicy().getLockoutFailureCount() > 0) { generateAccountStatusNotificationForLockedBindAccount(saslAuthUserEntry, pwPolicyState); } } } return true; }
/** * 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. ByteString simplePassword = getSimplePassword(); if (simplePassword == null || simplePassword.length() == 0) { 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. DN actualRootDN = DirectoryServer.getActualRootBindDN(bindDN); if (actualRootDN != null) { bindDN = actualRootDN; } Entry userEntry; try { userEntry = backend.getEntry(bindDN); } catch (DirectoryException de) { logger.traceException(de); userEntry = null; if (de.getResultCode() == ResultCode.REFERRAL) { // 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()); } } if (userEntry == null) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_OPERATION_UNKNOWN_USER.get()); } else { 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. authPolicyState = AuthenticationPolicyState.forUser(userEntry, false); if (authPolicyState.isPasswordPolicy()) { // Account is managed locally. PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; PasswordPolicy policy = pwPolicyState.getAuthenticationPolicy(); AttributeType pwType = policy.getPasswordAttribute(); List<Attribute> pwAttr = userEntry.getAttribute(pwType); if (pwAttr == null || pwAttr.isEmpty()) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_OPERATION_NO_PASSWORD.get()); } // Perform a number of password policy state checks for the // non-authenticated user. checkUnverifiedPasswordPolicyState(userEntry, null); // Invoke pre-operation plugins. if (!invokePreOpPlugins()) { return false; } // Determine whether the provided password matches any of the stored // passwords for the user. if (pwPolicyState.passwordMatches(simplePassword)) { setResultCode(ResultCode.SUCCESS); checkVerifiedPasswordPolicyState(userEntry, null); if (DirectoryServer.lockdownMode() && !ClientConnection.hasPrivilege(userEntry, BYPASS_LOCKDOWN)) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_REJECTED_LOCKDOWN_MODE.get()); } setAuthenticationInfo( new AuthenticationInfo( userEntry, getBindDN(), DirectoryServer.isRootDN(userEntry.getName()))); // Set resource limits for the authenticated user. setResourceLimits(userEntry); // Perform any remaining processing for a successful simple // authentication. pwPolicyState.handleDeprecatedStorageSchemes(simplePassword); pwPolicyState.clearFailureLockout(); if (isFirstWarning) { pwPolicyState.setWarnedTime(); int numSeconds = pwPolicyState.getSecondsUntilExpiration(); LocalizableMessage m = WARN_BIND_PASSWORD_EXPIRING.get(secondsToTimeString(numSeconds)); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRING, userEntry, m, AccountStatusNotification.createProperties( pwPolicyState, false, numSeconds, null, null)); } if (isGraceLogin) { pwPolicyState.updateGraceLoginTimes(); } pwPolicyState.setLastLoginTime(); } else { setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(ERR_BIND_OPERATION_WRONG_PASSWORD.get()); if (policy.getLockoutFailureCount() > 0) { generateAccountStatusNotificationForLockedBindAccount(userEntry, pwPolicyState); } } } else { // Check to see if the user is administratively disabled or locked. if (authPolicyState.isDisabled()) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_OPERATION_ACCOUNT_DISABLED.get()); } // Invoke pre-operation plugins. if (!invokePreOpPlugins()) { return false; } if (authPolicyState.passwordMatches(simplePassword)) { setResultCode(ResultCode.SUCCESS); if (DirectoryServer.lockdownMode() && !ClientConnection.hasPrivilege(userEntry, BYPASS_LOCKDOWN)) { throw new DirectoryException( ResultCode.INVALID_CREDENTIALS, ERR_BIND_REJECTED_LOCKDOWN_MODE.get()); } setAuthenticationInfo( new AuthenticationInfo( userEntry, getBindDN(), DirectoryServer.isRootDN(userEntry.getName()))); // Set resource limits for the authenticated user. setResourceLimits(userEntry); } else { setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(ERR_BIND_OPERATION_WRONG_PASSWORD.get()); } } return true; }
/** * Process this bind operation in a local backend. * * @param wfe The local backend work-flow element. */ public void processLocalBind(LocalBackendWorkflowElement wfe) { this.backend = wfe.getBackend(); // Initialize a number of variables for use during the bind processing. clientConnection = getClientConnection(); returnAuthzID = false; executePostOpPlugins = false; sizeLimit = DirectoryServer.getSizeLimit(); timeLimit = DirectoryServer.getTimeLimit(); lookthroughLimit = DirectoryServer.getLookthroughLimit(); idleTimeLimit = DirectoryServer.getIdleTimeLimit(); bindDN = getBindDN(); saslMechanism = getSASLMechanism(); authPolicyState = null; pwPolicyErrorType = null; pwPolicyControlRequested = false; isGraceLogin = false; isFirstWarning = false; mustChangePassword = false; pwPolicyWarningType = null; pwPolicyWarningValue = -1; pluginConfigManager = DirectoryServer.getPluginConfigManager(); processBind(); // Update the user's account with any password policy changes that may be // required. try { if (authPolicyState != null) { authPolicyState.finalizeStateAfterBind(); } } catch (DirectoryException de) { logger.traceException(de); setResponseData(de); } // Invoke the post-operation bind plugins. if (executePostOpPlugins) { PluginResult.PostOperation postOpResult = pluginConfigManager.invokePostOperationBindPlugins(this); if (!postOpResult.continueProcessing()) { setResultCode(postOpResult.getResultCode()); appendErrorMessage(postOpResult.getErrorMessage()); setMatchedDN(postOpResult.getMatchedDN()); setReferralURLs(postOpResult.getReferralURLs()); } } // Update the authentication information for the user. AuthenticationInfo authInfo = getAuthenticationInfo(); if (getResultCode() == ResultCode.SUCCESS && authInfo != null) { clientConnection.setAuthenticationInfo(authInfo); clientConnection.setSizeLimit(sizeLimit); clientConnection.setTimeLimit(timeLimit); clientConnection.setIdleTimeLimit(idleTimeLimit); clientConnection.setLookthroughLimit(lookthroughLimit); clientConnection.setMustChangePassword(mustChangePassword); if (returnAuthzID) { addResponseControl(new AuthorizationIdentityResponseControl(authInfo.getAuthorizationDN())); } } // 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) { PasswordPolicyResponseControl pwpControl = new PasswordPolicyResponseControl( pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType); addResponseControl(pwpControl); } else { if (pwPolicyErrorType == PasswordPolicyErrorType.PASSWORD_EXPIRED) { addResponseControl(new PasswordExpiredControl()); } else if (pwPolicyWarningType == PasswordPolicyWarningType.TIME_BEFORE_EXPIRATION) { addResponseControl(new PasswordExpiringControl(pwPolicyWarningValue)); } else if (mustChangePassword) { addResponseControl(new PasswordExpiredControl()); } } } else { if (pwPolicyControlRequested) { PasswordPolicyResponseControl pwpControl = new PasswordPolicyResponseControl( pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType); addResponseControl(pwpControl); } else { if (pwPolicyErrorType == PasswordPolicyErrorType.PASSWORD_EXPIRED) { addResponseControl(new PasswordExpiredControl()); } } } }