From 410c65c22c94384d9afd0741b618c96a97b81ed6 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Tue, 26 Jun 2007 18:57:13 +0000
Subject: [PATCH] Update the way that the password policy import plugin encodes passwords during an LDIF import.  The basic practice is as follows:

---
 opends/resource/schema/02-config.ldif                                                                       |   11 
 opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java                                 |  635 +++++++++++++++++++++++++++++++++------
 opends/src/admin/defn/org/opends/server/admin/std/PasswordPolicyImportPluginConfiguration.xml               |  119 +++++++
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java |   64 +++
 opends/resource/config/config.ldif                                                                          |    3 
 opends/src/server/org/opends/server/messages/PluginMessages.java                                            |   91 +++++
 6 files changed, 818 insertions(+), 105 deletions(-)

diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index d1dad8b..59a1c70 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -1068,7 +1068,7 @@
 objectClass: ds-cfg-password-policy
 cn: Root Password Policy
 ds-cfg-password-attribute: userPassword
-ds-cfg-default-password-storage-scheme: SSHA
+ds-cfg-default-password-storage-scheme: SSHA512
 ds-cfg-allow-expired-password-changes: false
 ds-cfg-allow-multiple-password-values: false
 ds-cfg-allow-pre-encoded-passwords: false
@@ -1278,6 +1278,7 @@
 dn: cn=Password Policy Import,cn=Plugins,cn=config
 objectClass: top
 objectClass: ds-cfg-plugin
+objectClass: ds-cfg-password-policy-import-plugin
 cn: Password Policy Import
 ds-cfg-plugin-class: org.opends.server.plugins.PasswordPolicyImportPlugin
 ds-cfg-plugin-enabled: true
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index ac833f7..4c40418 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -1457,6 +1457,12 @@
   NAME 'ds-cfg-plugin-order-intermediate-response'
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
   X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.429
+  NAME 'ds-cfg-default-user-password-storage-scheme'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.430
+  NAME 'ds-cfg-default-auth-password-storage-scheme'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
   NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL
   MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled )
@@ -2048,4 +2054,9 @@
   ds-cfg-plugin-order-search-result-reference $
   ds-cfg-plugin-order-intermediate-response )
   X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.115
+  NAME 'ds-cfg-password-policy-import-plugin' SUP ds-cfg-plugin STRUCTURAL
+  MAY ( ds-cfg-default-user-password-storage-scheme $
+  ds-cfg-default-auth-password-storage-scheme )
+  X-ORIGIN 'OpenDS Directory Server' )
 
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PasswordPolicyImportPluginConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PasswordPolicyImportPluginConfiguration.xml
new file mode 100644
index 0000000..32f2eb4
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PasswordPolicyImportPluginConfiguration.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+! 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
+!
+!
+!      Portions Copyright 2007 Sun Microsystems, Inc.
+! -->
+
+<adm:managed-object name="password-policy-import-plugin"
+plural-name="password-policy-import-plugins"
+package="org.opends.server.admin.std" extends="plugin"
+xmlns:adm="http://www.opends.org/admin"
+xmlns:ldap="http://www.opends.org/admin-ldap">
+  <adm:synopsis>
+    The
+    <adm:user-friendly-name />
+    is used to ensure that clear-text passwords contained in LDIF entries are
+    properly encoded before they are stored in the appropriate Directory Server
+    backend.
+  </adm:synopsis>
+
+  <adm:profile name="ldap">
+    <ldap:object-class>
+      <ldap:oid>1.3.6.1.4.1.26027.1.2.115</ldap:oid>
+      <ldap:name>ds-cfg-password-policy-import-plugin</ldap:name>
+      <ldap:superior>ds-cfg-plugin</ldap:superior>
+    </ldap:object-class>
+  </adm:profile>
+
+  <adm:property-override name="plugin-class">
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>
+          org.opends.server.plugins.PasswordPolicyImportPlugin
+        </adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+  </adm:property-override>
+
+  <adm:property name="default-user-password-storage-scheme" mandatory="false"
+       multi-valued="true">
+    <adm:synopsis>
+      Specifies the name(s) of the storage scheme(s) that will be used for
+      encoding passwords contained in attributes with the user password syntax
+      for entries that do not include the ds-pwp-password-policy-dn attribute to
+      specify which password policy should be used to govern them.
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          If the default password policy uses the attribute with the user
+          password syntax, then the server will use the default password storage
+          schemes for that password policy.  Otherwise, it will encode user
+          password values using the "SSHA" scheme.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.429</ldap:oid>
+        <ldap:name>ds-cfg-default-user-password-storage-scheme</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+
+  <adm:property name="default-auth-password-storage-scheme" mandatory="false"
+  multi-valued="true">
+    <adm:synopsis>
+      Specifies the name(s) of the storage scheme(s) that will be used for
+      encoding passwords contained in attributes with the auth password syntax
+      for entries that do not include the ds-pwp-password-policy-dn attribute to
+      specify which password policy should be used to govern them.
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          If the default password policy uses an attribute with the auth
+          password syntax, then the server will use the default password storage
+          schemes for that password policy.  Otherwise, it will encode auth
+          password values using the "SHA1" scheme.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.430</ldap:oid>
+        <ldap:name>ds-cfg-default-auth-password-storage-scheme</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+
+</adm:managed-object>
+
diff --git a/opends/src/server/org/opends/server/messages/PluginMessages.java b/opends/src/server/org/opends/server/messages/PluginMessages.java
index 450051b..ce1b4b0 100644
--- a/opends/src/server/org/opends/server/messages/PluginMessages.java
+++ b/opends/src/server/org/opends/server/messages/PluginMessages.java
@@ -789,6 +789,69 @@
 
 
   /**
+   * The message ID for the message that will be used if the password policy
+   * import plugin is not configured with any default auth password schemes and
+   * the SHA1 scheme is not available.  This takes a single argument, which is
+   * the name of the SHA1 scheme.
+   */
+  public static final int MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_AUTH_SCHEMES =
+       CATEGORY_MASK_PLUGIN | SEVERITY_MASK_SEVERE_ERROR | 69;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user specifies a
+   * default auth password storage scheme that is unknown to the server.  This
+   * takes a single argument, which is the specified scheme name.
+   */
+  public static final int MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_AUTH_SCHEME =
+       CATEGORY_MASK_PLUGIN | SEVERITY_MASK_SEVERE_ERROR | 70;
+
+
+
+  /**
+   * The message ID for the message that will be used if the password policy
+   * import plugin is not configured with any default user password schemes and
+   * the SSHA scheme is not available.  This takes a single argument, which is
+   * the name of the SSHA scheme.
+   */
+  public static final int MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_USER_SCHEMES =
+       CATEGORY_MASK_PLUGIN | SEVERITY_MASK_SEVERE_ERROR | 71;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user specifies a
+   * default user password storage scheme that is unknown to the server.  This
+   * takes a single argument, which is the specified scheme name.
+   */
+  public static final int MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_USER_SCHEME =
+       CATEGORY_MASK_PLUGIN | SEVERITY_MASK_SEVERE_ERROR | 72;
+
+
+
+  /**
+   * The message ID for the message that will be used if an entry references a
+   * custom password policy that does not exist.  This takes two arguments,
+   * which are the DN of the target entry and the DN of the password policy.
+   */
+  public static final int MSGID_PLUGIN_PWIMPORT_NO_SUCH_POLICY =
+       CATEGORY_MASK_PLUGIN | SEVERITY_MASK_SEVERE_WARNING | 73;
+
+
+
+  /**
+   * The message ID for the message that will be used if an error occurs while
+   * trying to decode the custom passwod policy DN.  This takes two arguments,
+   * which are the DN of the target entry and a message explaining the problem
+   * that occured.
+   */
+  public static final int MSGID_PLUGIN_PWIMPORT_CANNOT_DECODE_POLICY_DN =
+       CATEGORY_MASK_PLUGIN | SEVERITY_MASK_SEVERE_WARNING | 74;
+
+
+
+  /**
    * Associates a set of generic messages with the message IDs defined in this
    * class.
    */
@@ -1143,6 +1206,34 @@
                     "An error occurred while attempting to encode a password " +
                     "value stored in attribute %s of user entry %s:  %s.  " +
                     "Password values for this user will not be encoded");
+    registerMessage(MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_AUTH_SCHEMES,
+                    "The password policy import plugin is not configured " +
+                    "any default auth password schemes, and the server does " +
+                    "not support the %s auth password scheme");
+    registerMessage(MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_AUTH_SCHEME,
+                    "Auth password storage scheme %s referenced by the " +
+                    "password policy import plugin is not configured for use " +
+                    "in the server");
+    registerMessage(MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_USER_SCHEMES,
+                    "The password policy import plugin is not configured " +
+                    "any default user password schemes, and the server does " +
+                    "not support the %s auth password scheme");
+    registerMessage(MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_USER_SCHEME,
+                    "User password storage scheme %s referenced by the " +
+                    "password policy import plugin is not configured for use " +
+                    "in the server");
+    registerMessage(MSGID_PLUGIN_PWIMPORT_NO_SUCH_POLICY,
+                    "Entry '%s' indicates that it uses custom password " +
+                    "policy '%s', but no such policy is defined in the " +
+                    "server.  Any passwords contained in the entry will be " +
+                    "encoded using the default storage schemes, but " +
+                    "authentication as this user may not be possible");
+    registerMessage(MSGID_PLUGIN_PWIMPORT_CANNOT_DECODE_POLICY_DN,
+                    "An error occurred while attempting to decode the " +
+                    "value of the custom password policy attribute in " +
+                    "entry '%s':  %s.  Any passwords contained in the entry " +
+                    "will be encoded using the default storage schemes, but " +
+                    "authentication as this user may not be possible");
 
 
     registerMessage(MSGID_PLUGIN_TYPE_NOT_SUPPORTED,
diff --git a/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java b/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
index e35cd8b..38a47cb 100644
--- a/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
@@ -30,6 +30,7 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -38,7 +39,9 @@
 
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.meta.PluginCfgDefn;
-import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.admin.std.server.PasswordPolicyImportPluginCfg;
+import org.opends.server.api.Backend;
+import org.opends.server.api.ImportTaskListener;
 import org.opends.server.api.PasswordStorageScheme;
 import org.opends.server.api.plugin.DirectoryServerPlugin;
 import org.opends.server.api.plugin.LDIFPluginResult;
@@ -46,6 +49,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PasswordPolicy;
+import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
 import org.opends.server.types.Attribute;
@@ -53,18 +57,22 @@
 import org.opends.server.types.AttributeValue;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
 import org.opends.server.types.ErrorLogCategory;
 import org.opends.server.types.ErrorLogSeverity;
 import org.opends.server.types.LDIFImportConfig;
 import org.opends.server.types.ResultCode;
 
-import org.opends.server.types.DebugLogLevel;
+import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.extensions.ExtensionsConstants.*;
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.messages.MessageHandler.*;
 import static org.opends.server.messages.PluginMessages.*;
+import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
 
@@ -75,21 +83,37 @@
  * that all of the password values are properly encoded before they are stored.
  */
 public final class PasswordPolicyImportPlugin
-       extends DirectoryServerPlugin<PluginCfg>
-       implements ConfigurationChangeListener<PluginCfg>
+       extends DirectoryServerPlugin<PasswordPolicyImportPluginCfg>
+       implements ConfigurationChangeListener<PasswordPolicyImportPluginCfg>,
+                  ImportTaskListener
 {
   /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
 
-  // The sets of password storage schemes for the auth password attributes.
-  private final HashMap<AttributeType,PasswordStorageScheme[]>
-                     authPasswordSchemes;
 
-  // The sets of password storage schemes for the user password attributes.
-  private final HashMap<AttributeType,PasswordStorageScheme[]>
-                     userPasswordSchemes;
+
+  // The attribute type used to specify the password policy for an entry.
+  private AttributeType customPolicyAttribute;
+
+  // The set of attribute types defined in the schema with the auth password
+  // syntax.
+  private AttributeType[] authPasswordTypes;
+
+  // The set of attribute types defined in the schema with the user password
+  // syntax.
+  private AttributeType[] userPasswordTypes;
+
+  // The set of password storage schemes to use for the various password
+  // policies defined in the server.
+  private HashMap<DN,PasswordStorageScheme[]> schemesByPolicy;
+
+  // The default password storage schemes for auth password attributes.
+  private PasswordStorageScheme[] defaultAuthPasswordSchemes;
+
+  // The default password storage schemes for user password attributes.
+  private PasswordStorageScheme[] defaultUserPasswordSchemes;
 
 
 
@@ -97,82 +121,11 @@
    * Creates a new instance of this Directory Server plugin.  Every plugin must
    * implement a default constructor (it is the only one that will be used to
    * create plugins defined in the configuration), and every plugin constructor
-   * must call <CODE>super()</CODE> as its first element.
+   * must call {@code super()} as its first element.
    */
   public PasswordPolicyImportPlugin()
   {
     super();
-
-
-    // Get the password policies from the Directory Server configuration.  This
-    // is done in the constructor to allow the instance variables to be declared
-    // "final".
-    authPasswordSchemes = new HashMap<AttributeType,PasswordStorageScheme[]>();
-    userPasswordSchemes = new HashMap<AttributeType,PasswordStorageScheme[]>();
-    for (PasswordPolicy p : DirectoryServer.getPasswordPolicies())
-    {
-      AttributeType t = p.getPasswordAttribute();
-      if (p.usesAuthPasswordSyntax())
-      {
-        PasswordStorageScheme[] schemes = authPasswordSchemes.get(t);
-        if (schemes == null)
-        {
-          CopyOnWriteArrayList<PasswordStorageScheme> defaultSchemes =
-               p.getDefaultStorageSchemes();
-          schemes = new PasswordStorageScheme[defaultSchemes.size()];
-          defaultSchemes.toArray(schemes);
-          authPasswordSchemes.put(t, schemes);
-        }
-        else
-        {
-          LinkedHashSet<PasswordStorageScheme> newSchemes =
-               new LinkedHashSet<PasswordStorageScheme>();
-          for (PasswordStorageScheme s : schemes)
-          {
-            newSchemes.add(s);
-          }
-
-          for (PasswordStorageScheme s : p.getDefaultStorageSchemes())
-          {
-            newSchemes.add(s);
-          }
-
-          schemes = new PasswordStorageScheme[newSchemes.size()];
-          newSchemes.toArray(schemes);
-          authPasswordSchemes.put(t, schemes);
-        }
-      }
-      else
-      {
-        PasswordStorageScheme[] schemes = userPasswordSchemes.get(t);
-        if (schemes == null)
-        {
-          CopyOnWriteArrayList<PasswordStorageScheme> defaultSchemes =
-               p.getDefaultStorageSchemes();
-          schemes = new PasswordStorageScheme[defaultSchemes.size()];
-          defaultSchemes.toArray(schemes);
-          userPasswordSchemes.put(t, schemes);
-        }
-        else
-        {
-          LinkedHashSet<PasswordStorageScheme> newSchemes =
-               new LinkedHashSet<PasswordStorageScheme>();
-          for (PasswordStorageScheme s : schemes)
-          {
-            newSchemes.add(s);
-          }
-
-          for (PasswordStorageScheme s : p.getDefaultStorageSchemes())
-          {
-            newSchemes.add(s);
-          }
-
-          schemes = new PasswordStorageScheme[newSchemes.size()];
-          newSchemes.toArray(schemes);
-          userPasswordSchemes.put(t, schemes);
-        }
-      }
-    }
   }
 
 
@@ -182,10 +135,14 @@
    */
   @Override()
   public final void initializePlugin(Set<PluginType> pluginTypes,
-                                     PluginCfg configuration)
+                         PasswordPolicyImportPluginCfg configuration)
          throws ConfigException
   {
-    configuration.addChangeListener(this);
+    configuration.addPasswordPolicyImportChangeListener(this);
+
+    customPolicyAttribute =
+         DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_POLICY_DN, true);
+
 
     // Make sure that the plugin has been enabled for the appropriate types.
     for (PluginType t : pluginTypes)
@@ -203,6 +160,166 @@
           throw new ConfigException(msgID, message);
       }
     }
+
+
+    // Get the set of default password storage schemes for auth password
+    // attributes.
+    PasswordPolicy defaultPolicy = DirectoryServer.getDefaultPasswordPolicy();
+    Set<String> authSchemesSet =
+         configuration.getDefaultAuthPasswordStorageScheme();
+    if ((authSchemesSet == null) || authSchemesSet.isEmpty())
+    {
+      if (defaultPolicy.usesAuthPasswordSyntax())
+      {
+        CopyOnWriteArrayList<PasswordStorageScheme> schemeList =
+             defaultPolicy.getDefaultStorageSchemes();
+        defaultAuthPasswordSchemes =
+             new PasswordStorageScheme[schemeList.size()];
+        schemeList.toArray(defaultAuthPasswordSchemes);
+      }
+      else
+      {
+        defaultAuthPasswordSchemes = new PasswordStorageScheme[1];
+        defaultAuthPasswordSchemes[0] =
+             DirectoryServer.getAuthPasswordStorageScheme(
+                  AUTH_PASSWORD_SCHEME_NAME_SALTED_SHA_1);
+        if (defaultAuthPasswordSchemes[0] == null)
+        {
+          int    msgID   = MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_AUTH_SCHEMES;
+          String message = getMessage(msgID,
+                                      AUTH_PASSWORD_SCHEME_NAME_SALTED_SHA_1);
+          throw new ConfigException(msgID, message);
+        }
+      }
+    }
+    else
+    {
+      defaultAuthPasswordSchemes =
+           new PasswordStorageScheme[authSchemesSet.size()];
+      int i=0;
+      for (String schemeName : authSchemesSet)
+      {
+        defaultAuthPasswordSchemes[i] =
+             DirectoryServer.getAuthPasswordStorageScheme(schemeName);
+        if (defaultAuthPasswordSchemes[i] == null)
+        {
+          int    msgID   = MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_AUTH_SCHEME;
+          String message = getMessage(msgID, schemeName);
+          throw new ConfigException(msgID, message);
+        }
+        i++;
+      }
+    }
+
+
+    // Get the set of default password storage schemes for user password
+    // attributes.
+    Set<String> userSchemeSet =
+         configuration.getDefaultUserPasswordStorageScheme();
+    if ((userSchemeSet == null) || userSchemeSet.isEmpty())
+    {
+      if (! defaultPolicy.usesAuthPasswordSyntax())
+      {
+        CopyOnWriteArrayList<PasswordStorageScheme> schemeList =
+             defaultPolicy.getDefaultStorageSchemes();
+        defaultUserPasswordSchemes =
+             new PasswordStorageScheme[schemeList.size()];
+        schemeList.toArray(defaultUserPasswordSchemes);
+      }
+      else
+      {
+        defaultUserPasswordSchemes = new PasswordStorageScheme[1];
+        defaultUserPasswordSchemes[0] =
+             DirectoryServer.getPasswordStorageScheme(
+                  toLowerCase(STORAGE_SCHEME_NAME_SALTED_SHA_1));
+        if (defaultUserPasswordSchemes[0] == null)
+        {
+          int    msgID   = MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_USER_SCHEMES;
+          String message = getMessage(msgID, STORAGE_SCHEME_NAME_SALTED_SHA_1);
+          throw new ConfigException(msgID, message);
+        }
+      }
+    }
+    else
+    {
+      defaultUserPasswordSchemes =
+           new PasswordStorageScheme[userSchemeSet.size()];
+      int i=0;
+      for (String schemeName : userSchemeSet)
+      {
+        defaultUserPasswordSchemes[i] =
+             DirectoryServer.getPasswordStorageScheme(toLowerCase(schemeName));
+        if (defaultUserPasswordSchemes[i] == null)
+        {
+          int    msgID   = MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_USER_SCHEME;
+          String message = getMessage(msgID, schemeName);
+          throw new ConfigException(msgID, message);
+        }
+        i++;
+      }
+    }
+
+    processImportBegin(null, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void processImportBegin(Backend backend, LDIFImportConfig config)
+  {
+    // Find the set of attribute types with the auth password and user password
+    // syntax defined in the schema.
+    HashSet<AttributeType> authPWTypes = new HashSet<AttributeType>();
+    HashSet<AttributeType> userPWTypes = new HashSet<AttributeType>();
+    for (AttributeType t : DirectoryServer.getAttributeTypes().values())
+    {
+      if (t.getSyntaxOID().equals(SYNTAX_AUTH_PASSWORD_OID))
+      {
+        authPWTypes.add(t);
+      }
+      else if (t.getSyntaxOID().equals(SYNTAX_USER_PASSWORD_OID))
+      {
+        userPWTypes.add(t);
+      }
+    }
+
+
+    // Get the set of password policies defined in the server and get the
+    // attribute types associated with them.
+    HashMap<DN,PasswordStorageScheme[]> schemeMap =
+         new HashMap<DN,PasswordStorageScheme[]>();
+    for (PasswordPolicy p : DirectoryServer.getPasswordPolicies())
+    {
+      CopyOnWriteArrayList<PasswordStorageScheme> schemeList =
+           p.getDefaultStorageSchemes();
+      PasswordStorageScheme[] schemeArray =
+           new PasswordStorageScheme[schemeList.size()];
+      schemeList.toArray(schemeArray);
+      schemeMap.put(p.getConfigEntryDN(), schemeArray);
+    }
+
+
+    AttributeType[] authTypesArray = new AttributeType[authPWTypes.size()];
+    AttributeType[] userTypesArray = new AttributeType[userPWTypes.size()];
+    authPWTypes.toArray(authTypesArray);
+    userPWTypes.toArray(userTypesArray);
+
+    schemesByPolicy   = schemeMap;
+    authPasswordTypes = authTypesArray;
+    userPasswordTypes = userTypesArray;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void processImportEnd(Backend backend, LDIFImportConfig config,
+                               boolean successful)
+  {
+    // No implementation is required.
   }
 
 
@@ -218,18 +335,157 @@
     ArrayList<ByteString> encodedValueList = new ArrayList<ByteString>();
 
 
+    // See if the entry explicitly states the password policy that it should
+    //  use.  If so, then only use it to perform the encoding.
+    List<Attribute> attrList = entry.getAttribute(customPolicyAttribute);
+    if (attrList != null)
+    {
+      DN policyDN = null;
+      PasswordPolicy policy = null;
+policyLoop:
+      for (Attribute a : attrList)
+      {
+        for (AttributeValue v : a.getValues())
+        {
+          try
+          {
+            policyDN = DN.decode(v.getValue());
+            policy = DirectoryServer.getPasswordPolicy(policyDN);
+            if (policy == null)
+            {
+              int    msgID   = MSGID_PLUGIN_PWIMPORT_NO_SUCH_POLICY;
+              String message = getMessage(msgID, String.valueOf(entry.getDN()),
+                                          String.valueOf(policyDN));
+              logError(ErrorLogCategory.PLUGIN, ErrorLogSeverity.SEVERE_WARNING,
+                       message, msgID);
+            }
+            break policyLoop;
+          }
+          catch (DirectoryException de)
+          {
+            int    msgID   = MSGID_PLUGIN_PWIMPORT_CANNOT_DECODE_POLICY_DN;
+            String message = getMessage(msgID, String.valueOf(entry.getDN()),
+                                        de.getErrorMessage());
+            logError(ErrorLogCategory.PLUGIN, ErrorLogSeverity.SEVERE_WARNING,
+                     message, msgID);
+            break policyLoop;
+          }
+        }
+      }
+
+      if (policy != null)
+      {
+        PasswordStorageScheme[] schemes = schemesByPolicy.get(policyDN);
+        if (schemes != null)
+        {
+          attrList = entry.getAttribute(policy.getPasswordAttribute());
+          if (attrList == null)
+          {
+            return LDIFPluginResult.SUCCESS;
+          }
+
+          for (Attribute a : attrList)
+          {
+            encodedValueList.clear();
+
+            LinkedHashSet<AttributeValue> values = a.getValues();
+            Iterator<AttributeValue> iterator = values.iterator();
+            while (iterator.hasNext())
+            {
+              AttributeValue v = iterator.next();
+              ByteString value = v.getValue();
+
+              if (policy.usesAuthPasswordSyntax())
+              {
+                if (! AuthPasswordSyntax.isEncoded(value))
+                {
+                  try
+                  {
+                    for (PasswordStorageScheme s : schemes)
+                    {
+                      encodedValueList.add(s.encodeAuthPassword(value));
+                    }
+
+                    iterator.remove();
+                  }
+                  catch (Exception e)
+                  {
+                    if (debugEnabled())
+                    {
+                      TRACER.debugCaught(DebugLogLevel.ERROR, e);
+                    }
+
+                    int msgID = MSGID_PLUGIN_PWPIMPORT_ERROR_ENCODING_PASSWORD;
+                    String message = getMessage(msgID,
+                         policy.getPasswordAttribute().getNameOrOID(),
+                         String.valueOf(entry.getDN()),
+                         stackTraceToSingleLineString(e));
+                    logError(ErrorLogCategory.PLUGIN,
+                             ErrorLogSeverity.SEVERE_ERROR, message, msgID);
+
+                    encodedValueList.clear();
+                    break;
+                  }
+                }
+              }
+              else
+              {
+                if (! UserPasswordSyntax.isEncoded(value))
+                {
+                  try
+                  {
+                    for (PasswordStorageScheme s : schemes)
+                    {
+                      encodedValueList.add(s.encodePasswordWithScheme(value));
+                    }
+
+                    iterator.remove();
+                  }
+                  catch (Exception e)
+                  {
+                    if (debugEnabled())
+                    {
+                      TRACER.debugCaught(DebugLogLevel.ERROR, e);
+                    }
+
+                    int msgID = MSGID_PLUGIN_PWPIMPORT_ERROR_ENCODING_PASSWORD;
+                    String message = getMessage(msgID,
+                         policy.getPasswordAttribute().getNameOrOID(),
+                         String.valueOf(entry.getDN()),
+                         stackTraceToSingleLineString(e));
+                    logError(ErrorLogCategory.PLUGIN,
+                             ErrorLogSeverity.SEVERE_ERROR, message, msgID);
+
+                    encodedValueList.clear();
+                    break;
+                  }
+                }
+              }
+            }
+
+            for (ByteString s : encodedValueList)
+            {
+              values.add(new AttributeValue(policy.getPasswordAttribute(), s));
+            }
+          }
+
+          return LDIFPluginResult.SUCCESS;
+        }
+      }
+    }
+
+
     // Iterate through the list of auth password attributes.  If any of them
     // are present and their values are not encoded, then encode them with all
     // appropriate schemes.
-    for (AttributeType t : authPasswordSchemes.keySet())
+    for (AttributeType t : authPasswordTypes)
     {
-      List<Attribute> attrList = entry.getAttribute(t);
+      attrList = entry.getAttribute(t);
       if ((attrList == null) || attrList.isEmpty())
       {
         continue;
       }
 
-      PasswordStorageScheme[] schemes = authPasswordSchemes.get(t);
       for (Attribute a : attrList)
       {
         encodedValueList.clear();
@@ -244,7 +500,7 @@
           {
             try
             {
-              for (PasswordStorageScheme s : schemes)
+              for (PasswordStorageScheme s : defaultAuthPasswordSchemes)
               {
                 encodedValueList.add(s.encodeAuthPassword(value));
               }
@@ -282,15 +538,14 @@
     // Iterate through the list of user password attributes.  If any of them
     // are present and their values are not encoded, then encode them with all
     // appropriate schemes.
-    for (AttributeType t : userPasswordSchemes.keySet())
+    for (AttributeType t : userPasswordTypes)
     {
-      List<Attribute> attrList = entry.getAttribute(t);
+      attrList = entry.getAttribute(t);
       if ((attrList == null) || attrList.isEmpty())
       {
         continue;
       }
 
-      PasswordStorageScheme[] schemes = userPasswordSchemes.get(t);
       for (Attribute a : attrList)
       {
         encodedValueList.clear();
@@ -305,7 +560,7 @@
           {
             try
             {
-              for (PasswordStorageScheme s : schemes)
+              for (PasswordStorageScheme s : defaultUserPasswordSchemes)
               {
                 encodedValueList.add(s.encodePasswordWithScheme(value));
               }
@@ -348,7 +603,8 @@
   /**
    * {@inheritDoc}
    */
-  public boolean isConfigurationChangeAcceptable(PluginCfg configuration,
+  public boolean isConfigurationChangeAcceptable(
+                      PasswordPolicyImportPluginCfg configuration,
                       List<String> unacceptableReasons)
   {
     boolean configAcceptable = true;
@@ -371,6 +627,86 @@
       }
     }
 
+
+    // Get the set of default password storage schemes for auth password
+    // attributes.
+    Set<String> authSchemesSet =
+         configuration.getDefaultAuthPasswordStorageScheme();
+    if ((authSchemesSet == null) || authSchemesSet.isEmpty())
+    {
+      PasswordStorageScheme[] defaultAuthSchemes = new PasswordStorageScheme[1];
+      defaultAuthSchemes[0] =
+           DirectoryServer.getAuthPasswordStorageScheme(
+                AUTH_PASSWORD_SCHEME_NAME_SALTED_SHA_1);
+      if (defaultAuthSchemes[0] == null)
+      {
+        int    msgID   = MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_AUTH_SCHEMES;
+        String message = getMessage(msgID,
+                                    AUTH_PASSWORD_SCHEME_NAME_SALTED_SHA_1);
+        unacceptableReasons.add(message);
+        configAcceptable = false;
+      }
+    }
+    else
+    {
+      PasswordStorageScheme[] defaultAuthSchemes =
+           new PasswordStorageScheme[authSchemesSet.size()];
+      int i=0;
+      for (String schemeName : authSchemesSet)
+      {
+        defaultAuthSchemes[i] =
+             DirectoryServer.getAuthPasswordStorageScheme(schemeName);
+        if (defaultAuthSchemes[i] == null)
+        {
+          int    msgID   = MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_AUTH_SCHEME;
+          String message = getMessage(msgID, schemeName);
+          unacceptableReasons.add(message);
+          configAcceptable = false;
+        }
+        i++;
+      }
+    }
+
+
+    // Get the set of default password storage schemes for user password
+    // attributes.
+    Set<String> userSchemeSet =
+         configuration.getDefaultUserPasswordStorageScheme();
+    if ((userSchemeSet == null) || userSchemeSet.isEmpty())
+    {
+      PasswordStorageScheme[] defaultUserSchemes = new PasswordStorageScheme[1];
+      defaultUserSchemes[0] =
+           DirectoryServer.getPasswordStorageScheme(
+                toLowerCase(STORAGE_SCHEME_NAME_SALTED_SHA_1));
+      if (defaultUserSchemes[0] == null)
+      {
+        int    msgID   = MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_USER_SCHEMES;
+        String message = getMessage(msgID, STORAGE_SCHEME_NAME_SALTED_SHA_1);
+        unacceptableReasons.add(message);
+        configAcceptable = false;
+      }
+    }
+    else
+    {
+      PasswordStorageScheme[] defaultUserSchemes =
+           new PasswordStorageScheme[userSchemeSet.size()];
+      int i=0;
+      for (String schemeName : userSchemeSet)
+      {
+        defaultUserSchemes[i] =
+             DirectoryServer.getPasswordStorageScheme(toLowerCase(schemeName));
+        if (defaultUserSchemes[i] == null)
+        {
+          int    msgID   = MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_USER_SCHEME;
+          String message = getMessage(msgID, schemeName);
+          unacceptableReasons.add(message);
+          configAcceptable = false;
+        }
+        i++;
+      }
+    }
+
+
     return configAcceptable;
   }
 
@@ -379,10 +715,115 @@
   /**
    * {@inheritDoc}
    */
-  public ConfigChangeResult applyConfigurationChange(PluginCfg configuration)
+  public ConfigChangeResult applyConfigurationChange(
+                                 PasswordPolicyImportPluginCfg configuration)
   {
-    // No implementation is required.
-    return new ConfigChangeResult(ResultCode.SUCCESS, false);
+    ResultCode        resultCode          = ResultCode.SUCCESS;
+    boolean           adminActionRequired = false;
+    ArrayList<String> messages            = new ArrayList<String>();
+
+
+    // Get the set of default password storage schemes for auth password
+    // attributes.
+    PasswordPolicy defaultPolicy = DirectoryServer.getDefaultPasswordPolicy();
+    PasswordStorageScheme[] defaultAuthSchemes;
+    Set<String> authSchemesSet =
+         configuration.getDefaultAuthPasswordStorageScheme();
+    if ((authSchemesSet == null) || authSchemesSet.isEmpty())
+    {
+      if (defaultPolicy.usesAuthPasswordSyntax())
+      {
+        CopyOnWriteArrayList<PasswordStorageScheme> schemeList =
+             defaultPolicy.getDefaultStorageSchemes();
+        defaultAuthSchemes =
+             new PasswordStorageScheme[schemeList.size()];
+        schemeList.toArray(defaultAuthSchemes);
+      }
+      else
+      {
+        defaultAuthSchemes = new PasswordStorageScheme[1];
+        defaultAuthSchemes[0] =
+             DirectoryServer.getAuthPasswordStorageScheme(
+                  AUTH_PASSWORD_SCHEME_NAME_SALTED_SHA_1);
+        if (defaultAuthSchemes[0] == null)
+        {
+          resultCode = DirectoryServer.getServerErrorResultCode();
+
+          int msgID = MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_AUTH_SCHEMES;
+          messages.add(getMessage(msgID,
+                                  AUTH_PASSWORD_SCHEME_NAME_SALTED_SHA_1));
+        }
+      }
+    }
+    else
+    {
+      defaultAuthSchemes = new PasswordStorageScheme[authSchemesSet.size()];
+      int i=0;
+      for (String schemeName : authSchemesSet)
+      {
+        defaultAuthSchemes[i] =
+             DirectoryServer.getAuthPasswordStorageScheme(schemeName);
+        if (defaultAuthSchemes[i] == null)
+        {
+          resultCode = DirectoryServer.getServerErrorResultCode();
+
+          int msgID = MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_AUTH_SCHEME;
+          messages.add(getMessage(msgID, schemeName));
+        }
+        i++;
+      }
+    }
+
+
+    // Get the set of default password storage schemes for user password
+    // attributes.
+    PasswordStorageScheme[] defaultUserSchemes;
+    Set<String> userSchemeSet =
+         configuration.getDefaultUserPasswordStorageScheme();
+    if ((userSchemeSet == null) || userSchemeSet.isEmpty())
+    {
+      if (! defaultPolicy.usesAuthPasswordSyntax())
+      {
+        CopyOnWriteArrayList<PasswordStorageScheme> schemeList =
+             defaultPolicy.getDefaultStorageSchemes();
+        defaultUserSchemes =
+             new PasswordStorageScheme[schemeList.size()];
+        schemeList.toArray(defaultUserSchemes);
+      }
+      else
+      {
+        defaultUserSchemes = new PasswordStorageScheme[1];
+        defaultUserSchemes[0] = DirectoryServer.getPasswordStorageScheme(
+                  toLowerCase(STORAGE_SCHEME_NAME_SALTED_SHA_1));
+        if (defaultUserSchemes[0] == null)
+        {
+          resultCode = DirectoryServer.getServerErrorResultCode();
+
+          int msgID = MSGID_PLUGIN_PWIMPORT_NO_DEFAULT_USER_SCHEMES;
+          messages.add(getMessage(msgID, STORAGE_SCHEME_NAME_SALTED_SHA_1));
+        }
+      }
+    }
+    else
+    {
+      defaultUserSchemes = new PasswordStorageScheme[userSchemeSet.size()];
+      int i=0;
+      for (String schemeName : userSchemeSet)
+      {
+        defaultUserSchemes[i] =
+             DirectoryServer.getPasswordStorageScheme(toLowerCase(schemeName));
+        if (defaultUserSchemes[i] == null)
+        {
+          resultCode = DirectoryServer.getServerErrorResultCode();
+
+          int msgID = MSGID_PLUGIN_PWIMPORT_INVALID_DEFAULT_USER_SCHEME;
+          messages.add(getMessage(msgID, schemeName));
+        }
+        i++;
+      }
+    }
+
+    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
   }
 }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
index 7087eef..4e10d1b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
@@ -35,8 +35,8 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.server.AdminTestCaseUtils;
-import org.opends.server.admin.std.meta.PluginCfgDefn;
-import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.admin.std.meta.PasswordPolicyImportPluginCfgDefn;
+import org.opends.server.admin.std.server.PasswordPolicyImportPluginCfg;
 import org.opends.server.api.plugin.PluginType;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
@@ -86,11 +86,59 @@
          "dn: cn=Password Policy Import,cn=Plugins,cn=config",
          "objectClass: top",
          "objectClass: ds-cfg-plugin",
+         "objectClass: ds-cfg-password-policy-import-plugin",
          "cn: Password Policy Import",
          "ds-cfg-plugin-class: org.opends.server.plugins." +
               "PasswordPolicyImportPlugin",
          "ds-cfg-plugin-enabled: true",
-         "ds-cfg-plugin-type: ldifImport");
+         "ds-cfg-plugin-type: ldifImport",
+         "",
+         "dn: cn=Password Policy Import,cn=Plugins,cn=config",
+         "objectClass: top",
+         "objectClass: ds-cfg-plugin",
+         "objectClass: ds-cfg-password-policy-import-plugin",
+         "cn: Password Policy Import",
+         "ds-cfg-plugin-class: org.opends.server.plugins." +
+              "PasswordPolicyImportPlugin",
+         "ds-cfg-plugin-enabled: true",
+         "ds-cfg-plugin-type: ldifImport",
+         "ds-cfg-default-user-password-storage-scheme: SSHA",
+         "",
+         "dn: cn=Password Policy Import,cn=Plugins,cn=config",
+         "objectClass: top",
+         "objectClass: ds-cfg-plugin",
+         "objectClass: ds-cfg-password-policy-import-plugin",
+         "cn: Password Policy Import",
+         "ds-cfg-plugin-class: org.opends.server.plugins." +
+              "PasswordPolicyImportPlugin",
+         "ds-cfg-plugin-enabled: true",
+         "ds-cfg-plugin-type: ldifImport",
+         "ds-cfg-default-user-password-storage-scheme: CRYPT",
+         "ds-cfg-default-user-password-storage-scheme: SSHA",
+         "",
+         "dn: cn=Password Policy Import,cn=Plugins,cn=config",
+         "objectClass: top",
+         "objectClass: ds-cfg-plugin",
+         "objectClass: ds-cfg-password-policy-import-plugin",
+         "cn: Password Policy Import",
+         "ds-cfg-plugin-class: org.opends.server.plugins." +
+              "PasswordPolicyImportPlugin",
+         "ds-cfg-plugin-enabled: true",
+         "ds-cfg-plugin-type: ldifImport",
+         "ds-cfg-default-auth-password-storage-scheme: SHA1",
+         "",
+         "dn: cn=Password Policy Import,cn=Plugins,cn=config",
+         "objectClass: top",
+         "objectClass: ds-cfg-plugin",
+         "objectClass: ds-cfg-password-policy-import-plugin",
+         "cn: Password Policy Import",
+         "ds-cfg-plugin-class: org.opends.server.plugins." +
+              "PasswordPolicyImportPlugin",
+         "ds-cfg-plugin-enabled: true",
+         "ds-cfg-plugin-type: ldifImport",
+         "ds-cfg-default-user-password-storage-scheme: SSHA",
+         "ds-cfg-default-auth-password-storage-scheme: SHA1"
+    );
 
     Object[][] array = new Object[entries.size()][1];
     for (int i=0; i < array.length; i++)
@@ -124,8 +172,9 @@
       }
     }
 
-    PluginCfg configuration = AdminTestCaseUtils.getConfiguration(
-        PluginCfgDefn.getInstance(), e);
+    PasswordPolicyImportPluginCfg configuration =
+         AdminTestCaseUtils.getConfiguration(
+              PasswordPolicyImportPluginCfgDefn.getInstance(), e);
 
     PasswordPolicyImportPlugin plugin = new PasswordPolicyImportPlugin();
     plugin.initializePlugin(pluginTypes, configuration);
@@ -155,6 +204,7 @@
            "dn: cn=Password Policy Import,cn=Plugins,cn=config",
            "objectClass: top",
            "objectClass: ds-cfg-plugin",
+           "objectClass: ds-cfg-password-policy-import-plugin",
            "cn: Password Policy Import",
            "ds-cfg-plugin-class: org.opends.server.plugins." +
                 "PasswordPolicyImportPlugin",
@@ -200,9 +250,9 @@
     }
 
 
-    PluginCfg configuration =
+    PasswordPolicyImportPluginCfg configuration =
          AdminTestCaseUtils.getConfiguration(
-              PluginCfgDefn.getInstance(), e);
+              PasswordPolicyImportPluginCfgDefn.getInstance(), e);
 
     PasswordPolicyImportPlugin plugin = new PasswordPolicyImportPlugin();
     plugin.initializePlugin(pluginTypes, configuration);

--
Gitblit v1.10.0