From 87a32e534959a6ffaf12c6d69ce98197f7bee596 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 20 Sep 2011 11:29:12 +0000
Subject: [PATCH] Issue OPENDJ-262: Implement pass through authentication (PTA)
---
opends/src/server/org/opends/server/api/AuthenticationPolicyState.java | 295 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 273 insertions(+), 22 deletions(-)
diff --git a/opends/src/server/org/opends/server/api/AuthenticationPolicyState.java b/opends/src/server/org/opends/server/api/AuthenticationPolicyState.java
index b71ae6c..7b2973e 100644
--- a/opends/src/server/org/opends/server/api/AuthenticationPolicyState.java
+++ b/opends/src/server/org/opends/server/api/AuthenticationPolicyState.java
@@ -29,9 +29,20 @@
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
+import static org.opends.messages.CoreMessages.*;
+import static org.opends.server.config.ConfigConstants.OP_ATTR_ACCOUNT_DISABLED;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import static org.opends.server.util.StaticUtils.toLowerCase;
+
+import java.util.List;
+
+import org.opends.messages.Message;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.schema.GeneralizedTimeSyntax;
+import org.opends.server.types.*;
@@ -43,6 +54,13 @@
public abstract class AuthenticationPolicyState
{
/**
+ * The tracer object for the debug logger.
+ */
+ private static final DebugTracer TRACER = getTracer();
+
+
+
+ /**
* Returns the authentication policy state for the user provided user. This
* method is equivalent to the following:
*
@@ -68,10 +86,10 @@
* policy for the user.
* @see AuthenticationPolicy#forUser(Entry, boolean)
*/
- public final static AuthenticationPolicyState forUser(Entry userEntry,
- boolean useDefaultOnError) throws DirectoryException
+ public final static AuthenticationPolicyState forUser(final Entry userEntry,
+ final boolean useDefaultOnError) throws DirectoryException
{
- AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry,
+ final AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry,
useDefaultOnError);
return policy.createAuthenticationPolicyState(userEntry);
}
@@ -79,37 +97,184 @@
/**
- * Creates a new abstract authentication policy context.
+ * A utility method which may be used by implementations in order to obtain
+ * the value of the specified attribute from the provided entry as a boolean.
+ *
+ * @param entry
+ * The entry whose attribute is to be parsed as a boolean.
+ * @param attributeType
+ * The attribute type whose value should be parsed as a boolean.
+ * @return The attribute's value represented as a ConditionResult value, or
+ * ConditionResult.UNDEFINED if the specified attribute does not exist
+ * in the entry.
+ * @throws DirectoryException
+ * If the value cannot be decoded as a boolean.
*/
- protected AuthenticationPolicyState()
+ protected static final ConditionResult getBoolean(final Entry entry,
+ final AttributeType attributeType) throws DirectoryException
{
- // No implementation required.
+ final List<Attribute> attrList = entry.getAttribute(attributeType);
+ if (attrList != null)
+ {
+ for (final Attribute a : attrList)
+ {
+ if (a.isEmpty())
+ {
+ continue;
+ }
+
+ final String valueString = toLowerCase(a.iterator().next().getValue()
+ .toString());
+
+ if (valueString.equals("true") || valueString.equals("yes")
+ || valueString.equals("on") || valueString.equals("1"))
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugInfo("Attribute %s resolves to true for user entry "
+ + "%s", attributeType.getNameOrOID(), entry.getDN().toString());
+ }
+
+ return ConditionResult.TRUE;
+ }
+
+ if (valueString.equals("false") || valueString.equals("no")
+ || valueString.equals("off") || valueString.equals("0"))
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugInfo("Attribute %s resolves to false for user "
+ + "entry %s", attributeType.getNameOrOID(), entry.getDN()
+ .toString());
+ }
+
+ return ConditionResult.FALSE;
+ }
+
+ if (debugEnabled())
+ {
+ TRACER.debugError("Unable to resolve value %s for attribute %s "
+ + "in user entry %s as a Boolean.", valueString,
+ attributeType.getNameOrOID(), entry.getDN().toString());
+ }
+
+ final Message message = ERR_PWPSTATE_CANNOT_DECODE_BOOLEAN
+ .get(valueString, attributeType.getNameOrOID(), entry.getDN()
+ .toString());
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
+ }
+ }
+
+ if (debugEnabled())
+ {
+ TRACER.debugInfo("Returning %s because attribute %s does not exist "
+ + "in user entry %s", ConditionResult.UNDEFINED.toString(),
+ attributeType.getNameOrOID(), entry.getDN().toString());
+ }
+
+ return ConditionResult.UNDEFINED;
}
/**
- * Returns {@code true} if the provided password value matches any of the
- * user's passwords.
+ * A utility method which may be used by implementations in order to obtain
+ * the value of the specified attribute from the provided entry as a time in
+ * generalized time format.
*
- * @param password
- * The user-provided password to verify.
- * @return {@code true} if the provided password value matches any of the
- * user's passwords.
+ * @param entry
+ * The entry whose attribute is to be parsed as a boolean.
+ * @param attributeType
+ * The attribute type whose value should be parsed as a generalized
+ * time value.
+ * @return The requested time, or -1 if it could not be determined.
* @throws DirectoryException
- * If verification unexpectedly failed.
+ * If a problem occurs while attempting to decode the value as a
+ * generalized time.
*/
- public abstract boolean passwordMatches(ByteString password)
- throws DirectoryException;
+ protected static final long getGeneralizedTime(final Entry entry,
+ final AttributeType attributeType) throws DirectoryException
+ {
+ long timeValue = -1;
+
+ final List<Attribute> attrList = entry.getAttribute(attributeType);
+ if (attrList != null)
+ {
+ for (final Attribute a : attrList)
+ {
+ if (a.isEmpty())
+ {
+ continue;
+ }
+
+ final AttributeValue v = a.iterator().next();
+ try
+ {
+ timeValue = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(v
+ .getNormalizedValue());
+ }
+ catch (final Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+
+ TRACER.debugWarning("Unable to decode value %s for attribute %s "
+ + "in user entry %s: %s", v.getValue().toString(),
+ attributeType.getNameOrOID(), entry.getDN().toString(),
+ stackTraceToSingleLineString(e));
+ }
+
+ final Message message = ERR_PWPSTATE_CANNOT_DECODE_GENERALIZED_TIME
+ .get(v.getValue().toString(), attributeType.getNameOrOID(), entry
+ .getDN().toString(), String.valueOf(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, e);
+ }
+ break;
+ }
+ }
+
+ if (timeValue == -1)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugInfo("Returning -1 because attribute %s does not "
+ + "exist in user entry %s", attributeType.getNameOrOID(), entry
+ .getDN().toString());
+ }
+ }
+ // FIXME: else to be consistent...
+
+ return timeValue;
+ }
/**
- * Returns the authentication policy associated with this state.
- *
- * @return The authentication policy associated with this state.
+ * A boolean indicating whether or not the account associated with this
+ * authentication state has been administratively disabled.
*/
- public abstract AuthenticationPolicy getAuthenticationPolicy();
+ protected ConditionResult isDisabled = ConditionResult.UNDEFINED;
+
+ /**
+ * The user entry associated with this authentication policy state.
+ */
+ protected final Entry userEntry;
+
+
+
+ /**
+ * Creates a new abstract authentication policy context.
+ *
+ * @param userEntry
+ * The user's entry.
+ */
+ protected AuthenticationPolicyState(final Entry userEntry)
+ {
+ this.userEntry = userEntry;
+ }
@@ -129,6 +294,76 @@
/**
+ * Returns the authentication policy associated with this state.
+ *
+ * @return The authentication policy associated with this state.
+ */
+ public abstract AuthenticationPolicy getAuthenticationPolicy();
+
+
+
+ /**
+ * Returns {@code true} if this authentication policy state is associated with
+ * a user whose account has been administratively disabled.
+ * <p>
+ * The default implementation is use the value of the "ds-pwp-account-disable"
+ * attribute in the user's entry.
+ *
+ * @return {@code true} if this authentication policy state is associated with
+ * a user whose account has been administratively disabled.
+ */
+ public boolean isDisabled()
+ {
+ final AttributeType type = DirectoryServer.getAttributeType(
+ OP_ATTR_ACCOUNT_DISABLED, true);
+ try
+ {
+ isDisabled = getBoolean(userEntry, type);
+ }
+ catch (final Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ isDisabled = ConditionResult.TRUE;
+ if (debugEnabled())
+ {
+ TRACER.debugWarning("User %s is considered administratively "
+ + "disabled because an error occurred while "
+ + "attempting to make the determination: %s.", userEntry.getDN()
+ .toString(), stackTraceToSingleLineString(e));
+ }
+
+ return true;
+ }
+
+ if (isDisabled == ConditionResult.UNDEFINED)
+ {
+ isDisabled = ConditionResult.FALSE;
+ if (debugEnabled())
+ {
+ TRACER.debugInfo("User %s is not administratively disabled since "
+ + "the attribute \"%s\" is not present in the entry.", userEntry
+ .getDN().toString(), OP_ATTR_ACCOUNT_DISABLED);
+ }
+ return false;
+ }
+
+ if (debugEnabled())
+ {
+ TRACER.debugInfo("User %s %s administratively disabled.", userEntry
+ .getDN().toString(), ((isDisabled == ConditionResult.TRUE) ? " is"
+ : " is not"));
+ }
+
+ return isDisabled == ConditionResult.TRUE;
+ }
+
+
+
+ /**
* Returns {@code true} if this authentication policy state is associated with
* a password policy and the method {@link #getAuthenticationPolicy} will
* return a {@code PasswordPolicy}.
@@ -140,4 +375,20 @@
{
return getAuthenticationPolicy().isPasswordPolicy();
}
+
+
+
+ /**
+ * 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;
}
--
Gitblit v1.10.0