From 3883d2297c3422d8aec2b40530c2d2b0a00ee57d Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 25 Aug 2011 16:27:28 +0000
Subject: [PATCH] Final refactoring work for OPENDJ-262: Implement pass through authentication (PTA)
---
opends/src/server/org/opends/server/api/AuthenticationPolicy.java | 244 +++++++
opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java | 28
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java | 166 ++--
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java | 349 +++++----
opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java | 21
opends/src/server/org/opends/server/extensions/SASLContext.java | 54 +
opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java | 10
opends/src/server/org/opends/server/extensions/PasswordPolicySubentryVirtualAttributeProvider.java | 10
opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryPasswordPolicyTestCase.java | 11
opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java | 8
opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java | 56
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java | 56 -
opends/src/server/org/opends/server/core/SearchOperationBasis.java | 67 +
opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java | 56 +
opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java | 20
opends/src/server/org/opends/server/core/PasswordPolicyState.java | 598 ++---------------
opends/src/server/org/opends/server/api/AuthenticationPolicyState.java | 143 ++++
opends/src/server/org/opends/server/core/PasswordPolicy.java | 30
opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java | 41
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ErrorLogAccountStatusNotificationHandlerTestCase.java | 11
opends/src/messages/messages/extension.properties | 11
opends/src/server/org/opends/server/core/CoreConfigManager.java | 2
opends/src/server/org/opends/server/types/AccountStatusNotification.java | 2
23 files changed, 1,016 insertions(+), 978 deletions(-)
diff --git a/opends/src/messages/messages/extension.properties b/opends/src/messages/messages/extension.properties
index b70ff7e..c5736f2 100644
--- a/opends/src/messages/messages/extension.properties
+++ b/opends/src/messages/messages/extension.properties
@@ -587,7 +587,7 @@
INFO_SASLCRAMMD5_UPDATED_USER_BASE_DN_191=Attribute ds-cfg-user-base-dn in \
configuration entry %s has been updated. The DN %s will now be used as the \
search base when looking up user entries based on their username
- INFO_SASL_UNSUPPORTED_CALLBACK_192=An unsupported or unexpected callback was \
+INFO_SASL_UNSUPPORTED_CALLBACK_192=An unsupported or unexpected callback was \
provided to the SASL server for use during %s authentication: %s
MILD_ERR_SASL_NO_CREDENTIALS_193=The client connection included \
%s state information, indicating that the client was in the process \
@@ -1401,7 +1401,7 @@
SEVERE_ERR_SASLDIGESTMD5_PROTOCOL_ERROR_570=SASL DIGEST MD5 protocol error: %s
INFO_LOG_EXTENSION_INFORMATION_571=Loaded extension from file '%s' (build %s, \
revision %s)
- SEVERE_ERR_SASL_CREATE_SASL_SERVER_FAILED_572=Failed to create a SASL server \
+SEVERE_ERR_SASL_CREATE_SASL_SERVER_FAILED_572=Failed to create a SASL server \
for SASL mechanism %s using a server FQDN of %s
SEVERE_ERR_SASL_GSSAPI_KEYTAB_INVALID_573=GSSAPI SASL mechanism handler initalization \
failed because the keytab file %s does not exist
@@ -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
diff --git a/opends/src/server/org/opends/server/api/AuthenticationPolicy.java b/opends/src/server/org/opends/server/api/AuthenticationPolicy.java
index aeb4ef2..5054186 100644
--- a/opends/src/server/org/opends/server/api/AuthenticationPolicy.java
+++ b/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.
diff --git a/opends/src/server/org/opends/server/api/AuthenticationPolicyState.java b/opends/src/server/org/opends/server/api/AuthenticationPolicyState.java
new file mode 100644
index 0000000..b71ae6c
--- /dev/null
+++ b/opends/src/server/org/opends/server/api/AuthenticationPolicyState.java
@@ -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();
+ }
+}
diff --git a/opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java b/opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java
index b45f309..3f85360 100644
--- a/opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java
+++ b/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);
}
diff --git a/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java b/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
index 54ab358..dd4103a 100644
--- a/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
+++ b/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,19 +325,25 @@
// 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())
+ AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry,
+ false);
+ if (policy.isPasswordPolicy())
{
- Message message =
- ERR_PROXYAUTH1_UNUSABLE_ACCOUNT.get(String.valueOf(authzDN));
- throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
+ 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);
+ }
}
-
// If we've made it here, then the user is acceptable.
return userEntry;
}
diff --git a/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java b/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
index d5f576d..079bceb 100644
--- a/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
+++ b/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.
diff --git a/opends/src/server/org/opends/server/core/CoreConfigManager.java b/opends/src/server/org/opends/server/core/CoreConfigManager.java
index 2aebb66..3dfabb8 100644
--- a/opends/src/server/org/opends/server/core/CoreConfigManager.java
+++ b/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
diff --git a/opends/src/server/org/opends/server/core/PasswordPolicy.java b/opends/src/server/org/opends/server/core/PasswordPolicy.java
index e937944..884839b 100644
--- a/opends/src/server/org/opends/server/core/PasswordPolicy.java
+++ b/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);
+ }
}
diff --git a/opends/src/server/org/opends/server/core/PasswordPolicyState.java b/opends/src/server/org/opends/server/core/PasswordPolicyState.java
index 441445d..4ad0705 100644
--- a/opends/src/server/org/opends/server/core/PasswordPolicyState.java
+++ b/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
+ * 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)
- throws DirectoryException
+ 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
@@ -250,163 +215,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.
*
@@ -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,16 +576,7 @@
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));
- }
+ 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));
- }
+ 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,30 +720,13 @@
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));
- }
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
}
else
{
// erase
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ modifications.add(new Modification(ModificationType.REPLACE,
Attributes.empty(type), true));
- }
}
}
@@ -1089,16 +862,7 @@
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));
- }
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
}
}
@@ -1121,15 +885,8 @@
DirectoryServer.getAttributeType(OP_ATTR_ACCOUNT_EXPIRATION_TIME,
true);
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ 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,
+ modifications.add(new Modification(ModificationType.REPLACE,
Attributes.empty(type), true));
- }
return authFailureTimes;
}
@@ -1245,33 +995,11 @@
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();
- modifications.add(new Modification(ModificationType.DELETE, a,
- true));
- }
+ AttributeBuilder builder = new AttributeBuilder(type);
+ builder.addAll(valuesToRemove);
+ Attribute a = builder.toAttribute();
+ modifications.add(new Modification(ModificationType.DELETE, a,
+ true));
}
}
@@ -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));
- }
+ 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));
- }
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
// Now check to see if there have been sufficient failures to lock the
// account.
@@ -1458,15 +1170,8 @@
OP_ATTR_PWPOLICY_FAILURE_TIME);
}
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ modifications.add(new Modification(ModificationType.REPLACE,
Attributes.empty(type), true));
- }
}
@@ -1544,16 +1249,7 @@
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));
- }
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
}
@@ -1585,15 +1281,8 @@
OP_ATTR_PWPOLICY_LOCKED_TIME);
}
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ 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));
- }
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
if (debugEnabled())
{
@@ -1972,15 +1652,8 @@
AttributeType type =
DirectoryServer.getAttributeType(OP_ATTR_LAST_LOGIN_TIME, true);
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ modifications.add(new Modification(ModificationType.REPLACE,
Attributes.empty(type), true));
- }
}
@@ -2195,29 +1868,12 @@
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));
- }
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
}
else
{
- // erase
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ modifications.add(new Modification(ModificationType.REPLACE,
Attributes.empty(type), true));
- }
}
}
@@ -2732,16 +2388,7 @@
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));
- }
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
}
}
@@ -2763,15 +2410,8 @@
AttributeType type = DirectoryServer.getAttributeType(
OP_ATTR_PWPOLICY_CHANGED_BY_REQUIRED_TIME, true);
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ 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));
- }
+ 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));
- }
+ Attribute a = Attributes.empty(type);
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
if (debugEnabled())
{
@@ -2955,15 +2579,8 @@
graceLoginTimes = new ArrayList<Long>();
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ modifications.add(new Modification(ModificationType.REPLACE,
Attributes.empty(type), true));
- }
}
}
@@ -3036,27 +2653,10 @@
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)));
- }
+ Attribute addAttr = Attributes.create(type, AttributeValues.create(
+ type, GeneralizedTimeSyntax.format(highestGraceTime)));
- 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));
- }
+ modifications.add(new Modification(ModificationType.ADD, addAttr, true));
}
@@ -3094,17 +2694,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));
- }
+ modifications.add(new Modification(ModificationType.REPLACE, a, true));
}
@@ -3135,15 +2725,8 @@
OP_ATTR_PWPOLICY_GRACE_LOGIN_TIME);
}
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ 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,28 +3221,17 @@
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();
- modifications.add(new Modification(ModificationType.DELETE, a, true));
+ AttributeBuilder builder = new AttributeBuilder(type);
+ builder.addAll(removedValues);
+ Attribute a = builder.toAttribute();
+ modifications.add(new Modification(ModificationType.DELETE, a, true));
- if (! addedValues.isEmpty())
- {
- builder = new AttributeBuilder(type);
- builder.addAll(addedValues);
- Attribute a2 = builder.toAttribute();
- modifications.add(new Modification(ModificationType.ADD, a2, true));
- }
+ if (! addedValues.isEmpty())
+ {
+ builder = new AttributeBuilder(type);
+ builder.addAll(addedValues);
+ Attribute a2 = builder.toAttribute();
+ modifications.add(new Modification(ModificationType.ADD, a2, true));
}
if (debugEnabled())
@@ -4155,26 +3721,13 @@
// Apply the changes, either by adding modifications or by directly updating
// the entry.
- if (updateEntry)
+ for (Attribute a : removeAttrs)
{
- LinkedList<AttributeValue> valueList = new LinkedList<AttributeValue>();
- for (Attribute a : removeAttrs)
- {
- userEntry.removeAttribute(a, valueList);
- }
-
- userEntry.addAttribute(newHistAttr, valueList);
+ modifications.add(new Modification(ModificationType.DELETE, a, true));
}
- else
- {
- for (Attribute a : removeAttrs)
- {
- modifications.add(new Modification(ModificationType.DELETE, a, true));
- }
- modifications.add(new Modification(ModificationType.ADD, newHistAttr,
- true));
- }
+ modifications.add(new Modification(ModificationType.ADD, newHistAttr,
+ true));
}
@@ -4221,15 +3774,8 @@
AttributeType type = DirectoryServer.getAttributeType(
OP_ATTR_PWPOLICY_HISTORY_LC, true);
- if (updateEntry)
- {
- userEntry.removeAttribute(type);
- }
- else
- {
- modifications.add(new Modification(ModificationType.REPLACE,
+ 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.
diff --git a/opends/src/server/org/opends/server/core/SearchOperationBasis.java b/opends/src/server/org/opends/server/core/SearchOperationBasis.java
index 4f708f8..f2e46de 100644
--- a/opends/src/server/org/opends/server/core/SearchOperationBasis.java
+++ b/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;
@@ -639,47 +641,54 @@
}
}
- // Determine whether to include the account usable control. If so, then
+ // Determine whether to include the account usable control. If so, then
// create it now.
if (isIncludeUsableControl())
{
try
{
// FIXME -- Need a way to enable PWP debugging.
- PasswordPolicyState pwpState = new PasswordPolicyState(entry, false);
-
- boolean isInactive = pwpState.isDisabled() ||
- pwpState.isAccountExpired();
- boolean isLocked = pwpState.lockedDueToFailures() ||
- pwpState.lockedDueToMaximumResetAge() ||
- pwpState.lockedDueToIdleInterval();
- boolean isReset = pwpState.mustChangePassword();
- boolean isExpired = pwpState.isPasswordExpired();
-
- if (isInactive || isLocked || isReset || isExpired)
+ AuthenticationPolicy policy = AuthenticationPolicy
+ .forUser(entry, false);
+ if (policy.isPasswordPolicy())
{
- int secondsBeforeUnlock = pwpState.getSecondsUntilUnlock();
- int remainingGraceLogins = pwpState.getGraceLoginsRemaining();
+ PasswordPolicyState pwpState = (PasswordPolicyState) policy
+ .createAuthenticationPolicyState(entry);
- if (controls == null)
+ boolean isInactive = pwpState.isDisabled()
+ || pwpState.isAccountExpired();
+ boolean isLocked = pwpState.lockedDueToFailures()
+ || pwpState.lockedDueToMaximumResetAge()
+ || pwpState.lockedDueToIdleInterval();
+ boolean isReset = pwpState.mustChangePassword();
+ boolean isExpired = pwpState.isPasswordExpired();
+
+ if (isInactive || isLocked || isReset || isExpired)
{
- controls = new ArrayList<Control>(1);
- }
+ int secondsBeforeUnlock = pwpState.getSecondsUntilUnlock();
+ int remainingGraceLogins = pwpState.getGraceLoginsRemaining();
- controls.add(new AccountUsableResponseControl(isInactive, isReset,
- isExpired, remainingGraceLogins, isLocked,
- secondsBeforeUnlock));
- }
- else
- {
- if (controls == null)
+ if (controls == null)
+ {
+ controls = new ArrayList<Control>(1);
+ }
+
+ controls
+ .add(new AccountUsableResponseControl(isInactive, isReset,
+ isExpired, remainingGraceLogins, isLocked,
+ secondsBeforeUnlock));
+ }
+ else
{
- controls = new ArrayList<Control>(1);
- }
+ if (controls == null)
+ {
+ controls = new ArrayList<Control>(1);
+ }
- int secondsBeforeExpiration = pwpState.getSecondsUntilExpiration();
- controls.add(new AccountUsableResponseControl(
- secondsBeforeExpiration));
+ int secondsBeforeExpiration = pwpState.getSecondsUntilExpiration();
+ controls.add(new AccountUsableResponseControl(
+ secondsBeforeExpiration));
+ }
}
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
index 0f1b8d6..e494529 100644
--- a/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
+++ b/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())
{
diff --git a/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java b/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
index 1ebbb1d..3502229 100644
--- a/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
+++ b/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);
diff --git a/opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java b/opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
index ff12942..3ea552b 100644
--- a/opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
+++ b/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)
{
diff --git a/opends/src/server/org/opends/server/extensions/PasswordPolicySubentryVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/PasswordPolicySubentryVirtualAttributeProvider.java
index 612a6b6..52f3a4a 100644
--- a/opends/src/server/org/opends/server/extensions/PasswordPolicySubentryVirtualAttributeProvider.java
+++ b/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");
diff --git a/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
index 8671c72..aa06ad0 100644
--- a/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
+++ b/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;
diff --git a/opends/src/server/org/opends/server/extensions/SASLContext.java b/opends/src/server/org/opends/server/extensions/SASLContext.java
index 954baad..c94cc20 100644
--- a/opends/src/server/org/opends/server/extensions/SASLContext.java
+++ b/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,12 +336,25 @@
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);
+ {
+ bindOp.setResultCode(ResultCode.INVALID_CREDENTIALS);
+ }
+
+ if (cbMsg != null)
+ {
+ bindOp.setAuthFailureReason(cbMsg);
+ }
+ else
+ {
+ bindOp.setAuthFailureReason(msg);
+ }
}
@@ -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(
diff --git a/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java b/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
index d80ce25..8273673 100644
--- a/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
+++ b/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)
diff --git a/opends/src/server/org/opends/server/types/AccountStatusNotification.java b/opends/src/server/org/opends/server/types/AccountStatusNotification.java
index e868922..df79cd0 100644
--- a/opends/src/server/org/opends/server/types/AccountStatusNotification.java
+++ b/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());
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
index 3f9a2aa..9a2f57b 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
+++ b/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());
- }
- 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)));
- }
- }
+ // The entry doesn't have a locally managed password, so no action is
+ // required.
+ return;
}
-
- if (passwordPolicy == null)
- {
- passwordPolicy = DirectoryServer.getDefaultPasswordPolicy();
- }
+ PasswordPolicy passwordPolicy = (PasswordPolicy) policy;
// See if a password was specified.
AttributeType passwordAttribute = passwordPolicy.getPasswordAttribute();
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
index 68d58d9..026621f 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
+++ b/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)
@@ -569,124 +560,148 @@
}
- // Check to see if the user has a password. If not, then fail.
+ // 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();
- AttributeType pwType = policy.getPasswordAttribute();
-
- List<Attribute> pwAttr = userEntry.getAttribute(pwType);
- if ((pwAttr == null) || (pwAttr.isEmpty()))
+ authPolicyState = AuthenticationPolicyState.forUser(userEntry, false);
+ if (authPolicyState.isPasswordPolicy())
{
- throw new DirectoryException(ResultCode.INVALID_CREDENTIALS,
- ERR_BIND_OPERATION_NO_PASSWORD.get(
- String.valueOf(bindDN)));
- }
+ // Account is managed locally.
+ PasswordPolicyState pwPolicyState =
+ (PasswordPolicyState) authPolicyState;
+ PasswordPolicy policy = pwPolicyState.getAuthenticationPolicy();
+ AttributeType pwType = policy.getPasswordAttribute();
- // 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())
- {
- 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,
- Privilege.BYPASS_LOCKDOWN)))
+ List<Attribute> pwAttr = userEntry.getAttribute(pwType);
+ if ((pwAttr == null) || (pwAttr.isEmpty()))
{
throw new DirectoryException(ResultCode.INVALID_CREDENTIALS,
- ERR_BIND_REJECTED_LOCKDOWN_MODE.get());
+ ERR_BIND_OPERATION_NO_PASSWORD.get(String.valueOf(bindDN)));
}
- setAuthenticationInfo(new AuthenticationInfo(userEntry, getBindDN(),
- simplePassword, DirectoryServer.isRootDN(userEntry.getDN())));
+ // Perform a number of password policy state checks for the user.
+ checkPasswordPolicyState(userEntry, null);
- // 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)
+ // Invoke pre-operation plugins.
+ if (!invokePreOpPlugins())
{
- pwPolicyState.setWarnedTime();
-
- int numSeconds = pwPolicyState.getSecondsUntilExpiration();
- Message m = WARN_BIND_PASSWORD_EXPIRING.get(
- secondsToTimeString(numSeconds));
-
- pwPolicyState.generateAccountStatusNotification(
- AccountStatusNotificationType.PASSWORD_EXPIRING, userEntry, m,
- AccountStatusNotification.createProperties(pwPolicyState,
- false, numSeconds, null, null));
+ return false;
}
- if (isGraceLogin)
+ // Determine whether the provided password matches any of the stored
+ // passwords for the user.
+ if (pwPolicyState.passwordMatches(simplePassword))
{
- pwPolicyState.updateGraceLoginTimes();
- }
+ setResultCode(ResultCode.SUCCESS);
- pwPolicyState.setLastLoginTime();
+ 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);
+
+ // Perform any remaining processing for a successful simple
+ // authentication.
+ pwPolicyState.handleDeprecatedStorageSchemes(simplePassword);
+ pwPolicyState.clearFailureLockout();
+
+ if (isFirstWarning)
+ {
+ pwPolicyState.setWarnedTime();
+
+ int numSeconds = pwPolicyState.getSecondsUntilExpiration();
+ Message 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)
+ {
+ pwPolicyState.updateAuthFailureTimes();
+ if (pwPolicyState.lockedDueToFailures())
+ {
+ AccountStatusNotificationType notificationType;
+ Message m;
+
+ boolean tempLocked;
+ int lockoutDuration = pwPolicyState.getSecondsUntilUnlock();
+ if (lockoutDuration > -1)
+ {
+ notificationType =
+ AccountStatusNotificationType.ACCOUNT_TEMPORARILY_LOCKED;
+ tempLocked = true;
+
+ m = ERR_BIND_ACCOUNT_TEMPORARILY_LOCKED
+ .get(secondsToTimeString(lockoutDuration));
+ }
+ else
+ {
+ 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));
+ }
+ }
+ }
}
else
{
- setResultCode(ResultCode.INVALID_CREDENTIALS);
- setAuthFailureReason(ERR_BIND_OPERATION_WRONG_PASSWORD.get());
-
- if (policy.getLockoutFailureCount() > 0)
+ // Invoke pre-operation plugins.
+ if (!invokePreOpPlugins())
{
- pwPolicyState.updateAuthFailureTimes();
- if (pwPolicyState.lockedDueToFailures())
+ return false;
+ }
+
+ if (authPolicyState.passwordMatches(simplePassword))
+ {
+ setResultCode(ResultCode.SUCCESS);
+
+ if (DirectoryServer.lockdownMode()
+ && (!ClientConnection.hasPrivilege(userEntry,
+ Privilege.BYPASS_LOCKDOWN)))
{
- AccountStatusNotificationType notificationType;
- Message m;
-
- boolean tempLocked;
- int lockoutDuration = pwPolicyState.getSecondsUntilUnlock();
- if (lockoutDuration > -1)
- {
- notificationType = AccountStatusNotificationType.
- ACCOUNT_TEMPORARILY_LOCKED;
- tempLocked = true;
-
- m = ERR_BIND_ACCOUNT_TEMPORARILY_LOCKED.get(
- secondsToTimeString(lockoutDuration));
- }
- else
- {
- 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));
+ 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());
}
}
@@ -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,21 +815,20 @@
}
// 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.
- checkPasswordPolicyState(saslAuthUserEntry, saslHandler);
+ // 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);
+ }
}
@@ -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,11 +869,10 @@
}
pwPolicyState.setLastLoginTime();
-
-
- // Set appropriate resource limits for the user.
- setResourceLimits(saslAuthUserEntry);
}
+
+ // Set appropriate resource limits for the user.
+ setResourceLimits(saslAuthUserEntry);
}
else if (resultCode == ResultCode.SASL_BIND_IN_PROGRESS)
{
@@ -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)
- throws DirectoryException
+ 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
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index 3fc9444..327323e 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/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,12 +523,7 @@
try
{
handleInitialPasswordPolicyProcessing();
-
- wasLocked = false;
- if (passwordChanged)
- {
- performAdditionalPasswordChangedProcessing();
- }
+ performAdditionalPasswordChangedProcessing();
}
catch (DirectoryException de)
{
@@ -632,20 +625,16 @@
}
else
{
- if(!processPreOperation()) {
- break modifyProcessing;
- }
+ 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();
- }
+ handleAccountStatusNotifications();
}
@@ -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,33 +1842,48 @@
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;
throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
- ERR_MODIFY_PW_CHANGE_REQUIRES_CURRENT_PW.get());
+ ERR_MODIFY_PW_CHANGE_REQUIRES_CURRENT_PW.get());
}
// 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,
- ERR_MODIFY_MULTIPLE_PASSWORDS_NOT_ALLOWED.get());
+ ERR_MODIFY_MULTIPLE_PASSWORDS_NOT_ALLOWED.get());
}
// 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)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryPasswordPolicyTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryPasswordPolicyTestCase.java
index 9a3419b..d9d5e40 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryPasswordPolicyTestCase.java
+++ b/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);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ErrorLogAccountStatusNotificationHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ErrorLogAccountStatusNotificationHandlerTestCase.java
index 9d94aa8..4345088 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ErrorLogAccountStatusNotificationHandlerTestCase.java
+++ b/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 =
--
Gitblit v1.10.0