From a00e82adec8a13d514f9aa29f56762591426bd5e Mon Sep 17 00:00:00 2001
From: Ludovic Poitou <ludovic.poitou@forgerock.com>
Date: Thu, 30 Jan 2014 13:50:01 +0000
Subject: [PATCH] Fix for OPENDJ-1295, allow password policy subentries to refer to configured password validators. To do so, one will need to add an auxiliary objectclass in the password policy subentry and the mandatory ds-cfg-password-validator attribute (value is the DN of the validator in cn=config DIT).
---
opends/src/server/org/opends/server/core/SubentryPasswordPolicy.java | 165 +++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 136 insertions(+), 29 deletions(-)
diff --git a/opends/src/server/org/opends/server/core/SubentryPasswordPolicy.java b/opends/src/server/org/opends/server/core/SubentryPasswordPolicy.java
index 4d3973c..2fa308d 100644
--- a/opends/src/server/org/opends/server/core/SubentryPasswordPolicy.java
+++ b/opends/src/server/org/opends/server/core/SubentryPasswordPolicy.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.opends.server.core;
@@ -31,17 +31,22 @@
import static org.opends.messages.ConfigMessages.*;
import static org.opends.messages.CoreMessages.*;
+import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.schema.SchemaConstants.*;
import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn.*;
+import org.opends.server.admin.std.server.PasswordValidatorCfg;
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.config.ConfigException;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.*;
@@ -82,35 +87,41 @@
private static final String PWD_ATTR_FAILURECOUNTINTERVAL =
"pwdfailurecountinterval";
- // Password Policy Subentry DN.
- private final DN passwordPolicySubentryDN;
- // The value of the "allow-user-password-changes" property.
- private final Boolean pAllowUserPasswordChanges;
- // The value of the "force-change-on-reset" property.
- private final Boolean pForceChangeOnReset;
- // The value of the "grace-login-count" property.
- private final Integer pGraceLoginCount;
- // The value of the "lockout-duration" property.
- private final Long pLockoutDuration;
- // The value of the "lockout-failure-count" property.
- private final Integer pLockoutFailureCount;
- // The value of the "lockout-failure-expiration-interval" property.
- private final Long pLockoutFailureExpirationInterval;
- // The value of the "max-password-age" property.
- private final Long pMaxPasswordAge;
- // The value of the "min-password-age" property.
- private final Long pMinPasswordAge;
- // The value of the "password-attribute" property.
- private final AttributeType pPasswordAttribute;
- // The value of the "password-change-requires-current-password" property.
- private final Boolean pPasswordChangeRequiresCurrentPassword;
- // The value of the "password-expiration-warning-interval" property.
- private final Long pPasswordExpirationWarningInterval;
- // The value of the "password-history-count" property.
- private final Integer pPasswordHistoryCount;
- // Indicates if the password attribute uses auth password syntax.
- private final Boolean pAuthPasswordSyntax;
+ private static final String PWD_ATTR_VALIDATOR = "ds-cfg-password-validator";
+ private static final String PWD_OC_VALIDATORPOLICY = "pwdvalidatorpolicy";
+ /** Password Policy Subentry DN. */
+ private final DN passwordPolicySubentryDN;
+ /** The value of the "allow-user-password-changes" property. */
+ private final Boolean pAllowUserPasswordChanges;
+ /** The value of the "force-change-on-reset" property. */
+ private final Boolean pForceChangeOnReset;
+ /** The value of the "grace-login-count" property. */
+ private final Integer pGraceLoginCount;
+ /** The value of the "lockout-duration" property. */
+ private final Long pLockoutDuration;
+ /** The value of the "lockout-failure-count" property. */
+ private final Integer pLockoutFailureCount;
+ /** The value of the "lockout-failure-expiration-interval" property. */
+ private final Long pLockoutFailureExpirationInterval;
+ /** The value of the "max-password-age" property. */
+ private final Long pMaxPasswordAge;
+ /** The value of the "min-password-age" property. */
+ private final Long pMinPasswordAge;
+ /** The value of the "password-attribute" property. */
+ private final AttributeType pPasswordAttribute;
+ /** The value of the "password-change-requires-current-password" property. */
+ private final Boolean pPasswordChangeRequiresCurrentPassword;
+ /** The value of the "password-expiration-warning-interval" property. */
+ private final Long pPasswordExpirationWarningInterval;
+ /** The value of the "password-history-count" property. */
+ private final Integer pPasswordHistoryCount;
+ /** Indicates if the password attribute uses auth password syntax. */
+ private final Boolean pAuthPasswordSyntax;
+ /** The set of password validators if any. */
+ private final Set<DN> pValidatorNames = new HashSet<DN>();
+ /** Used when logging errors due to invalid validator reference. */
+ private final AtomicBoolean isAlreadyLogged = new AtomicBoolean();
// Returns the global default password policy which will be used for deriving
@@ -500,6 +511,36 @@
{
this.pLockoutFailureExpirationInterval = null;
}
+
+ // Now check for the pwdValidatorPolicy OC and its attribute.
+ // Determine if this is a password validator policy object class.
+ ObjectClass pwdValidatorPolicyOC =
+ DirectoryServer.getObjectClass(PWD_OC_VALIDATORPOLICY);
+ if (pwdValidatorPolicyOC != null &&
+ objectClasses.containsKey(pwdValidatorPolicyOC))
+ {
+ AttributeType pwdAttrType =
+ DirectoryServer.getAttributeType(PWD_ATTR_VALIDATOR, true);
+ List<Attribute> pwdAttrList = entry.getAttribute(pwdAttrType);
+ if ((pwdAttrList != null) && (!pwdAttrList.isEmpty()))
+ {
+ for (Attribute attr : pwdAttrList)
+ {
+ for (AttributeValue val : attr)
+ {
+ DN validatorDN = DN.decode(val.getValue());
+ if (DirectoryServer.getPasswordValidator(validatorDN) == null)
+ {
+ throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+ ERR_PWPOLICY_UNKNOWN_VALIDATOR.get(
+ this.passwordPolicySubentryDN.toNormalizedString(),
+ validatorDN.toString(), PWD_ATTR_VALIDATOR));
+ }
+ pValidatorNames.add(validatorDN);
+ }
+ }
+ }
+ }
}
@@ -964,10 +1005,76 @@
@Override
public Collection<PasswordValidator<?>> getPasswordValidators()
{
+ if (!pValidatorNames.isEmpty())
+ {
+ Collection<PasswordValidator<?>> values =
+ new HashSet<PasswordValidator<?>>();
+ for (DN validatorDN : pValidatorNames){
+ PasswordValidator<?> validator = DirectoryServer
+ .getPasswordValidator(validatorDN);
+ if (validator == null) {
+ PasswordValidator<?> errorValidator = new RejectPasswordValidator(
+ validatorDN.toString(), passwordPolicySubentryDN.toString());
+ values.clear();
+ values.add(errorValidator);
+ return values;
+ }
+ values.add(validator);
+ }
+ isAlreadyLogged.set(false);
+ return values;
+ }
return getDefaultPasswordPolicy().getPasswordValidators();
}
+ /**
+ * Implementation of a specific Password Validator that reject all
+ * password due to mis-configured password policy subentry.
+ * This is only used when a subentry is referencing a password
+ * validator that is no longer configured.
+ */
+ private final class RejectPasswordValidator extends
+ PasswordValidator<PasswordValidatorCfg>
+ {
+ private final String validatorName;
+ private final String pwPolicyName;
+ public RejectPasswordValidator(String name, String policyName)
+ {
+ super();
+ validatorName = name;
+ pwPolicyName = policyName;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public void initializePasswordValidator(PasswordValidatorCfg configuration)
+ throws ConfigException
+ {
+ // do nothing
+ }
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public boolean passwordIsAcceptable(ByteString newPassword,
+ Set<ByteString> currentPasswords,
+ Operation operation, Entry userEntry,
+ MessageBuilder invalidReason)
+ {
+ invalidReason.append(ERR_PWPOLICY_REJECT_DUE_TO_UNKNOWN_VALIDATOR_REASON
+ .get());
+
+ // Only log an error once, on first error
+ if (isAlreadyLogged.compareAndSet(false, true)) {
+ logError(ERR_PWPOLICY_REJECT_DUE_TO_UNKNOWN_VALIDATOR_LOG.get(
+ userEntry.getDN().toNormalizedString(), pwPolicyName,
+ validatorName));
+ }
+ return false;
+ }
+ }
/**
* {@inheritDoc}
--
Gitblit v1.10.0