From 12823021edd6b9c4262466ddbfbce6aa8d36d0b5 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)

---
 opendj-sdk/opends/src/server/org/opends/server/api/AuthenticationPolicy.java |  244 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 243 insertions(+), 1 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/AuthenticationPolicy.java b/opendj-sdk/opends/src/server/org/opends/server/api/AuthenticationPolicy.java
index aeb4ef2..5054186 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/AuthenticationPolicy.java
+++ b/opendj-sdk/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.

--
Gitblit v1.10.0