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

matthew_swift
23.26.2007 feb5d90ec016c99712f19c5485cf7633cd38f111
opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java
@@ -29,21 +29,15 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.ExternalSASLMechanismHandlerCfg;
import org.opends.server.api.CertificateMapper;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.ConnectionSecurityProvider;
import org.opends.server.api.SASLMechanismHandler;
import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.config.DNConfigAttribute;
import org.opends.server.config.MultiChoiceConfigAttribute;
import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1OctetString;
@@ -78,29 +72,10 @@
 * other places to find and evaluate this external authentication information.
 */
public class ExternalSASLMechanismHandler
       extends SASLMechanismHandler
       implements ConfigurableComponent
       extends SASLMechanismHandler<ExternalSASLMechanismHandlerCfg>
       implements ConfigurationChangeListener<
                       ExternalSASLMechanismHandlerCfg>
{
  /**
   * The set of value strings that may be used for the peer certificate
   * validation policy.
   */
  private static final HashSet<String> validationValueStrings;
  static
  {
    validationValueStrings = new HashSet<String>(3);
    validationValueStrings.add(CertificateValidationPolicy.ALWAYS.toString());
    validationValueStrings.add(CertificateValidationPolicy.NEVER.toString());
    validationValueStrings.add(
         CertificateValidationPolicy.IFPRESENT.toString());
  }
  // The attribute type that should hold the certificates to use for the
  // validation.
  private AttributeType certificateAttributeType;
@@ -109,12 +84,12 @@
  // client with a certificate in the user's entry.
  private CertificateValidationPolicy validationPolicy;
  // The DN of the configuration entry for the associated certificate mapper.
  private DN certificateMapperDN;
  // The DN of the configuration entry for this SASL mechanism handler.
  private DN configEntryDN;
  // The current configuration for this SASL mechanism handler.
  private ExternalSASLMechanismHandlerCfg currentConfig;
  /**
@@ -125,7 +100,6 @@
  public ExternalSASLMechanismHandler()
  {
    super();
  }
@@ -134,136 +108,65 @@
   * {@inheritDoc}
   */
  @Override()
  public void initializeSASLMechanismHandler(ConfigEntry configEntry)
  public void initializeSASLMechanismHandler(
                   ExternalSASLMechanismHandlerCfg configuration)
         throws ConfigException, InitializationException
  {
    this.configEntryDN = configEntry.getDN();
    configuration.addExternalChangeListener(this);
    currentConfig = configuration;
    configEntryDN = configuration.dn();
    // See if we should attempt to validate client certificates against those in
    // the corresponding user's entry.
    validationPolicy = CertificateValidationPolicy.NEVER;
    int msgID = MSGID_SASLEXTERNAL_DESCRIPTION_VALIDATION_POLICY;
    MultiChoiceConfigAttribute validateStub =
         new MultiChoiceConfigAttribute(ATTR_CLIENT_CERT_VALIDATION_POLICY,
                                        getMessage(msgID), false, false, false,
                                        validationValueStrings);
    try
    switch (configuration.getCertificateValidationPolicy())
    {
      MultiChoiceConfigAttribute validateAttr =
           (MultiChoiceConfigAttribute)
           configEntry.getConfigAttribute(validateStub);
      if (validateAttr != null)
      {
        validationPolicy = CertificateValidationPolicy.policyForName(
                                validateAttr.activeValue());
        if (validationPolicy == null)
        {
          msgID = MSGID_SASLEXTERNAL_INVALID_VALIDATION_VALUE;
          String message = getMessage(msgID, String.valueOf(configEntryDN),
                                      validateAttr.activeValue());
          throw new ConfigException(msgID, message);
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_VALIDATION_POLICY;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  stackTraceToSingleLineString(e));
      throw new InitializationException(msgID, message, e);
      case NEVER:
        validationPolicy = CertificateValidationPolicy.NEVER;
        break;
      case IFPRESENT:
        validationPolicy = CertificateValidationPolicy.IFPRESENT;
        break;
      case ALWAYS:
        validationPolicy = CertificateValidationPolicy.ALWAYS;
        break;
    }
    // Get the attribute type to use for validating the certificates.  If none
    // is provided, then default to the userCertificate type.
    String attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
    msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERTIFICATE_ATTRIBUTE;
    StringConfigAttribute certAttributeStub =
         new StringConfigAttribute(ATTR_VALIDATION_CERT_ATTRIBUTE,
                                   getMessage(msgID), false, false, false);
    try
    String attrTypeName = configuration.getCertificateAttribute();
    if (attrTypeName == null)
    {
      StringConfigAttribute certAttributeAttr =
           (StringConfigAttribute)
           configEntry.getConfigAttribute(certAttributeStub);
      if (certAttributeAttr != null)
      {
        attrTypeName = toLowerCase(certAttributeAttr.activeValue());
      }
      attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_ATTR;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  stackTraceToSingleLineString(e));
      throw new InitializationException(msgID, message, e);
    }
    certificateAttributeType = DirectoryServer.getAttributeType(attrTypeName);
    certificateAttributeType =
         DirectoryServer.getAttributeType(toLowerCase(attrTypeName), false);
    if (certificateAttributeType == null)
    {
      msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
      int    msgID   = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
      String message = getMessage(msgID, String.valueOf(attrTypeName),
                                  String.valueOf(configEntryDN));
      throw new ConfigException(msgID, message);
    }
    // Get the DN of the certificate mapper to use with this handler.
    msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERT_MAPPER_DN;
    DNConfigAttribute certMapperStub =
         new DNConfigAttribute(ATTR_CERTMAPPER_DN, getMessage(msgID), true,
                               false, false);
    try
    // Make sure that the configured certificate mapper is valid.
    CertificateMapper certificateMapper =
         DirectoryServer.getCertificateMapper(
              configuration.getCertificateMapperDN());
    if (certificateMapper == null)
    {
      DNConfigAttribute certMapperAttr =
           (DNConfigAttribute) configEntry.getConfigAttribute(certMapperStub);
      if (certMapperAttr == null)
      {
        msgID = MSGID_SASLEXTERNAL_NO_CERTIFICATE_MAPPER_DN;
        String message = getMessage(msgID, String.valueOf(configEntryDN));
        throw new ConfigException(msgID, message);
      }
      else
      {
        certificateMapperDN = certMapperAttr.activeValue();
        CertificateMapper mapper =
             DirectoryServer.getCertificateMapper(certificateMapperDN);
        if (mapper == null)
        {
          msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
          String message = getMessage(msgID, String.valueOf(configEntryDN),
                                      String.valueOf(certificateMapperDN));
          throw new ConfigException(msgID, message);
        }
      }
    }
    catch (ConfigException ce)
    {
      throw ce;
    }
    catch (Exception e)
    {
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_MAPPER_DN;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  stackTraceToSingleLineString(e));
      int    msgID   = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
      String message =
           getMessage(msgID, String.valueOf(configEntryDN),
                      String.valueOf(configuration.getCertificateMapperDN()));
      throw new ConfigException(msgID, message);
    }
    DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_EXTERNAL, this);
    DirectoryServer.registerConfigurableComponent(this);
  }
@@ -274,7 +177,7 @@
  @Override()
  public void finalizeSASLMechanismHandler()
  {
    DirectoryServer.deregisterConfigurableComponent(this);
    currentConfig.removeExternalChangeListener(this);
    DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_EXTERNAL);
  }
@@ -287,6 +190,11 @@
  @Override()
  public void processSASLBind(BindOperation bindOperation)
  {
    ExternalSASLMechanismHandlerCfg config = currentConfig;
    AttributeType certificateAttributeType = this.certificateAttributeType;
    CertificateValidationPolicy validationPolicy = this.validationPolicy;
    // Get the client connection used for the bind request, and get the
    // security manager for that connection.  If either are null, then fail.
    ClientConnection clientConnection = bindOperation.getClientConnection();
@@ -346,6 +254,7 @@
    // Get the certificate mapper to use to map the certificate to a user entry.
    DN certificateMapperDN = config.getCertificateMapperDN();
    CertificateMapper certificateMapper =
         DirectoryServer.getCertificateMapper(certificateMapperDN);
    if (certificateMapper == null)
@@ -526,401 +435,6 @@
  /**
   * Retrieves the DN of the configuration entry with which this component is
   * associated.
   *
   * @return  The DN of the configuration entry with which this component is
   *          associated.
   */
  public DN getConfigurableComponentEntryDN()
  {
    return configEntryDN;
  }
  /**
   * Retrieves the set of configuration attributes that are associated with this
   * configurable component.
   *
   * @return  The set of configuration attributes that are associated with this
   *          configurable component.
   */
  public List<ConfigAttribute> getConfigurationAttributes()
  {
    LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
    int msgID = MSGID_SASLEXTERNAL_DESCRIPTION_VALIDATION_POLICY;
    attrList.add(new MultiChoiceConfigAttribute(
                          ATTR_CLIENT_CERT_VALIDATION_POLICY, getMessage(msgID),
                          false, false, false, validationValueStrings,
                          validationPolicy.toString()));
    msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERTIFICATE_ATTRIBUTE;
    String certTypeStr = certificateAttributeType.getNameOrOID();
    attrList.add(new StringConfigAttribute(ATTR_VALIDATION_CERT_ATTRIBUTE,
                                           getMessage(msgID), false, false,
                                           false, certTypeStr));
    msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERT_MAPPER_DN;
    attrList.add(new DNConfigAttribute(ATTR_CERTMAPPER_DN, getMessage(msgID),
                                       true, false, false,
                                       certificateMapperDN));
    return attrList;
  }
  /**
   * Indicates whether the provided configuration entry has an acceptable
   * configuration for this component.  If it does not, then detailed
   * information about the problem(s) should be added to the provided list.
   *
   * @param  configEntry          The configuration entry for which to make the
   *                              determination.
   * @param  unacceptableReasons  A list that can be used to hold messages about
   *                              why the provided entry does not have an
   *                              acceptable configuration.
   *
   * @return  <CODE>true</CODE> if the provided entry has an acceptable
   *          configuration for this component, or <CODE>false</CODE> if not.
   */
  public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
                                            List<String> unacceptableReasons)
  {
    // Look at the validation policy configuration.
    int msgID = MSGID_SASLEXTERNAL_DESCRIPTION_VALIDATION_POLICY;
    MultiChoiceConfigAttribute validateStub =
         new MultiChoiceConfigAttribute(ATTR_CLIENT_CERT_VALIDATION_POLICY,
                                        getMessage(msgID), false, false, false,
                                        validationValueStrings);
    try
    {
      MultiChoiceConfigAttribute validateAttr =
           (MultiChoiceConfigAttribute)
           configEntry.getConfigAttribute(validateStub);
      if (validateAttr != null)
      {
        if (CertificateValidationPolicy.policyForName(
                 validateAttr.activeValue())== null)
        {
          msgID = MSGID_SASLEXTERNAL_INVALID_VALIDATION_VALUE;
          unacceptableReasons.add(getMessage(msgID,
                                             String.valueOf(configEntryDN),
                                             validateAttr.activeValue()));
          return false;
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_VALIDATION_POLICY;
      unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
                                         stackTraceToSingleLineString(e)));
      return false;
    }
    // Look at the certificate attribute type configuration.
    String attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
    msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERTIFICATE_ATTRIBUTE;
    StringConfigAttribute certAttributeStub =
         new StringConfigAttribute(ATTR_VALIDATION_CERT_ATTRIBUTE,
                                   getMessage(msgID), false, false, false);
    try
    {
      StringConfigAttribute certAttributeAttr =
           (StringConfigAttribute)
           configEntry.getConfigAttribute(certAttributeStub);
      if (certAttributeAttr != null)
      {
        attrTypeName = toLowerCase(certAttributeAttr.activeValue());
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_ATTR;
      unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
                                         stackTraceToSingleLineString(e)));
      return false;
    }
    if (DirectoryServer.getAttributeType(attrTypeName) == null)
    {
      msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
      unacceptableReasons.add(getMessage(msgID, String.valueOf(attrTypeName),
                                         String.valueOf(configEntryDN)));
      return false;
    }
    // Look at the certificate mapper DN.
    msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERT_MAPPER_DN;
    DNConfigAttribute certMapperStub =
         new DNConfigAttribute(ATTR_CERTMAPPER_DN, getMessage(msgID), true,
                               false, false);
    try
    {
      DNConfigAttribute certMapperAttr =
           (DNConfigAttribute) configEntry.getConfigAttribute(certMapperStub);
      if (certMapperAttr == null)
      {
        msgID = MSGID_SASLEXTERNAL_NO_CERTIFICATE_MAPPER_DN;
        String message = getMessage(msgID, String.valueOf(configEntryDN));
        unacceptableReasons.add(message);
        return false;
      }
      else
      {
        DN certMapperDN = certMapperAttr.activeValue();
        CertificateMapper mapper =
             DirectoryServer.getCertificateMapper(certMapperDN);
        if (mapper == null)
        {
          msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
          String message = getMessage(msgID, String.valueOf(configEntryDN),
                                      String.valueOf(certMapperDN));
          unacceptableReasons.add(message);
          return false;
        }
      }
    }
    catch (Exception e)
    {
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_MAPPER_DN;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  stackTraceToSingleLineString(e));
      unacceptableReasons.add(message);
      return false;
    }
    // If we've gotten to this point, then everything must be OK.
    return true;
  }
  /**
   * Makes a best-effort attempt to apply the configuration contained in the
   * provided entry.  Information about the result of this processing should be
   * added to the provided message list.  Information should always be added to
   * this list if a configuration change could not be applied.  If detailed
   * results are requested, then information about the changes applied
   * successfully (and optionally about parameters that were not changed) should
   * also be included.
   *
   * @param  configEntry      The entry containing the new configuration to
   *                          apply for this component.
   * @param  detailedResults  Indicates whether detailed information about the
   *                          processing should be added to the list.
   *
   * @return  Information about the result of the configuration update.
   */
  public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
                                                  boolean detailedResults)
  {
    ResultCode        resultCode          = ResultCode.SUCCESS;
    boolean           adminActionRequired = false;
    ArrayList<String> messages            = new ArrayList<String>();
    // Look at the validation policy configuration.
    CertificateValidationPolicy newValidationPolicy =
         CertificateValidationPolicy.NEVER;
    int msgID = MSGID_SASLEXTERNAL_DESCRIPTION_VALIDATION_POLICY;
    MultiChoiceConfigAttribute validateStub =
         new MultiChoiceConfigAttribute(ATTR_CLIENT_CERT_VALIDATION_POLICY,
                                        getMessage(msgID), false, false, false,
                                        validationValueStrings);
    try
    {
      MultiChoiceConfigAttribute validateAttr =
           (MultiChoiceConfigAttribute)
           configEntry.getConfigAttribute(validateStub);
      if (validateAttr != null)
      {
        newValidationPolicy = CertificateValidationPolicy.policyForName(
                                   validateAttr.activeValue());
        if (newValidationPolicy == null)
        {
          resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
          msgID = MSGID_SASLEXTERNAL_INVALID_VALIDATION_VALUE;
          messages.add(getMessage(msgID, String.valueOf(configEntryDN),
                                  validateAttr.activeValue()));
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        debugCaught(DebugLogLevel.ERROR, e);
      }
      resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_VALIDATION_POLICY;
      messages.add(getMessage(msgID, String.valueOf(configEntryDN),
                              stackTraceToSingleLineString(e)));
    }
    // Look at the certificate attribute type configuration.
    String attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
    msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERTIFICATE_ATTRIBUTE;
    StringConfigAttribute certAttributeStub =
         new StringConfigAttribute(ATTR_VALIDATION_CERT_ATTRIBUTE,
                                   getMessage(msgID), false, false, false);
    try
    {
      StringConfigAttribute certAttributeAttr =
           (StringConfigAttribute)
           configEntry.getConfigAttribute(certAttributeStub);
      if (certAttributeAttr != null)
      {
        attrTypeName = toLowerCase(certAttributeAttr.activeValue());
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_ATTR;
      messages.add(getMessage(msgID, String.valueOf(configEntryDN),
                              stackTraceToSingleLineString(e)));
      resultCode = DirectoryServer.getServerErrorResultCode();
    }
    AttributeType newCertType = DirectoryServer.getAttributeType(attrTypeName);
    if (newCertType == null)
    {
      msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
      messages.add(getMessage(msgID, String.valueOf(attrTypeName),
                              String.valueOf(configEntryDN)));
      if (resultCode == ResultCode.SUCCESS)
      {
        resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
      }
    }
    // Look at the certificate mapper DN.
    DN newCertificateMapperDN = null;
    msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERT_MAPPER_DN;
    DNConfigAttribute certMapperStub =
         new DNConfigAttribute(ATTR_CERTMAPPER_DN, getMessage(msgID), true,
                               false, false);
    try
    {
      DNConfigAttribute certMapperAttr =
           (DNConfigAttribute) configEntry.getConfigAttribute(certMapperStub);
      if (certMapperAttr == null)
      {
        if (resultCode == ResultCode.SUCCESS)
        {
          resultCode = ResultCode.OBJECTCLASS_VIOLATION;
        }
        msgID = MSGID_SASLEXTERNAL_NO_CERTIFICATE_MAPPER_DN;
        messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
      }
      else
      {
        newCertificateMapperDN = certMapperAttr.activeValue();
        CertificateMapper mapper =
             DirectoryServer.getCertificateMapper(newCertificateMapperDN);
        if (mapper == null)
        {
          if (resultCode == ResultCode.SUCCESS)
          {
            resultCode = ResultCode.OBJECTCLASS_VIOLATION;
          }
          msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
          messages.add(getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(newCertificateMapperDN)));
        }
      }
    }
    catch (Exception e)
    {
      if (resultCode == ResultCode.SUCCESS)
      {
        resultCode = ResultCode.OBJECTCLASS_VIOLATION;
      }
      msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_MAPPER_DN;
      messages.add(getMessage(msgID, String.valueOf(configEntryDN),
                              stackTraceToSingleLineString(e)));
    }
    // If everything has been successful, then apply any changes that were made.
    if (resultCode == ResultCode.SUCCESS)
    {
      if (newValidationPolicy != validationPolicy)
      {
        validationPolicy = newValidationPolicy;
        if (detailedResults)
        {
          msgID = MSGID_SASLEXTERNAL_UPDATED_VALIDATION_POLICY;
          messages.add(getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(validationPolicy)));
        }
      }
      if (! certificateAttributeType.equals(newCertType))
      {
        certificateAttributeType = newCertType;
        if (detailedResults)
        {
          msgID = MSGID_SASLEXTERNAL_UPDATED_CERT_ATTR;
          messages.add(getMessage(msgID, String.valueOf(configEntryDN),
                                  certificateAttributeType.getNameOrOID()));
        }
      }
      if (! newCertificateMapperDN.equals(certificateMapperDN))
      {
        certificateMapperDN = newCertificateMapperDN;
        if (detailedResults)
        {
          msgID = MSGID_SASLEXTERNAL_UPDATED_CERT_MAPPER_DN;
          messages.add(getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(newCertificateMapperDN)));
        }
      }
    }
    // Return the result to the caller.
    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
@@ -941,5 +455,114 @@
    // This may be considered a secure mechanism.
    return true;
  }
  /**
   * {@inheritDoc}
   */
  public boolean isConfigurationChangeAcceptable(
                      ExternalSASLMechanismHandlerCfg configuration,
                      List<String> unacceptableReasons)
  {
    boolean configAcceptable = true;
    // Get the attribute type to use for validating the certificates.  If none
    // is provided, then default to the userCertificate type.
    String attrTypeName = configuration.getCertificateAttribute();
    if (attrTypeName != null)
    {
      attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
    }
    AttributeType newCertificateType =
         DirectoryServer.getAttributeType(toLowerCase(attrTypeName), false);
    if (newCertificateType == null)
    {
      int msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
      unacceptableReasons.add(getMessage(msgID, String.valueOf(attrTypeName),
                                         String.valueOf(configEntryDN)));
      configAcceptable = false;
    }
    // Make sure that the configured certificate mapper is valid.
    CertificateMapper certificateMapper =
         DirectoryServer.getCertificateMapper(
              configuration.getCertificateMapperDN());
    if (certificateMapper == null)
    {
      int msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
      unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
           String.valueOf(configuration.getCertificateMapperDN())));
      configAcceptable = false;
    }
    return configAcceptable;
  }
  /**
   * {@inheritDoc}
   */
  public ConfigChangeResult applyConfigurationChange(
              ExternalSASLMechanismHandlerCfg configuration)
  {
    ResultCode        resultCode          = ResultCode.SUCCESS;
    boolean           adminActionRequired = false;
    ArrayList<String> messages            = new ArrayList<String>();
    // See if we should attempt to validate client certificates against those in
    // the corresponding user's entry.
    CertificateValidationPolicy newValidationPolicy =
         CertificateValidationPolicy.ALWAYS;
    switch (configuration.getCertificateValidationPolicy())
    {
      case NEVER:
        newValidationPolicy = CertificateValidationPolicy.NEVER;
        break;
      case IFPRESENT:
        newValidationPolicy = CertificateValidationPolicy.IFPRESENT;
        break;
      case ALWAYS:
        newValidationPolicy = CertificateValidationPolicy.ALWAYS;
        break;
    }
    // Get the attribute type to use for validating the certificates.  If none
    // is provided, then default to the userCertificate type.
    String attrTypeName = configuration.getCertificateAttribute();
    if (attrTypeName == null)
    {
      attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
    }
    AttributeType newCertificateType =
         DirectoryServer.getAttributeType(toLowerCase(attrTypeName), false);
    if (newCertificateType == null)
    {
      if (resultCode == ResultCode.SUCCESS)
      {
        resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
      }
      int msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
      messages.add(getMessage(msgID, String.valueOf(attrTypeName),
                              String.valueOf(configEntryDN)));
    }
    if (resultCode == ResultCode.SUCCESS)
    {
      validationPolicy         = newValidationPolicy;
      certificateAttributeType = newCertificateType;
      currentConfig            = configuration;
    }
   return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
}