opends/src/messages/messages/extension.properties
@@ -1427,3 +1427,10 @@ character sets: %s MILD_ERR_STATICMEMBERS_CANNOT_DECODE_DN_582=An error occurred while \ attempting to decode member's DN %s of static group %s: %s MILD_ERR_SASL_ACCOUNT_NOT_LOCAL_583=SASL %s authentication \ is not supported for user %s because the account is not managed locally MILD_ERR_EXTOP_PASSMOD_ACCOUNT_NOT_LOCAL_584=Password modification is not \ supported for user %s because the account is not managed locally MILD_ERR_EXTOP_PWPSTATE_ACCOUNT_NOT_LOCAL_585=The password policy state \ extended operation is not supported for user %s because the account is not \ managed locally opends/src/server/org/opends/server/api/AuthenticationPolicy.java
@@ -29,7 +29,20 @@ import org.opends.server.types.DN; import static org.opends.messages.CoreMessages.*; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.ErrorLogger.logError; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; import java.util.List; import org.opends.messages.Message; import org.opends.server.core.DirectoryServer; import org.opends.server.loggers.debug.DebugLogger; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.*; import org.opends.server.util.TimeThread; @@ -39,6 +52,173 @@ public abstract class AuthenticationPolicy { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = DebugLogger.getTracer(); /** * Returns the authentication policy for the user provided user. The following * algorithm is used in order to obtain the appropriate authentication policy: * <ul> * <li>if the user entry contains the {@code ds-pwp-password-policy-dn} * attribute (whether real or virtual), then the referenced authentication * policy will be returned * <li>otherwise, a search is performed in order to find the nearest * applicable password policy sub-entry to the user entry, * <li>otherwise, the default password policy will be returned. * </ul> * * @param userEntry * The user entry. * @param useDefaultOnError * Indicates whether the server should fall back to using the default * password policy if there is a problem with the configured policy * for the user. * @return The password policy for the user. * @throws DirectoryException * If a problem occurs while attempting to determine the password * policy for the user. */ public final static AuthenticationPolicy forUser(Entry userEntry, boolean useDefaultOnError) throws DirectoryException { // First check to see if the ds-pwp-password-policy-dn is present. String userDNString = userEntry.getDN().toString(); AttributeType type = DirectoryServer.getAttributeType( OP_ATTR_PWPOLICY_POLICY_DN, true); List<Attribute> attrList = userEntry.getAttribute(type); if (attrList != null) { for (Attribute a : attrList) { if (a.isEmpty()) continue; AttributeValue v = a.iterator().next(); DN subentryDN; try { subentryDN = DN.decode(v.getValue()); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } if (debugEnabled()) { TRACER.debugError("Could not parse password policy subentry " + "DN %s for user %s: %s", v.getValue().toString(), userDNString, stackTraceToSingleLineString(e)); } Message message = ERR_PWPSTATE_CANNOT_DECODE_SUBENTRY_VALUE_AS_DN .get(v.getValue().toString(), userDNString, e.getMessage()); if (useDefaultOnError) { logError(message); return DirectoryServer.getDefaultPasswordPolicy(); } else { throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message, e); } } AuthenticationPolicy policy = DirectoryServer .getAuthenticationPolicy(subentryDN); if (policy == null) { if (debugEnabled()) { TRACER.debugError("Password policy subentry %s for user %s " + "is not defined in the Directory Server.", String.valueOf(subentryDN), userDNString); } Message message = ERR_PWPSTATE_NO_SUCH_POLICY.get(userDNString, String.valueOf(subentryDN)); if (useDefaultOnError) { logError(message); return DirectoryServer.getDefaultPasswordPolicy(); } else { throw new DirectoryException( DirectoryServer.getServerErrorResultCode(), message); } } if (debugEnabled()) { TRACER.debugInfo("Using password policy subentry %s for user %s.", String.valueOf(subentryDN), userDNString); } return policy; } } // The ds-pwp-password-policy-dn attribute was not present, so instead // search for the nearest applicable sub-entry. List<SubEntry> pwpSubEntries = DirectoryServer.getSubentryManager() .getSubentries(userEntry); if ((pwpSubEntries != null) && (!pwpSubEntries.isEmpty())) { for (SubEntry subentry : pwpSubEntries) { try { if (subentry.getEntry().isPasswordPolicySubentry()) { AuthenticationPolicy policy = DirectoryServer .getAuthenticationPolicy(subentry.getDN()); if (policy == null) { // This shouldn't happen but if it does debug log // this problem and fall back to default policy. if (debugEnabled()) { TRACER.debugError("Found unknown password policy subentry " + "DN %s for user %s", subentry.getDN().toString(), userDNString); } break; } return policy; } } catch (Exception e) { if (debugEnabled()) { TRACER.debugError("Could not parse password policy subentry " + "DN %s for user %s: %s", subentry.getDN().toString(), userDNString, stackTraceToSingleLineString(e)); } } } } // No authentication policy found, so use the global default. if (debugEnabled()) { TRACER.debugInfo("Using the default password policy for user %s", userDNString); } return DirectoryServer.getDefaultPasswordPolicy(); } /** * Creates a new abstract authentication policy. */ protected AuthenticationPolicy() @@ -60,6 +240,68 @@ /** * Returns {@code true} if this authentication policy is a password policy and * the methods {@link #createAuthenticationPolicyState(Entry)} and * {@link #createAuthenticationPolicyState(Entry, long)} will return a * {@code PasswordPolicyState}. * <p> * The default implementation is to return {@code false}. * * @return {@code true} if this authentication policy is a password policy, * otherwise {@code false}. */ public boolean isPasswordPolicy() { return false; } /** * Returns the authentication policy state object for the provided user using * the current time as the basis for all time-based state logic (such as * expiring passwords). * <p> * The default implementation is to call * {@link #createAuthenticationPolicyState(Entry, long)} with the current * time. * * @param userEntry * The user's entry. * @return The authentication policy state object for the provided user. * @throws DirectoryException * If a problem occurs while attempting to initialize the state * object from the provided user entry. */ public AuthenticationPolicyState createAuthenticationPolicyState( Entry userEntry) throws DirectoryException { return createAuthenticationPolicyState(userEntry, TimeThread.getTime()); } /** * Returns an authentication policy state object for the provided user using * the specified time as the basis for all time-based state logic (such as * expiring passwords). * * @param userEntry * The user's entry. * @param time * The time since the epoch to use for all time-based state logic * (such as expiring passwords). * @return The authentication policy state object for the provided user. * @throws DirectoryException * If a problem occurs while attempting to initialize the state * object from the provided user entry. */ public abstract AuthenticationPolicyState createAuthenticationPolicyState( Entry userEntry, long time) throws DirectoryException; /** * Performs any necessary work to finalize this authentication policy. * <p> * The default implementation is to do nothing. opends/src/server/org/opends/server/api/AuthenticationPolicyState.java
New file @@ -0,0 +1,143 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2011 ForgeRock AS. */ package org.opends.server.api; import org.opends.server.types.ByteString; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; /** * The authentication policy context associated with a user's entry, which is * responsible for managing the user's account, their password, as well as * authenticating the user. */ public abstract class AuthenticationPolicyState { /** * Returns the authentication policy state for the user provided user. This * method is equivalent to the following: * * <pre> * AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry, * useDefaultOnError); * AuthenticationPolicyState state = policy * .createAuthenticationPolicyState(userEntry); * </pre> * * See the documentation of {@link AuthenticationPolicy#forUser} for a * description of the algorithm used to find a user's authentication policy. * * @param userEntry * The user entry. * @param useDefaultOnError * Indicates whether the server should fall back to using the default * password policy if there is a problem with the configured policy * for the user. * @return The password policy for the user. * @throws DirectoryException * If a problem occurs while attempting to determine the password * policy for the user. * @see AuthenticationPolicy#forUser(Entry, boolean) */ public final static AuthenticationPolicyState forUser(Entry userEntry, boolean useDefaultOnError) throws DirectoryException { AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry, useDefaultOnError); return policy.createAuthenticationPolicyState(userEntry); } /** * Creates a new abstract authentication policy context. */ protected AuthenticationPolicyState() { // No implementation required. } /** * Returns {@code true} if the provided password value matches any of the * user's passwords. * * @param password * The user-provided password to verify. * @return {@code true} if the provided password value matches any of the * user's passwords. * @throws DirectoryException * If verification unexpectedly failed. */ public abstract boolean passwordMatches(ByteString password) throws DirectoryException; /** * Returns the authentication policy associated with this state. * * @return The authentication policy associated with this state. */ public abstract AuthenticationPolicy getAuthenticationPolicy(); /** * Performs any finalization required after a bind operation has completed. * Implementations may perform internal operations in order to persist * internal state to the user's entry if needed. * * @throws DirectoryException * If a problem occurs during finalization. */ public void finalizeStateAfterBind() throws DirectoryException { // Do nothing by default. } /** * Returns {@code true} if this authentication policy state is associated with * a password policy and the method {@link #getAuthenticationPolicy} will * return a {@code PasswordPolicy}. * * @return {@code true} if this authentication policy state is associated with * a password policy, otherwise {@code false}. */ public boolean isPasswordPolicy() { return getAuthenticationPolicy().isPasswordPolicy(); } } opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java
@@ -23,6 +23,7 @@ * * * Copyright 2006-2009 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. */ package org.opends.server.controls; import org.opends.messages.Message; @@ -189,12 +190,7 @@ */ public PasswordPolicyResponseControl() { super(OID_PASSWORD_POLICY_CONTROL, false); warningType = null; errorType = null; warningValue = -1; this(false, null, -1, null); } opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
@@ -23,6 +23,7 @@ * * * Copyright 2006-2008 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. */ package org.opends.server.controls; import org.opends.messages.Message; @@ -31,6 +32,7 @@ import java.util.concurrent.locks.Lock; import java.io.IOException; import org.opends.server.api.AuthenticationPolicy; import org.opends.server.core.DirectoryServer; import org.opends.server.core.PasswordPolicyState; import org.opends.server.protocols.asn1.*; @@ -323,18 +325,24 @@ // FIXME -- We should provide some mechanism for enabling debug // processing. PasswordPolicyState pwpState = new PasswordPolicyState(userEntry, false); AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry, false); if (policy.isPasswordPolicy()) { PasswordPolicyState pwpState = (PasswordPolicyState) policy .createAuthenticationPolicyState(userEntry); if (pwpState.isDisabled() || pwpState.isAccountExpired() || pwpState.lockedDueToFailures() || pwpState.lockedDueToIdleInterval() || pwpState.lockedDueToMaximumResetAge() || pwpState.isPasswordExpired()) { Message message = ERR_PROXYAUTH1_UNUSABLE_ACCOUNT.get(String.valueOf(authzDN)); throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message); Message message = ERR_PROXYAUTH1_UNUSABLE_ACCOUNT.get(String .valueOf(authzDN)); throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message); } } // If we've made it here, then the user is acceptable. return userEntry; opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
@@ -23,6 +23,7 @@ * * * Copyright 2006-2008 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. */ package org.opends.server.controls; import org.opends.messages.Message; @@ -32,6 +33,7 @@ import java.util.concurrent.locks.Lock; import java.io.IOException; import org.opends.server.api.AuthenticationPolicy; import org.opends.server.api.IdentityMapper; import org.opends.server.core.DirectoryServer; import org.opends.server.core.PasswordPolicyState; @@ -274,20 +276,7 @@ // FIXME -- We should provide some mechanism for enabling debug // processing. PasswordPolicyState pwpState = new PasswordPolicyState(userEntry, false); if (pwpState.isDisabled() || pwpState.isAccountExpired() || pwpState.lockedDueToFailures() || pwpState.lockedDueToIdleInterval() || pwpState.lockedDueToMaximumResetAge() || pwpState.isPasswordExpired()) { Message message = ERR_PROXYAUTH2_UNUSABLE_ACCOUNT.get(String.valueOf(authzDN)); throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message); } checkAccountIsUsable(userEntry); // If we've made it here, then the user is acceptable. return userEntry; @@ -327,19 +316,7 @@ { // FIXME -- We should provide some mechanism for enabling debug // processing. PasswordPolicyState pwpState = new PasswordPolicyState(userEntry, false); if (pwpState.isDisabled() || pwpState.isAccountExpired() || pwpState.lockedDueToFailures() || pwpState.lockedDueToIdleInterval() || pwpState.lockedDueToMaximumResetAge() || pwpState.isPasswordExpired()) { Message message = ERR_PROXYAUTH2_UNUSABLE_ACCOUNT.get( String.valueOf(userEntry.getDN())); throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message); } checkAccountIsUsable(userEntry); return userEntry; } @@ -353,6 +330,31 @@ private void checkAccountIsUsable(Entry userEntry) throws DirectoryException { AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry, false); if (policy.isPasswordPolicy()) { PasswordPolicyState pwpState = (PasswordPolicyState) policy .createAuthenticationPolicyState(userEntry); if (pwpState.isDisabled() || pwpState.isAccountExpired() || pwpState.lockedDueToFailures() || pwpState.lockedDueToIdleInterval() || pwpState.lockedDueToMaximumResetAge() || pwpState.isPasswordExpired()) { Message message = ERR_PROXYAUTH2_UNUSABLE_ACCOUNT.get(String .valueOf(userEntry.getDN())); throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message); } } } /** * Appends a string representation of this proxied auth v2 control to the * provided buffer. opends/src/server/org/opends/server/core/CoreConfigManager.java
@@ -420,7 +420,7 @@ DN defaultPasswordPolicyDN = configuration.getDefaultPasswordPolicyDN(); AuthenticationPolicy policy = DirectoryServer .getAuthenticationPolicy(defaultPasswordPolicyDN); if (!(policy instanceof PasswordPolicy)) if (!policy.isPasswordPolicy()) { Message message = ERR_CONFIG_PWPOLICY_CANNOT_CHANGE_DEFAULT_POLICY_WRONG_TYPE opends/src/server/org/opends/server/core/PasswordPolicy.java
@@ -37,6 +37,9 @@ import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn.*; import org.opends.server.api.*; import org.opends.server.types.AttributeType; import org.opends.server.types.DN; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; @@ -58,6 +61,13 @@ /** * {@inheritDoc} */ public abstract DN getDN(); /** * Indicates whether the associated password attribute uses the auth password * syntax. * @@ -607,4 +617,24 @@ */ public abstract StateUpdateFailurePolicy getStateUpdateFailurePolicy(); /** * {@inheritDoc} */ public boolean isPasswordPolicy() { return true; } /** * {@inheritDoc} */ public PasswordPolicyState createAuthenticationPolicyState(Entry userEntry, long time) throws DirectoryException { return new PasswordPolicyState(this, userEntry, time); } } opends/src/server/org/opends/server/core/PasswordPolicyState.java
@@ -46,10 +46,7 @@ import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn; import org.opends.server.api.AccountStatusNotificationHandler; import org.opends.server.api.PasswordGenerator; import org.opends.server.api.PasswordStorageScheme; import org.opends.server.api.PasswordValidator; import org.opends.server.api.*; import org.opends.server.loggers.ErrorLogger; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.protocols.internal.InternalClientConnection; @@ -58,7 +55,6 @@ import org.opends.server.schema.GeneralizedTimeSyntax; import org.opends.server.schema.UserPasswordSyntax; import org.opends.server.types.*; import org.opends.server.util.TimeThread; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.debug.DebugLogger.*; @@ -72,7 +68,7 @@ * This class provides a data structure for holding password policy state * information for a user account. */ public final class PasswordPolicyState public final class PasswordPolicyState extends AuthenticationPolicyState { /** * The tracer object for the debug logger. @@ -84,10 +80,6 @@ // The user entry with which this state information is associated. private final Entry userEntry; // Indicates whether the user entry itself should be updated or if the updates // should be stored as modifications. private final boolean updateEntry; // The string representation of the user's DN. private final String userDNString; @@ -162,56 +154,29 @@ /** * Creates a new password policy state object with the provided information. * * @param userEntry The entry with the user account. * @param updateEntry Indicates whether changes should update the provided * user entry directly or whether they should be * collected as a set of modifications. * * @throws DirectoryException If a problem occurs while attempting to * determine the password policy for the user or * perform any other state initialization. */ public PasswordPolicyState(Entry userEntry, boolean updateEntry) throws DirectoryException { this(userEntry, updateEntry, TimeThread.getTime(), false); } /** * Creates a new password policy state object with the provided information. * Note that this version of the constructor should only be used for testing * purposes when the tests should be evaluated with a fixed time rather than * the actual current time. For all other purposes, the other constructor * should be used. * * @param userEntry The entry with the user account. * @param updateEntry Indicates whether changes should update the * provided user entry directly or whether they * should be collected as a set of modifications. * @param currentTime The time to use as the current time for all * time-related determinations. * @param useDefaultOnError Indicates whether the server should fall back to * using the default password policy if there is a * problem with the configured policy for the user. * * @throws DirectoryException If a problem occurs while attempting to * determine the password policy for the user or * perform any other state initialization. * @param policy * The password policy associated with the state. * @param userEntry * The entry with the user account. * @param currentTime * The time to use as the current time for all time-related * determinations. * @throws DirectoryException * If a problem occurs while attempting to determine the password * policy for the user or perform any other state initialization. */ public PasswordPolicyState(Entry userEntry, boolean updateEntry, long currentTime, boolean useDefaultOnError) PasswordPolicyState(PasswordPolicy policy, Entry userEntry, long currentTime) throws DirectoryException { this.userEntry = userEntry; this.updateEntry = updateEntry; this.currentTime = currentTime; userDNString = userEntry.getDN().toString(); passwordPolicy = getPasswordPolicy(this.userEntry, useDefaultOnError); this.userDNString = userEntry.getDN().toString(); this.passwordPolicy = policy; // Get the password changed time for the user. AttributeType type @@ -251,163 +216,6 @@ /** * Retrieves the password policy for the user. If the user entry contains the * ds-pwp-password-policy-dn attribute (whether real or virtual), that * password policy is returned, otherwise applicable to the user entry * subentry password policy is returned, if any, otherwise the default * password policy is returned. * * @param userEntry The user entry. * @param useDefaultOnError Indicates whether the server should fall back to * using the default password policy if there is a * problem with the configured policy for the user. * * @return The password policy for the user. * * @throws DirectoryException If a problem occurs while attempting to * determine the password policy for the user. */ public static PasswordPolicy getPasswordPolicy(Entry userEntry, boolean useDefaultOnError) throws DirectoryException { String userDNString = userEntry.getDN().toString(); AttributeType type = DirectoryServer.getAttributeType( OP_ATTR_PWPOLICY_POLICY_DN, true); List<Attribute> attrList = userEntry.getAttribute(type); if (attrList != null) { for (Attribute a : attrList) { if (a.isEmpty()) continue; AttributeValue v = a.iterator().next(); DN subentryDN; try { subentryDN = DN.decode(v.getValue()); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } if (debugEnabled()) { TRACER.debugError("Could not parse password policy subentry " + "DN %s for user %s: %s", v.getValue().toString(), userDNString, stackTraceToSingleLineString(e)); } Message message = ERR_PWPSTATE_CANNOT_DECODE_SUBENTRY_VALUE_AS_DN.get( v.getValue().toString(), userDNString, e.getMessage()); if (useDefaultOnError) { ErrorLogger.logError(message); return DirectoryServer.getDefaultPasswordPolicy(); } else { throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message, e); } } PasswordPolicy policy = (PasswordPolicy) DirectoryServer .getAuthenticationPolicy(subentryDN); if (policy == null) { if (debugEnabled()) { TRACER.debugError("Password policy subentry %s for user %s " + "is not defined in the Directory Server.", String.valueOf(subentryDN), userDNString); } Message message = ERR_PWPSTATE_NO_SUCH_POLICY.get( userDNString, String.valueOf(subentryDN)); if (useDefaultOnError) { ErrorLogger.logError(message); return DirectoryServer.getDefaultPasswordPolicy(); } else { throw new DirectoryException( DirectoryServer.getServerErrorResultCode(), message); } } if (debugEnabled()) { TRACER.debugInfo("Using password policy subentry %s for user %s.", String.valueOf(subentryDN), userDNString); } return policy; } } // No attribute defined password policy: try locating and using the // closest to this entry password policy subentry defined, if any. List<SubEntry> pwpSubEntries = DirectoryServer.getSubentryManager().getSubentries(userEntry); if ((pwpSubEntries != null) && (!pwpSubEntries.isEmpty())) { for (SubEntry subentry : pwpSubEntries) { try { if (subentry.getEntry().isPasswordPolicySubentry()) { PasswordPolicy policy = (PasswordPolicy) DirectoryServer .getAuthenticationPolicy(subentry.getDN()); if (policy == null) { // This shouldnt happen but if it does debug log // this problem and fall back to default policy. if (debugEnabled()) { TRACER.debugError( "Found unknown password policy subentry " + "DN %s for user %s", subentry.getDN().toString(), userDNString); } break; } return policy; } } catch (Exception e) { if (debugEnabled()) { TRACER.debugError("Could not parse password policy subentry " + "DN %s for user %s: %s", subentry.getDN().toString(), userDNString, stackTraceToSingleLineString(e)); } } } } // There is no policy subentry defined: use the default. if (debugEnabled()) { TRACER.debugInfo("Using the default password policy for user %s", userDNString); } return DirectoryServer.getDefaultPasswordPolicy(); } /** * Retrieves the value of the specified attribute as a string. * * @param attributeType The attribute type whose value should be retrieved. @@ -667,11 +475,9 @@ /** * Retrieves the password policy associated with this state information. * * @return The password policy associated with this state information. * {@inheritDoc} */ public PasswordPolicy getPolicy() public PasswordPolicy getAuthenticationPolicy() { return passwordPolicy; } @@ -770,18 +576,9 @@ Attribute a = Attributes.create(OP_ATTR_PWPOLICY_CHANGED_TIME, timeValue); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(a.getAttributeType(), attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } } } @@ -801,15 +598,8 @@ AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_CHANGED_TIME_LC, true); if (updateEntry) { userEntry.removeAttribute(type); } else { Attribute a = Attributes.empty(type); modifications.add(new Modification(ModificationType.REPLACE, a, true)); } // Fall back to using the entry creation time as the password changed time, @@ -930,32 +720,15 @@ if (isDisabled) { Attribute a = Attributes.create(type, String.valueOf(true)); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } } else { // erase if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } } @@ -1089,18 +862,9 @@ true); Attribute a = Attributes.create(type, timeStr); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } } } @@ -1121,16 +885,9 @@ DirectoryServer.getAttributeType(OP_ATTR_ACCOUNT_EXPIRATION_TIME, true); if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } @@ -1187,15 +944,8 @@ authFailureTimes = new ArrayList<Long>(); if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } return authFailureTimes; } @@ -1245,27 +995,6 @@ if (valuesToRemove != null) { if (updateEntry) { if (authFailureTimes.isEmpty()) { userEntry.removeAttribute(type); } else { AttributeBuilder builder = new AttributeBuilder(type); for (Long l : authFailureTimes) { builder.add( AttributeValues.create(type, GeneralizedTimeSyntax.format(l))); } ArrayList<Attribute> keepList = new ArrayList<Attribute>(1); keepList.add(builder.toAttribute()); userEntry.putAttribute(type, keepList); } } else { AttributeBuilder builder = new AttributeBuilder(type); builder.addAll(valuesToRemove); Attribute a = builder.toAttribute(); @@ -1273,7 +1002,6 @@ true)); } } } if (debugEnabled()) { @@ -1344,14 +1072,7 @@ Attribute addAttr = Attributes.create(type, AttributeValues.create(type, GeneralizedTimeSyntax.format(highestFailureTime))); if (updateEntry) { userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.ADD, addAttr, true)); } // Now check to see if there have been sufficient failures to lock the // account. @@ -1403,16 +1124,7 @@ } Attribute a = builder.toAttribute(); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } // Now check to see if there have been sufficient failures to lock the // account. @@ -1458,16 +1170,9 @@ OP_ATTR_PWPOLICY_FAILURE_TIME); } if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } /** @@ -1544,17 +1249,8 @@ Attribute a = Attributes.create(type, AttributeValues.create(type, GeneralizedTimeSyntax.format(failureLockedTime))); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } } @@ -1585,16 +1281,9 @@ OP_ATTR_PWPOLICY_LOCKED_TIME); } if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } @@ -1936,16 +1625,7 @@ Attribute a = Attributes.create(type, timestamp); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } if (debugEnabled()) { @@ -1972,16 +1652,9 @@ AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_LAST_LOGIN_TIME, true); if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } @@ -2195,31 +1868,14 @@ if (mustChangePassword) { Attribute a = Attributes.create(type, String.valueOf(true)); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } } else { // erase if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } } @@ -2732,18 +2388,9 @@ String timeValue = GeneralizedTimeSyntax.format(requiredChangeTime); Attribute a = Attributes.create(type, timeValue); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } } } @@ -2763,16 +2410,9 @@ AttributeType type = DirectoryServer.getAttributeType( OP_ATTR_PWPOLICY_CHANGED_BY_REQUIRED_TIME, true); if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } @@ -2861,16 +2501,7 @@ Attribute a = Attributes.create(type, GeneralizedTimeSyntax .createGeneralizedTimeValue(currentTime)); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } if (debugEnabled()) { @@ -2898,15 +2529,8 @@ AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_WARNED_TIME, true); if (updateEntry) { userEntry.removeAttribute(type); } else { Attribute a = Attributes.empty(type); modifications.add(new Modification(ModificationType.REPLACE, a, true)); } if (debugEnabled()) { @@ -2955,17 +2579,10 @@ graceLoginTimes = new ArrayList<Long>(); if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } } if (debugEnabled()) @@ -3036,28 +2653,11 @@ OP_ATTR_PWPOLICY_GRACE_LOGIN_TIME); } if (updateEntry) { AttributeBuilder builder = new AttributeBuilder(type); for (Long l : graceTimes) { builder.add(AttributeValues.create(type, GeneralizedTimeSyntax .format(l))); } ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(builder.toAttribute()); userEntry.putAttribute(type, attrList); } else { Attribute addAttr = Attributes.create(type, AttributeValues.create( type, GeneralizedTimeSyntax.format(highestGraceTime))); modifications.add(new Modification(ModificationType.ADD, addAttr, true)); } } @@ -3094,18 +2694,8 @@ } Attribute a = builder.toAttribute(); if (updateEntry) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(a); userEntry.putAttribute(type, attrList); } else { modifications.add(new Modification(ModificationType.REPLACE, a, true)); } } @@ -3135,16 +2725,9 @@ OP_ATTR_PWPOLICY_GRACE_LOGIN_TIME); } if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } @@ -3240,13 +2823,7 @@ /** * Indicates whether the provided password value matches any of the stored * passwords in the user entry. * * @param password The user-provided password to verify. * * @return <CODE>true</CODE> if the provided password matches any of the * stored password values, or <CODE>false</CODE> if not. * {@inheritDoc} */ public boolean passwordMatches(ByteString password) { @@ -3644,16 +3221,6 @@ return; } if (updateEntry) { AttributeBuilder builder = new AttributeBuilder(type); builder.addAll(updatedValues); ArrayList<Attribute> newList = new ArrayList<Attribute>(1); newList.add(builder.toAttribute()); userEntry.putAttribute(type, newList); } else { AttributeBuilder builder = new AttributeBuilder(type); builder.addAll(removedValues); Attribute a = builder.toAttribute(); @@ -3666,7 +3233,6 @@ Attribute a2 = builder.toAttribute(); modifications.add(new Modification(ModificationType.ADD, a2, true)); } } if (debugEnabled()) { @@ -4155,18 +3721,6 @@ // Apply the changes, either by adding modifications or by directly updating // the entry. if (updateEntry) { LinkedList<AttributeValue> valueList = new LinkedList<AttributeValue>(); for (Attribute a : removeAttrs) { userEntry.removeAttribute(a, valueList); } userEntry.addAttribute(newHistAttr, valueList); } else { for (Attribute a : removeAttrs) { modifications.add(new Modification(ModificationType.DELETE, a, true)); @@ -4175,7 +3729,6 @@ modifications.add(new Modification(ModificationType.ADD, newHistAttr, true)); } } @@ -4221,16 +3774,9 @@ AttributeType type = DirectoryServer.getAttributeType( OP_ATTR_PWPOLICY_HISTORY_LC, true); if (updateEntry) { userEntry.removeAttribute(type); } else { modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true)); } } @@ -4322,13 +3868,9 @@ /** * Performs an internal modification to update the user's entry, if necessary. * This will do nothing if no modifications are required. * * @throws DirectoryException If a problem occurs while processing the * internal modification. * {@inheritDoc} */ public void updateUserEntry() public void finalizeStateAfterBind() throws DirectoryException { // If there are no modifications, then there's nothing to do. opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -36,6 +36,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import org.opends.server.api.AuthenticationPolicy; import org.opends.server.api.ClientConnection; import org.opends.server.api.plugin.PluginResult; import org.opends.server.controls.AccountUsableResponseControl; @@ -646,13 +648,18 @@ try { // FIXME -- Need a way to enable PWP debugging. PasswordPolicyState pwpState = new PasswordPolicyState(entry, false); AuthenticationPolicy policy = AuthenticationPolicy .forUser(entry, false); if (policy.isPasswordPolicy()) { PasswordPolicyState pwpState = (PasswordPolicyState) policy .createAuthenticationPolicyState(entry); boolean isInactive = pwpState.isDisabled() || pwpState.isAccountExpired(); boolean isLocked = pwpState.lockedDueToFailures() || pwpState.lockedDueToMaximumResetAge() || pwpState.lockedDueToIdleInterval(); boolean isInactive = pwpState.isDisabled() || pwpState.isAccountExpired(); boolean isLocked = pwpState.lockedDueToFailures() || pwpState.lockedDueToMaximumResetAge() || pwpState.lockedDueToIdleInterval(); boolean isReset = pwpState.mustChangePassword(); boolean isExpired = pwpState.isPasswordExpired(); @@ -666,7 +673,8 @@ controls = new ArrayList<Control>(1); } controls.add(new AccountUsableResponseControl(isInactive, isReset, controls .add(new AccountUsableResponseControl(isInactive, isReset, isExpired, remainingGraceLogins, isLocked, secondsBeforeUnlock)); } @@ -682,6 +690,7 @@ secondsBeforeExpiration)); } } } catch (Exception e) { if (debugEnabled()) opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
@@ -23,6 +23,7 @@ * * * Copyright 2006-2009 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. */ package org.opends.server.extensions; @@ -40,9 +41,7 @@ import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.server.CramMD5SASLMechanismHandlerCfg; import org.opends.server.admin.std.server.SASLMechanismHandlerCfg; import org.opends.server.api.ClientConnection; import org.opends.server.api.IdentityMapper; import org.opends.server.api.SASLMechanismHandler; import org.opends.server.api.*; import org.opends.server.config.ConfigException; import org.opends.server.core.BindOperation; import org.opends.server.core.DirectoryServer; @@ -441,8 +440,19 @@ List<ByteString> clearPasswords; try { PasswordPolicyState pwPolicyState = new PasswordPolicyState(userEntry, false); AuthenticationPolicyState authState = AuthenticationPolicyState.forUser( userEntry, false); if (!authState.isPasswordPolicy()) { bindOperation.setResultCode(ResultCode.INAPPROPRIATE_AUTHENTICATION); Message message = ERR_SASL_ACCOUNT_NOT_LOCAL .get(SASL_MECHANISM_CRAM_MD5, String.valueOf(userEntry.getDN())); bindOperation.setAuthFailureReason(message); return; } PasswordPolicyState pwPolicyState = (PasswordPolicyState) authState; clearPasswords = pwPolicyState.getClearPasswords(); if ((clearPasswords == null) || clearPasswords.isEmpty()) { opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
@@ -40,10 +40,7 @@ import org.opends.server.admin.std.server.ExtendedOperationHandlerCfg; import org.opends.server.admin.std.server. PasswordModifyExtendedOperationHandlerCfg; import org.opends.server.api.ClientConnection; import org.opends.server.api.ExtendedOperationHandler; import org.opends.server.api.IdentityMapper; import org.opends.server.api.PasswordStorageScheme; import org.opends.server.api.*; import org.opends.server.config.ConfigException; import org.opends.server.controls.PasswordPolicyResponseControl; import org.opends.server.controls.PasswordPolicyWarningType; @@ -514,7 +511,17 @@ PasswordPolicyState pwPolicyState; try { pwPolicyState = new PasswordPolicyState(userEntry, false); AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry, false); if (!policy.isPasswordPolicy()) { operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); operation.appendErrorMessage(ERR_EXTOP_PASSMOD_ACCOUNT_NOT_LOCAL .get(String.valueOf(userDN))); return; } pwPolicyState = (PasswordPolicyState) policy .createAuthenticationPolicyState(userEntry); } catch (DirectoryException de) { @@ -533,6 +540,7 @@ } // Determine whether the user is changing his own password or if it's an // administrative reset. If it's an administrative reset, then the // requester must have the PASSWORD_RESET privilege. @@ -614,7 +622,7 @@ if (oldPassword == null) { if (selfChange && pwPolicyState.getPolicy() && pwPolicyState.getAuthenticationPolicy() .isPasswordChangeRequiresCurrentPassword()) { operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); @@ -637,8 +645,9 @@ } else { if (pwPolicyState.getPolicy().isRequireSecureAuthentication() && (! operation.getClientConnection().isSecure())) if (pwPolicyState.getAuthenticationPolicy() .isRequireSecureAuthentication() && (!operation.getClientConnection().isSecure())) { operation.setResultCode(ResultCode.CONFIDENTIALITY_REQUIRED); operation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue( @@ -674,8 +683,9 @@ // If it is a self password change and we don't allow that, then reject // the request. if (selfChange && (! pwPolicyState.getPolicy().isAllowUserPasswordChanges())) if (selfChange && (!pwPolicyState.getAuthenticationPolicy() .isAllowUserPasswordChanges())) { if (pwPolicyRequested) { @@ -697,10 +707,10 @@ // If we require secure password changes and the connection isn't secure, // then reject the request. if (pwPolicyState.getPolicy().isRequireSecurePasswordChanges() && (! operation.getClientConnection().isSecure())) if (pwPolicyState.getAuthenticationPolicy() .isRequireSecurePasswordChanges() && (!operation.getClientConnection().isSecure())) { operation.setResultCode(ResultCode.CONFIDENTIALITY_REQUIRED); operation.appendErrorMessage( @@ -733,8 +743,8 @@ // If the user's password is expired and it's a self-change request, then // see if that's OK. if ((selfChange && pwPolicyState.isPasswordExpired() && (! pwPolicyState.getPolicy().isAllowExpiredPasswordChanges()))) if ((selfChange && pwPolicyState.isPasswordExpired() && (!pwPolicyState .getAuthenticationPolicy().isAllowExpiredPasswordChanges()))) { if (pwPolicyRequested) { @@ -800,7 +810,8 @@ // by an internal operation or during synchronization, so we don't // need to check for those cases. isPreEncoded = true; if (! pwPolicyState.getPolicy().isAllowPreEncodedPasswords()) if (!pwPolicyState.getAuthenticationPolicy() .isAllowPreEncodedPasswords()) { operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); @@ -813,7 +824,7 @@ { // Run the new password through the set of password validators. if (selfChange || (!pwPolicyState.getPolicy() || (!pwPolicyState.getAuthenticationPolicy() .isSkipValidationForAdministrators())) { HashSet<ByteString> clearPasswords; @@ -866,7 +877,7 @@ { if (pwPolicyState.isPasswordInHistory(newPassword)) { if (selfChange || (! pwPolicyState.getPolicy(). if (selfChange || (! pwPolicyState.getAuthenticationPolicy(). isSkipValidationForAdministrators())) { operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); @@ -918,7 +929,8 @@ // If the current password was provided, then remove all matching values // from the user's entry and replace them with the new password. // Otherwise replace all password values. AttributeType attrType = pwPolicyState.getPolicy().getPasswordAttribute(); AttributeType attrType = pwPolicyState.getAuthenticationPolicy() .getPasswordAttribute(); List<Modification> modList = new ArrayList<Modification>(); if (oldPassword != null) { @@ -926,7 +938,7 @@ Set<AttributeValue> existingValues = pwPolicyState.getPasswordValues(); LinkedHashSet<AttributeValue> deleteValues = new LinkedHashSet<AttributeValue>(existingValues.size()); if (pwPolicyState.getPolicy().isAuthPasswordSyntax()) if (pwPolicyState.getAuthenticationPolicy().isAuthPasswordSyntax()) { for (AttributeValue v : existingValues) { @@ -1056,7 +1068,7 @@ else { pwPolicyState.setMustChangePassword( pwPolicyState.getPolicy().isForceChangeOnReset()); pwPolicyState.getAuthenticationPolicy().isForceChangeOnReset()); } @@ -1133,7 +1145,7 @@ // Save attachments for post-op plugins (e.g. Samba password plugin). operation.setAttachment(AUTHZ_DN_ATTACHMENT, userDN); operation.setAttachment(PWD_ATTRIBUTE_ATTACHMENT, pwPolicyState .getPolicy().getPasswordAttribute()); .getAuthenticationPolicy().getPasswordAttribute()); if (!isPreEncoded) { operation.setAttachment(CLEAR_PWD_ATTACHMENT, newPassword); opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
@@ -37,6 +37,7 @@ import org.opends.messages.Message; import org.opends.server.admin.std.server. PasswordPolicyStateExtendedOperationHandlerCfg; import org.opends.server.api.AuthenticationPolicy; import org.opends.server.api.ClientConnection; import org.opends.server.api.ExtendedOperationHandler; import org.opends.server.config.ConfigException; @@ -600,11 +601,19 @@ } // Get the password policy state for the user entry. PasswordPolicyState pwpState; PasswordPolicy policy; try { pwpState = new PasswordPolicyState(userEntry, false); policy = pwpState.getPolicy(); AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry, false); if (!policy.isPasswordPolicy()) { operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); operation.appendErrorMessage(ERR_EXTOP_PWPSTATE_ACCOUNT_NOT_LOCAL .get(String.valueOf(userEntry))); return; } pwpState = (PasswordPolicyState) policy .createAuthenticationPolicyState(userEntry); } catch (DirectoryException de) { @@ -617,6 +626,7 @@ return; } PasswordPolicy policy = pwpState.getAuthenticationPolicy(); isAccountSetDisabled = false; isAccountSetEnabled = false; // Create a hash set that will be used to hold the types of the return @@ -708,8 +718,9 @@ // And it's updated password policy state try { pwpState = new PasswordPolicyState(userEntry, false); policy = pwpState.getPolicy(); // We should not need to re-fetch the password policy. pwpState = (PasswordPolicyState) policy .createAuthenticationPolicyState(userEntry); } catch (DirectoryException de) { opends/src/server/org/opends/server/extensions/PasswordPolicySubentryVirtualAttributeProvider.java
@@ -34,12 +34,11 @@ import org.opends.messages.Message; import org.opends.server.admin.std.server. PasswordPolicySubentryVirtualAttributeCfg; import org.opends.server.api.AuthenticationPolicy; import org.opends.server.api.VirtualAttributeProvider; import org.opends.server.core.DirectoryServer; import org.opends.server.core.SearchOperation; import org.opends.server.config.ConfigException; import org.opends.server.core.PasswordPolicy; import org.opends.server.core.PasswordPolicyState; import org.opends.server.loggers.ErrorLogger; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.*; @@ -111,12 +110,11 @@ if (!entry.isSubentry() && !entry.isLDAPSubentry()) { PasswordPolicy policy = null; AuthenticationPolicy policy = null; try { policy = PasswordPolicyState.getPasswordPolicy( entry, false); policy = AuthenticationPolicy.forUser(entry, false); } catch (DirectoryException de) { @@ -133,7 +131,7 @@ } } if (policy != null) if (policy != null && policy.isPasswordPolicy()) { AttributeType dnAttrType = DirectoryServer.getAttributeType( "1.3.6.1.4.1.42.2.27.8.1.23"); opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
@@ -23,44 +23,35 @@ * * * Copyright 2006-2009 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. */ package org.opends.server.extensions; import org.opends.messages.Message; import static org.opends.messages.ExtensionMessages.*; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import static org.opends.server.loggers.debug.DebugLogger.getTracer; import static org.opends.server.util.ServerConstants.SASL_MECHANISM_PLAIN; import static org.opends.server.util.StaticUtils.toLowerCase; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Lock; import org.opends.messages.Message; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.server.PlainSASLMechanismHandlerCfg; import org.opends.server.admin.std.server.SASLMechanismHandlerCfg; import org.opends.server.api.AuthenticationPolicyState; import org.opends.server.api.IdentityMapper; import org.opends.server.api.SASLMechanismHandler; import org.opends.server.config.ConfigException; import org.opends.server.core.BindOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.core.PasswordPolicyState; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.types.AuthenticationInfo; import org.opends.server.types.ByteString; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.DirectoryException; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.InitializationException; import org.opends.server.types.LockManager; import org.opends.server.types.Privilege; import org.opends.server.types.ResultCode; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.DebugLogLevel; import static org.opends.messages.ExtensionMessages.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.types.*; @@ -508,12 +499,14 @@ // provided password was correct. try { PasswordPolicyState pwPolicyState = new PasswordPolicyState(userEntry, false); if (! pwPolicyState.passwordMatches(ByteString.valueOf(password))) // FIXME: we should store store the auth state in with the bind operation // so that any state updates, such as cached passwords, are persisted to // the user's entry when the bind completes. AuthenticationPolicyState authState = AuthenticationPolicyState.forUser( userEntry, false); if (!authState.passwordMatches(ByteString.valueOf(password))) { bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS); Message message = ERR_SASLPLAIN_INVALID_PASSWORD.get(); bindOperation.setAuthFailureReason(message); return; opends/src/server/org/opends/server/extensions/SASLContext.java
@@ -23,6 +23,7 @@ * * * Copyright 2008-2009 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. */ package org.opends.server.extensions; @@ -48,6 +49,7 @@ import org.ietf.jgss.GSSException; import org.opends.server.loggers.debug.DebugTracer; import org.opends.messages.Message; import org.opends.server.api.AuthenticationPolicyState; import org.opends.server.api.ClientConnection; import org.opends.server.api.IdentityMapper; import org.opends.server.core.AccessControlConfigManager; @@ -57,6 +59,7 @@ import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.ldap.LDAPClientConnection; import org.opends.server.types.*; import static org.opends.messages.ExtensionMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.util.ServerConstants.*; @@ -101,6 +104,9 @@ //Error message used by callbacks. private Message cbMsg; //Error code used by callbacks. private ResultCode cbResultCode; //The current bind operation used by the callbacks. private BindOperation bindOp; @@ -330,14 +336,27 @@ dispose(); ClientConnection clientConn = bindOp.getClientConnection(); clientConn.setSASLAuthStateInfo(null); //Check if the callback message is null and use that message if not. if(cbMsg != null) bindOp.setAuthFailureReason(cbMsg); if (cbResultCode != null) { bindOp.setResultCode(cbResultCode); } else bindOp.setAuthFailureReason(msg); { bindOp.setResultCode(ResultCode.INVALID_CREDENTIALS); } if (cbMsg != null) { bindOp.setAuthFailureReason(cbMsg); } else { bindOp.setAuthFailureReason(msg); } } /** * Checks the specified authentication information parameter against the @@ -398,6 +417,18 @@ * @param cbMsg The message to set the callback message to. */ private void setCallbackMsg(Message cbMsg) { setCallbackMsg(ResultCode.INVALID_CREDENTIALS, cbMsg); } /** * Sets the callback message to the specified message. * * @param cbResultCode The result code. * @param cbMsg The message. */ private void setCallbackMsg(ResultCode cbResultCode, Message cbMsg) { this.cbResultCode = cbResultCode; this.cbMsg = cbMsg; } @@ -614,8 +645,19 @@ //Try to get a clear password to use. List<ByteString> clearPasswords; try { PasswordPolicyState pwPolicyState = new PasswordPolicyState(authEntry, false); AuthenticationPolicyState authState = AuthenticationPolicyState.forUser(authEntry, false); if (!authState.isPasswordPolicy()) { Message message = ERR_SASL_ACCOUNT_NOT_LOCAL.get( mechanism, String.valueOf(authEntry.getDN())); setCallbackMsg(ResultCode.INAPPROPRIATE_AUTHENTICATION, message); return; } PasswordPolicyState pwPolicyState = (PasswordPolicyState) authState; clearPasswords = pwPolicyState.getClearPasswords(); if ((clearPasswords == null) || clearPasswords.isEmpty()) { setCallbackMsg( opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
@@ -365,14 +365,20 @@ try { policyDN = DN.decode(v.getValue()); policy = (PasswordPolicy) DirectoryServer AuthenticationPolicy authPolicy = DirectoryServer .getAuthenticationPolicy(policyDN); if (policy == null) if (authPolicy == null) { Message message = WARN_PLUGIN_PWIMPORT_NO_SUCH_POLICY.get( String.valueOf(entry.getDN()), String.valueOf(policyDN)); logError(message); } if (authPolicy.isPasswordPolicy()) { policy = (PasswordPolicy) authPolicy; } break policyLoop; } catch (DirectoryException de) opends/src/server/org/opends/server/types/AccountStatusNotification.java
@@ -237,7 +237,7 @@ new HashMap<AccountStatusNotificationProperty, List<String>>(4); PasswordPolicy policy = pwPolicyState.getPolicy(); PasswordPolicy policy = pwPolicyState.getAuthenticationPolicy(); ArrayList<String> propList = new ArrayList<String>(1); propList.add(policy.getDN().toString()); opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -38,20 +38,13 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.locks.Lock; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import org.opends.server.api.AttributeSyntax; import org.opends.server.api.Backend; import org.opends.server.api.ChangeNotificationListener; import org.opends.server.api.ClientConnection; import org.opends.server.api.PasswordStorageScheme; import org.opends.server.api.PasswordValidator; import org.opends.server.api.SynchronizationProvider; import org.opends.server.api.*; import org.opends.server.api.plugin.PluginResult; import org.opends.server.controls.LDAPAssertionRequestControl; import org.opends.server.controls.LDAPPostReadRequestControl; @@ -1029,49 +1022,14 @@ // FIXME -- We need to check to see if the password policy subentry // might be specified virtually rather than as a real // attribute. PasswordPolicy passwordPolicy = null; List<Attribute> pwAttrList = entry.getAttribute(OP_ATTR_PWPOLICY_POLICY_DN); if ((pwAttrList != null) && (! pwAttrList.isEmpty())) AuthenticationPolicy policy = AuthenticationPolicy.forUser(entry, false); if (!policy.isPasswordPolicy()) { Attribute a = pwAttrList.get(0); Iterator<AttributeValue> iterator = a.iterator(); if (iterator.hasNext()) { DN policyDN; try { policyDN = DN.decode(iterator.next().getValue()); // The entry doesn't have a locally managed password, so no action is // required. return; } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_ADD_INVALID_PWPOLICY_DN_SYNTAX.get( String.valueOf(entryDN), de.getMessageObject())); } passwordPolicy = (PasswordPolicy) DirectoryServer .getAuthenticationPolicy(policyDN); if (passwordPolicy == null) { throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, ERR_ADD_NO_SUCH_PWPOLICY.get( String.valueOf(entryDN), String.valueOf(policyDN))); } } } if (passwordPolicy == null) { passwordPolicy = DirectoryServer.getDefaultPasswordPolicy(); } PasswordPolicy passwordPolicy = (PasswordPolicy) policy; // See if a password was specified. AttributeType passwordAttribute = passwordPolicy.getPasswordAttribute(); opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
@@ -35,9 +35,7 @@ import org.opends.messages.Message; import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn; import org.opends.server.api.Backend; import org.opends.server.api.ClientConnection; import org.opends.server.api.SASLMechanismHandler; import org.opends.server.api.*; import org.opends.server.api.plugin.PluginResult; import org.opends.server.controls.AuthorizationIdentityResponseControl; import org.opends.server.controls.PasswordExpiredControl; @@ -138,15 +136,8 @@ // The idle time limit that should be enforced for the user. private long idleTimeLimit; /** * The password policy that applies to the user. */ protected PasswordPolicy policy; /** * The password policy state for the user. */ protected PasswordPolicyState pwPolicyState; // Authentication policy state. private AuthenticationPolicyState authPolicyState; // The password policy error type for this bind operation. private PasswordPolicyErrorType pwPolicyErrorType; @@ -199,7 +190,7 @@ idleTimeLimit = DirectoryServer.getIdleTimeLimit(); bindDN = getBindDN(); saslMechanism = getSASLMechanism(); pwPolicyState = null; authPolicyState = null; pwPolicyErrorType = null; pwPolicyControlRequested = false; isGraceLogin = false; @@ -330,9 +321,9 @@ // required. try { if (pwPolicyState != null) if (authPolicyState != null) { pwPolicyState.updateUserEntry(); authPolicyState.finalizeStateAfterBind(); } } catch (DirectoryException de) @@ -571,45 +562,40 @@ // Check to see if the user has a password. If not, then fail. // FIXME -- We need to have a way to enable/disable debugging. pwPolicyState = new PasswordPolicyState(userEntry, false); policy = pwPolicyState.getPolicy(); 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( String.valueOf(bindDN))); ERR_BIND_OPERATION_NO_PASSWORD.get(String.valueOf(bindDN))); } // Perform a number of password policy state checks for the user. checkPasswordPolicyState(userEntry, null); // Invoke the pre-operation bind plugins. executePostOpPlugins = true; PluginResult.PreOperation preOpResult = pluginConfigManager.invokePreOperationBindPlugins(this); if (!preOpResult.continueProcessing()) // Invoke pre-operation plugins. if (!invokePreOpPlugins()) { setResultCode(preOpResult.getResultCode()); appendErrorMessage(preOpResult.getErrorMessage()); setMatchedDN(preOpResult.getMatchedDN()); setReferralURLs(preOpResult.getReferralURLs()); return false; } // Determine whether the provided password matches any of the stored // passwords for the user. if (pwPolicyState.passwordMatches(simplePassword)) { setResultCode(ResultCode.SUCCESS); if (DirectoryServer.lockdownMode() && (! ClientConnection.hasPrivilege(userEntry, if (DirectoryServer.lockdownMode() && (!ClientConnection.hasPrivilege(userEntry, Privilege.BYPASS_LOCKDOWN))) { throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, @@ -618,11 +604,9 @@ setAuthenticationInfo(new AuthenticationInfo(userEntry, getBindDN(), simplePassword, DirectoryServer.isRootDN(userEntry.getDN()))); // Set resource limits for the authenticated user. setResourceLimits(userEntry); // Perform any remaining processing for a successful simple // authentication. pwPolicyState.handleDeprecatedStorageSchemes(simplePassword); @@ -633,8 +617,8 @@ pwPolicyState.setWarnedTime(); int numSeconds = pwPolicyState.getSecondsUntilExpiration(); Message m = WARN_BIND_PASSWORD_EXPIRING.get( secondsToTimeString(numSeconds)); Message m = WARN_BIND_PASSWORD_EXPIRING .get(secondsToTimeString(numSeconds)); pwPolicyState.generateAccountStatusNotification( AccountStatusNotificationType.PASSWORD_EXPIRING, userEntry, m, @@ -666,29 +650,60 @@ 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.get( secondsToTimeString(lockoutDuration)); m = ERR_BIND_ACCOUNT_TEMPORARILY_LOCKED .get(secondsToTimeString(lockoutDuration)); } else { notificationType = AccountStatusNotificationType. ACCOUNT_PERMANENTLY_LOCKED; notificationType = AccountStatusNotificationType.ACCOUNT_PERMANENTLY_LOCKED; tempLocked = false; m = ERR_BIND_ACCOUNT_PERMANENTLY_LOCKED.get(); } pwPolicyState.generateAccountStatusNotification( notificationType, userEntry, m, AccountStatusNotification.createProperties(pwPolicyState, tempLocked, -1, null, null)); pwPolicyState.generateAccountStatusNotification(notificationType, userEntry, m, AccountStatusNotification.createProperties( pwPolicyState, tempLocked, -1, null, null)); } } } } else { // Invoke pre-operation plugins. if (!invokePreOpPlugins()) { return false; } if (authPolicyState.passwordMatches(simplePassword)) { setResultCode(ResultCode.SUCCESS); if (DirectoryServer.lockdownMode() && (!ClientConnection.hasPrivilege(userEntry, Privilege.BYPASS_LOCKDOWN))) { throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, ERR_BIND_REJECTED_LOCKDOWN_MODE.get()); } setAuthenticationInfo(new AuthenticationInfo(userEntry, getBindDN(), simplePassword, DirectoryServer.isRootDN(userEntry.getDN()))); // Set resource limits for the authenticated user. setResourceLimits(userEntry); } else { setResultCode(ResultCode.INVALID_CREDENTIALS); setAuthFailureReason(ERR_BIND_OPERATION_WRONG_PASSWORD.get()); } } return true; } @@ -728,16 +743,9 @@ } // Invoke the pre-operation bind plugins. executePostOpPlugins = true; PluginResult.PreOperation preOpResult = pluginConfigManager.invokePreOperationBindPlugins(this); if (!preOpResult.continueProcessing()) // Invoke pre-operation plugins. if (!invokePreOpPlugins()) { setResultCode(preOpResult.getResultCode()); appendErrorMessage(preOpResult.getErrorMessage()); setMatchedDN(preOpResult.getMatchedDN()); setReferralURLs(preOpResult.getReferralURLs()); return false; } @@ -776,15 +784,9 @@ // NYI // Invoke the pre-operation bind plugins. PluginResult.PreOperation preOpResult = pluginConfigManager.invokePreOperationBindPlugins(this); if (!preOpResult.continueProcessing()) // Invoke pre-operation plugins. if (!invokePreOpPlugins()) { setResultCode(preOpResult.getResultCode()); appendErrorMessage(preOpResult.getErrorMessage()); setMatchedDN(preOpResult.getMatchedDN()); setReferralURLs(preOpResult.getReferralURLs()); return false; } @@ -813,22 +815,21 @@ } // Create the password policy state object. if (saslAuthUserEntry == null) if (saslAuthUserEntry != null) { pwPolicyState = null; } else { // FIXME -- Need to have a way to enable debugging. pwPolicyState = new PasswordPolicyState(saslAuthUserEntry, false); policy = pwPolicyState.getPolicy(); setUserEntryDN(saslAuthUserEntry.getDN()); // Perform password policy checks that will need to be completed // regardless of whether the authentication was successful. // 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 will // need to be completed regardless of whether the authentication was // successful. checkPasswordPolicyState(saslAuthUserEntry, saslHandler); } } // Determine whether the authentication was successful and perform @@ -836,8 +837,11 @@ ResultCode resultCode = getResultCode(); if (resultCode == ResultCode.SUCCESS) { if (pwPolicyState != null) if (authPolicyState != null && authPolicyState.isPasswordPolicy()) { PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; if (saslHandler.isPasswordBased(saslMechanism) && pwPolicyState.mustChangePassword()) { @@ -865,12 +869,11 @@ } pwPolicyState.setLastLoginTime(); } // Set appropriate resource limits for the user. setResourceLimits(saslAuthUserEntry); } } else if (resultCode == ResultCode.SASL_BIND_IN_PROGRESS) { // FIXME -- Is any special processing needed here? @@ -878,12 +881,15 @@ } else { if (pwPolicyState != null) if (authPolicyState != null && authPolicyState.isPasswordPolicy()) { PasswordPolicyState pwPolicyState = (PasswordPolicyState) authPolicyState; if (saslHandler.isPasswordBased(saslMechanism)) { if (pwPolicyState.getPolicy().getLockoutFailureCount() > 0) if (pwPolicyState.getAuthenticationPolicy() .getLockoutFailureCount() > 0) { pwPolicyState.updateAuthFailureTimes(); if (pwPolicyState.lockedDueToFailures()) @@ -924,20 +930,45 @@ private boolean invokePreOpPlugins() { executePostOpPlugins = true; PluginResult.PreOperation preOpResult = pluginConfigManager .invokePreOperationBindPlugins(this); if (!preOpResult.continueProcessing()) { setResultCode(preOpResult.getResultCode()); appendErrorMessage(preOpResult.getErrorMessage()); setMatchedDN(preOpResult.getMatchedDN()); setReferralURLs(preOpResult.getReferralURLs()); return false; } else { return true; } } /** * Validates a number of password policy state constraints for the user. * * @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. * @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 checkPasswordPolicyState(Entry userEntry, SASLMechanismHandler<?> saslHandler) protected void checkPasswordPolicyState( 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 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -44,12 +44,7 @@ import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import org.opends.server.api.AttributeSyntax; import org.opends.server.api.Backend; import org.opends.server.api.ChangeNotificationListener; import org.opends.server.api.ClientConnection; import org.opends.server.api.PasswordStorageScheme; import org.opends.server.api.SynchronizationProvider; import org.opends.server.api.*; import org.opends.server.api.plugin.PluginResult; import org.opends.server.controls.LDAPAssertionRequestControl; import org.opends.server.controls.LDAPPostReadRequestControl; @@ -67,14 +62,12 @@ import org.opends.server.core.PluginConfigManager; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.schema.AuthPasswordSyntax; import org.opends.server.schema.BooleanSyntax; import org.opends.server.schema.UserPasswordSyntax; import org.opends.server.types.*; import org.opends.server.types.operation.PostOperationModifyOperation; import org.opends.server.types.operation.PostResponseModifyOperation; import org.opends.server.types.operation.PostSynchronizationModifyOperation; import org.opends.server.types.operation.PreOperationModifyOperation; import org.opends.server.util.TimeThread; import org.opends.server.util.Validator; @@ -141,7 +134,7 @@ /** * Indicates whether the user's account was locked before this change. */ protected boolean wasLocked; protected boolean wasLocked = false; /** * The client connection associated with this operation. @@ -451,8 +444,13 @@ selfChange = entryDN.equals(getAuthorizationDN()); // FIXME -- Need a way to enable debug mode. pwPolicyState = new PasswordPolicyState(currentEntry, false, TimeThread.getTime(), true); AuthenticationPolicy policy = AuthenticationPolicy.forUser( currentEntry, true); if (policy.isPasswordPolicy()) { pwPolicyState = (PasswordPolicyState) policy .createAuthenticationPolicyState(currentEntry); } } catch (DirectoryException de) { @@ -525,13 +523,8 @@ try { handleInitialPasswordPolicyProcessing(); wasLocked = false; if (passwordChanged) { performAdditionalPasswordChangedProcessing(); } } catch (DirectoryException de) { if (debugEnabled()) @@ -632,21 +625,17 @@ } else { if(!processPreOperation()) { if (!processPreOperation()) { break modifyProcessing; } backend.replaceEntry(currentEntry, modifiedEntry, this); // See if we need to generate any account status notifications as a // result of the changes. if (passwordChanged || enabledStateChanged || wasLocked) { handleAccountStatusNotifications(); } } // Handle any processing that may be needed for the pre-read and/or @@ -997,36 +986,12 @@ } // If the modification is not updating the password attribute, // then check if the isEnabled flag should be set and then perform any // schema processing. boolean isPassword = t.equals(pwPolicyState.getPolicy().getPasswordAttribute()); // then perform any schema processing. boolean isPassword = (pwPolicyState != null) && t.equals(pwPolicyState.getAuthenticationPolicy() .getPasswordAttribute()); if (!isPassword ) { // See if it's an attribute used to maintain the account // enabled/disabled state. AttributeType disabledAttr = DirectoryServer.getAttributeType(OP_ATTR_ACCOUNT_DISABLED, true); if (t.equals(disabledAttr)) { enabledStateChanged = true; for (AttributeValue v : a) { try { isEnabled = (! BooleanSyntax.DECODER.decode(v)); } catch (DirectoryException de) { throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_MODIFY_INVALID_DISABLED_VALUE.get( OP_ATTR_ACCOUNT_DISABLED, String.valueOf(de.getMessageObject())), de); } } } switch (m.getModificationType()) { case ADD: @@ -1062,8 +1027,15 @@ currentPasswordProvided = false; isEnabled = true; enabledStateChanged = false; if (pwPolicyState == null) { // Account not managed locally so nothing to do. return; } if (currentEntry.hasAttribute( pwPolicyState.getPolicy().getPasswordAttribute())) pwPolicyState.getAuthenticationPolicy().getPasswordAttribute())) { // It may actually have more than one, but we can't tell the difference if // the values are encoded, and its enough for our purposes just to know @@ -1085,8 +1057,8 @@ for (Modification m : modifications) { AttributeType t = m.getAttribute().getAttributeType(); boolean isPassword = t.equals(pwPolicyState.getPolicy().getPasswordAttribute()); boolean isPassword = t.equals(pwPolicyState.getAuthenticationPolicy() .getPasswordAttribute()); if (isPassword) { passwordChanged = true; @@ -1116,8 +1088,8 @@ // If the modification is updating the password attribute, then perform // any necessary password policy processing. This processing should be // skipped for synchronization operations. boolean isPassword = t.equals(pwPolicyState.getPolicy().getPasswordAttribute()); boolean isPassword = t.equals(pwPolicyState.getAuthenticationPolicy() .getPasswordAttribute()); if (isPassword) { if (!isSynchronizationOperation()) @@ -1135,8 +1107,9 @@ // If it's a self change, then see if that's allowed. if (selfChange && (! pwPolicyState.getPolicy().isAllowUserPasswordChanges())) if (selfChange && (!pwPolicyState.getAuthenticationPolicy() .isAllowUserPasswordChanges())) { pwpErrorType = PasswordPolicyErrorType.PASSWORD_MOD_NOT_ALLOWED; throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, @@ -1146,8 +1119,9 @@ // If we require secure password changes, then makes sure it's a // secure communication channel. if (pwPolicyState.getPolicy().isRequireSecurePasswordChanges() && (! clientConnection.isSecure())) if (pwPolicyState.getAuthenticationPolicy() .isRequireSecurePasswordChanges() && (!clientConnection.isSecure())) { pwpErrorType = PasswordPolicyErrorType.PASSWORD_MOD_NOT_ALLOWED; throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, @@ -1242,8 +1216,8 @@ // If there were multiple password values, then make sure that's // OK. if ((!isInternalOperation()) && (!pwPolicyState.getPolicy().isAllowMultiplePasswordValues()) && (passwordsToAdd > 1)) && (!pwPolicyState.getAuthenticationPolicy() .isAllowMultiplePasswordValues()) && (passwordsToAdd > 1)) { pwpErrorType = PasswordPolicyErrorType.PASSWORD_MOD_NOT_ALLOWED; throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, @@ -1260,7 +1234,8 @@ if (pwPolicyState.passwordIsPreEncoded(v.getValue())) { if ((!isInternalOperation()) && !pwPolicyState.getPolicy().isAllowPreEncodedPasswords()) && !pwPolicyState.getAuthenticationPolicy() .isAllowPreEncodedPasswords()) { pwpErrorType = PasswordPolicyErrorType.INSUFFICIENT_PASSWORD_QUALITY; throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, @@ -1382,7 +1357,7 @@ { for (AttributeValue av : attr) { if (pwPolicyState.getPolicy().isAuthPasswordSyntax()) if (pwPolicyState.getAuthenticationPolicy().isAuthPasswordSyntax()) { if (AuthPasswordSyntax.isEncoded(av.getValue())) { @@ -1867,11 +1842,24 @@ public void performAdditionalPasswordChangedProcessing() throws DirectoryException { if (pwPolicyState == null) { // Account not managed locally so nothing to do. return; } if (!passwordChanged) { // Nothing to do. return; } // If it was a self change, then see if the current password was provided // and handle accordingly. if (selfChange && pwPolicyState.getPolicy().isPasswordChangeRequiresCurrentPassword() && (! currentPasswordProvided)) if (selfChange && pwPolicyState.getAuthenticationPolicy() .isPasswordChangeRequiresCurrentPassword() && (!currentPasswordProvided)) { pwpErrorType = PasswordPolicyErrorType.MUST_SUPPLY_OLD_PASSWORD; @@ -1882,8 +1870,9 @@ // If this change would result in multiple password values, then see if // that's OK. if ((numPasswords > 1) && (! pwPolicyState.getPolicy().isAllowMultiplePasswordValues())) if ((numPasswords > 1) && (!pwPolicyState.getAuthenticationPolicy() .isAllowMultiplePasswordValues())) { pwpErrorType = PasswordPolicyErrorType.PASSWORD_MOD_NOT_ALLOWED; throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, @@ -1892,8 +1881,9 @@ // If any of the password values should be validated, then do so now. if (selfChange || (! pwPolicyState.getPolicy().isSkipValidationForAdministrators())) if (selfChange || (!pwPolicyState.getAuthenticationPolicy() .isSkipValidationForAdministrators())) { if (newPasswords != null) { @@ -1965,7 +1955,7 @@ { if (pwPolicyState.isPasswordInHistory(v.getValue())) { if (selfChange || (! pwPolicyState.getPolicy(). if (selfChange || (! pwPolicyState.getAuthenticationPolicy(). isSkipValidationForAdministrators())) { pwpErrorType = PasswordPolicyErrorType.PASSWORD_IN_HISTORY; @@ -1992,8 +1982,8 @@ pwPolicyState.clearGraceLoginTimes(); pwPolicyState.clearWarnedTime(); if (pwPolicyState.getPolicy().isForceChangeOnAdd() || pwPolicyState.getPolicy().isForceChangeOnReset()) if (pwPolicyState.getAuthenticationPolicy().isForceChangeOnAdd() || pwPolicyState.getAuthenticationPolicy().isForceChangeOnReset()) { if (selfChange) { @@ -2002,17 +1992,17 @@ else { if ((pwpErrorType == null) && pwPolicyState.getPolicy().isForceChangeOnReset()) pwPolicyState.getAuthenticationPolicy().isForceChangeOnReset()) { pwpErrorType = PasswordPolicyErrorType.CHANGE_AFTER_RESET; } pwPolicyState.setMustChangePassword( pwPolicyState.getPolicy().isForceChangeOnReset()); pwPolicyState.getAuthenticationPolicy().isForceChangeOnReset()); } } if (pwPolicyState.getPolicy().getRequireChangeByTime() > 0) if (pwPolicyState.getAuthenticationPolicy().getRequireChangeByTime() > 0) { pwPolicyState.setRequiredChangeTime(); } @@ -2079,6 +2069,18 @@ */ protected void handleAccountStatusNotifications() { if (pwPolicyState == null) { // Account not managed locally, so nothing to do. return; } if (!(passwordChanged || enabledStateChanged || wasLocked)) { // Account managed locally, but unchanged, so nothing to do. return; } if (passwordChanged) { if (selfChange) opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryPasswordPolicyTestCase.java
@@ -36,6 +36,7 @@ import org.testng.annotations.Test; import org.opends.server.TestCaseUtils; import org.opends.server.api.AuthenticationPolicy; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValues; @@ -304,19 +305,15 @@ "uid=rogasawara," + BASE)); assertNotNull(testEntry); PasswordPolicyState state = new PasswordPolicyState(testEntry, false); assertNotNull(state); PasswordPolicy statePolicy = state.getPolicy(); AuthenticationPolicy statePolicy = AuthenticationPolicy.forUser(testEntry, false); assertNotNull(statePolicy); assertEquals(policy, statePolicy); // Make sure this policy is gone and default // policy is in effect instead. TestCaseUtils.deleteEntry(policyEntry.getDN()); state = new PasswordPolicyState(testEntry, false); assertNotNull(state); statePolicy = state.getPolicy(); statePolicy = AuthenticationPolicy.forUser(testEntry, false); assertNotNull(statePolicy); assertEquals(defaultPolicy, statePolicy); } opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ErrorLogAccountStatusNotificationHandlerTestCase.java
@@ -41,6 +41,7 @@ import org.opends.server.TestCaseUtils; import org.opends.messages.Message; import org.opends.server.api.AccountStatusNotificationHandler; import org.opends.server.api.AuthenticationPolicy; import org.opends.server.admin.server.AdminTestCaseUtils; import org.opends.server.admin.std.meta. ErrorLogAccountStatusNotificationHandlerCfgDefn; @@ -50,7 +51,6 @@ import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.core.PasswordPolicy; import org.opends.server.core.PasswordPolicyState; import org.opends.server.types.AccountStatusNotification; import org.opends.server.types.AccountStatusNotificationProperty; import org.opends.server.types.AccountStatusNotificationType; @@ -189,7 +189,7 @@ String dnStr = "cn=Error Log Handler,cn=Account Status Notification " + "Handlers,cn=config"; DN handlerDN = DN.decode(dnStr); AccountStatusNotificationHandler handler = AccountStatusNotificationHandler<?> handler = DirectoryServer.getAccountStatusNotificationHandler(handlerDN); assertNotNull(handler); assertTrue(handler instanceof ErrorLogAccountStatusNotificationHandler); @@ -250,16 +250,15 @@ String dnStr = "cn=Error Log Handler,cn=Account Status Notification " + "Handlers,cn=config"; DN handlerDN = DN.decode(dnStr); AccountStatusNotificationHandler handler = AccountStatusNotificationHandler<?> handler = DirectoryServer.getAccountStatusNotificationHandler(handlerDN); assertNotNull(handler); Entry userEntry = DirectoryServer.getEntry(DN.decode("uid=test.user,o=test")); PasswordPolicyState pwPolicyState = new PasswordPolicyState(userEntry, false); PasswordPolicy policy = pwPolicyState.getPolicy(); PasswordPolicy policy = (PasswordPolicy) AuthenticationPolicy.forUser( userEntry, false); HashMap<AccountStatusNotificationProperty,List<String>> notificationProperties =