mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
26.57.2007 410c65c22c94384d9afd0741b618c96a97b81ed6
Update the way that the password policy import plugin encodes passwords during
an LDIF import. The basic practice is as follows:

- If the entry specifies a particular password policy, then the default
password storage schemes for that policy will be used to encode the password.

- If the entry does not specify a particular password policy, then the server
will use the password scheme(s) specified in the
ds-cfg-default-user-password-storage-scheme or
ds-cfg-default-auth-password-storage-scheme attribute in the plugin
configuration entry, if they are present.

- If the configuration entry does not specify a default set of storage
schemes, but it uses a password attribute that has the same syntax as the
password attribute used by the server's default password policy, then the
default password storage schemes from the server's default password policy
will be used.

- If all else fails, the server will use SSHA for passwords with the user
password syntax, or SHA1 for passwords with the auth password syntax.

OpenDS Issue Number: 849
1 files added
5 files modified
923 ■■■■ changed files
opends/resource/config/config.ldif 3 ●●●● patch | view | raw | blame | history
opends/resource/schema/02-config.ldif 11 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/PasswordPolicyImportPluginConfiguration.xml 119 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/PluginMessages.java 91 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java 635 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java 64 ●●●● patch | view | raw | blame | history
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
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' )
opends/src/admin/defn/org/opends/server/admin/std/PasswordPolicyImportPluginConfiguration.xml
New file
@@ -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>
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,
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);
  }
}
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);