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

Matthew Swift
09.20.2016 a6cb29f7519b50d945e398bbc44cc6095a50a285
OPENDJ-2877: implement server LDAP key/trust manager providers

Implemented LDAP based key and trust manager providers which
use an internal connection to a local backend as their LDAP key
store.

Both providers accept a global key store password, but do not
re-use the password for individually encrypting secrets since
this will simply result in double encryption using the same
password.
4 files added
2 files modified
547 ■■■■■ changed files
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/LDAPKeyManagerProviderConfiguration.xml 58 ●●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/LDAPTrustManagerProviderConfiguration.xml 59 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/schema/02-config.ldif 20 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/LDAPKeyManagerProvider.java 196 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/LDAPTrustManagerProvider.java 170 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/messages/org/opends/messages/extension.properties 44 ●●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/LDAPKeyManagerProviderConfiguration.xml
New file
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
  The contents of this file are subject to the terms of the Common Development and
  Distribution License (the License). You may not use this file except in compliance with the
  License.
  You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
  specific language governing permission and limitations under the License.
  When distributing Covered Software, include this CDDL Header Notice in each file and include
  the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
  Header, with the fields enclosed by brackets [] replaced by your own identifying
  information: "Portions copyright [year] [name of copyright owner]".
  Copyright 2016 ForgeRock AS.
  -->
<adm:managed-object name="ldap-key-manager-provider"
                    plural-name="ldap-key-manager-providers"
                    package="org.forgerock.opendj.server.config" extends="key-manager-provider"
                    xmlns:adm="http://opendj.forgerock.org/admin"
                    xmlns:ldap="http://opendj.forgerock.org/admin-ldap"
                    advanced="true">
  <adm:synopsis>
    The LDAP key manager provider uses an LDAP key store managed by the server to obtain server certificates.
  </adm:synopsis>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:name>ds-cfg-ldap-key-manager-provider</ldap:name>
      <ldap:superior>ds-cfg-key-manager-provider</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="java-class" advanced="true">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.extensions.LDAPKeyManagerProvider
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property name="base-dn" mandatory="true">
    <adm:synopsis>
      The base DN beneath which LDAP key store entries are located.
    </adm:synopsis>
    <adm:syntax>
      <adm:dn />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:name>ds-cfg-base-dn</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property-reference name="key-store-pin" />
  <adm:property-reference name="key-store-pin-property" />
  <adm:property-reference name="key-store-pin-environment-variable" />
  <adm:property-reference name="key-store-pin-file" />
</adm:managed-object>
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/LDAPTrustManagerProviderConfiguration.xml
New file
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
  The contents of this file are subject to the terms of the Common Development and
  Distribution License (the License). You may not use this file except in compliance with the
  License.
  You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
  specific language governing permission and limitations under the License.
  When distributing Covered Software, include this CDDL Header Notice in each file and include
  the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
  Header, with the fields enclosed by brackets [] replaced by your own identifying
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2016 ForgeRock AS.
  ! -->
<adm:managed-object name="ldap-trust-manager-provider"
                    plural-name="ldap-trust-manager-providers"
                    package="org.forgerock.opendj.server.config" extends="trust-manager-provider"
                    xmlns:adm="http://opendj.forgerock.org/admin"
                    xmlns:ldap="http://opendj.forgerock.org/admin-ldap"
                    advanced="true">
  <adm:synopsis>
    The LDAP trust manager provider determines whether to trust a presented certificate based on whether that
    certificate exists in an LDAP key store managed by the server.
  </adm:synopsis>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:name>ds-cfg-ldap-trust-manager-provider</ldap:name>
      <ldap:superior>ds-cfg-trust-manager-provider</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="java-class" advanced="true">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.extensions.LDAPTrustManagerProvider
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property name="base-dn" mandatory="true">
    <adm:synopsis>
      The base DN beneath which LDAP key store entries are located.
    </adm:synopsis>
    <adm:syntax>
      <adm:dn />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:name>ds-cfg-base-dn</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property-reference name="trust-store-pin" />
  <adm:property-reference name="trust-store-pin-property" />
  <adm:property-reference name="trust-store-pin-environment-variable" />
  <adm:property-reference name="trust-store-pin-file" />
</adm:managed-object>
opendj-server-legacy/resource/schema/02-config.ldif
@@ -6073,6 +6073,26 @@
  MAY ( ds-cfg-rotation-policy $
        ds-cfg-retention-policy )
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.51
  NAME 'ds-cfg-ldap-key-manager-provider'
  SUP ds-cfg-key-manager-provider
  STRUCTURAL
  MUST ds-cfg-base-dn
  MAY ( ds-cfg-key-store-pin $
        ds-cfg-key-store-pin-property $
        ds-cfg-key-store-pin-environment-variable $
        ds-cfg-key-store-pin-file )
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.52
  NAME 'ds-cfg-ldap-trust-manager-provider'
  SUP ds-cfg-trust-manager-provider
  STRUCTURAL
  MUST ds-cfg-base-dn
  MAY ( ds-cfg-trust-store-pin $
        ds-cfg-trust-store-pin-property $
        ds-cfg-trust-store-pin-environment-variable $
        ds-cfg-trust-store-pin-file )
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.53
  NAME 'ds-cfg-json-schema'
  SUP ds-cfg-schema-provider
opendj-server-legacy/src/main/java/org/opends/server/extensions/LDAPKeyManagerProvider.java
New file
@@ -0,0 +1,196 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.opends.server.extensions;
import static org.forgerock.opendj.adapter.server3x.Adapters.newRootConnectionFactory;
import static org.forgerock.opendj.security.KeyStoreParameters.GLOBAL_PASSWORD;
import static org.forgerock.opendj.security.OpenDJProvider.newLDAPKeyStore;
import static org.forgerock.opendj.security.OpenDJProvider.newClearTextPasswordFactory;
import static org.forgerock.util.Options.defaultOptions;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.util.StaticUtils.getExceptionMessage;
import java.security.KeyStore;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStoreException;
import java.util.List;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigChangeResult;
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.server.config.server.LDAPKeyManagerProviderCfg;
import org.forgerock.util.Factory;
import org.forgerock.util.Options;
import org.opends.server.api.KeyManagerProvider;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
/** This class defines a key manager provider that will access keys stored in an LDAP backend. */
public class LDAPKeyManagerProvider extends KeyManagerProvider<LDAPKeyManagerProviderCfg>
        implements ConfigurationChangeListener<LDAPKeyManagerProviderCfg>
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The configuration for this key manager provider. */
  private LDAPKeyManagerProviderCfg currentConfig;
  private Factory<char[]> passwordFactory;
  /** Lazily initialized key store (some services are unavailable at server startup). */
  private KeyStore keyStore;
  /** Creates a new LDAP key manager provider. */
  public LDAPKeyManagerProvider()
  {
    // No implementation is required.
  }
  @Override
  public void initializeKeyManagerProvider(LDAPKeyManagerProviderCfg cfg) throws InitializationException
  {
    configure(cfg);
    cfg.addLDAPChangeListener(this);
  }
  private synchronized void configure(final LDAPKeyManagerProviderCfg cfg) throws InitializationException
  {
    keyStore = null;
    passwordFactory = newClearTextPasswordFactory(getKeyStorePIN(cfg));
    currentConfig = cfg;
  }
  private synchronized KeyStore getKeyStore()
  {
    if (keyStore == null)
    {
      final Options options = defaultOptions().set(GLOBAL_PASSWORD, passwordFactory);
      keyStore = newLDAPKeyStore(newRootConnectionFactory(), currentConfig.getBaseDN(), options);
    }
    return keyStore;
  }
  @Override
  public synchronized void finalizeKeyManagerProvider()
  {
    keyStore = null;
    currentConfig.removeLDAPChangeListener(this);
  }
  @Override
  public boolean containsKeyWithAlias(String alias)
  {
    try
    {
      return getKeyStore().entryInstanceOf(alias, PrivateKeyEntry.class);
    }
    catch (KeyStoreException e)
    {
      // Ignore.
      logger.traceException(e);
    }
    return false;
  }
  @Override
  public KeyManager[] getKeyManagers() throws DirectoryException
  {
    try
    {
      String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
      KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManagerAlgorithm);
      keyManagerFactory.init(getKeyStore(), passwordFactory.newInstance());
      return keyManagerFactory.getKeyManagers();
    }
    catch (Exception e)
    {
      LocalizableMessage message = ERR_LDAP_KEYMANAGER_CANNOT_CREATE_FACTORY.get(currentConfig.getBaseDN(),
                                                                                 getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, e);
    }
  }
  @Override
  public boolean containsAtLeastOneKey()
  {
    try
    {
      // Not strictly correct since this test includes trusted certs and secret keys, but it should be sufficient.
      // A more accurate approach is to query each alias, but this could be expensive when the key store is large.
      return getKeyStore().size() > 0;
    }
    catch (Exception e)
    {
      logger.traceException(e);
    }
    return false;
  }
  @Override
  public boolean isConfigurationAcceptable(LDAPKeyManagerProviderCfg cfg, List<LocalizableMessage> unacceptableReasons)
  {
    return isConfigurationChangeAcceptable(cfg, unacceptableReasons);
  }
  @Override
  public boolean isConfigurationChangeAcceptable(LDAPKeyManagerProviderCfg cfg,
                                                 List<LocalizableMessage> unacceptableReasons)
  {
    try
    {
      getKeyStorePIN(cfg);
      return true;
    }
    catch (InitializationException e)
    {
      unacceptableReasons.add(e.getMessageObject());
      return false;
    }
  }
  @Override
  public ConfigChangeResult applyConfigurationChange(LDAPKeyManagerProviderCfg cfg)
  {
    final ConfigChangeResult ccr = new ConfigChangeResult();
    try
    {
      configure(cfg);
    }
    catch (InitializationException e)
    {
      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
      ccr.addMessage(e.getMessageObject());
    }
    return ccr;
  }
  private static char[] getKeyStorePIN(LDAPKeyManagerProviderCfg cfg) throws InitializationException
  {
    return FileBasedKeyManagerProvider.getKeyStorePIN(cfg.getKeyStorePinProperty(),
                                                      cfg.getKeyStorePinEnvironmentVariable(),
                                                      cfg.getKeyStorePinFile(),
                                                      cfg.getKeyStorePin(),
                                                      cfg.dn(),
                                                      ERR_LDAP_KEYMANAGER_PIN_PROPERTY_NOT_SET,
                                                      ERR_LDAP_KEYMANAGER_PIN_ENVAR_NOT_SET,
                                                      ERR_LDAP_KEYMANAGER_PIN_NO_SUCH_FILE,
                                                      ERR_LDAP_KEYMANAGER_PIN_FILE_CANNOT_READ,
                                                      ERR_LDAP_KEYMANAGER_PIN_FILE_EMPTY);
  }
}
opendj-server-legacy/src/main/java/org/opends/server/extensions/LDAPTrustManagerProvider.java
New file
@@ -0,0 +1,170 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.opends.server.extensions;
import static org.forgerock.opendj.adapter.server3x.Adapters.newRootConnectionFactory;
import static org.forgerock.opendj.security.KeyStoreParameters.GLOBAL_PASSWORD;
import static org.forgerock.opendj.security.OpenDJProvider.newLDAPKeyStore;
import static org.forgerock.opendj.security.OpenDJProvider.newClearTextPasswordFactory;
import static org.forgerock.util.Options.defaultOptions;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.extensions.FileBasedKeyManagerProvider.getKeyStorePIN;
import static org.opends.server.util.StaticUtils.getExceptionMessage;
import java.security.KeyStore;
import java.util.List;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.config.server.ConfigChangeResult;
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.server.config.server.LDAPTrustManagerProviderCfg;
import org.forgerock.opendj.server.config.server.TrustManagerProviderCfg;
import org.forgerock.util.Factory;
import org.forgerock.util.Options;
import org.opends.server.api.TrustManagerProvider;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
import org.opends.server.util.ExpirationCheckTrustManager;
/** This class defines a trust manager provider that will reference certificates stored in an LDAP backend. */
public class LDAPTrustManagerProvider extends TrustManagerProvider<LDAPTrustManagerProviderCfg>
        implements ConfigurationChangeListener<LDAPTrustManagerProviderCfg>
{
  /** The handle to the configuration for this trust manager. */
  private LDAPTrustManagerProviderCfg currentConfig;
  private Factory<char[]> passwordFactory;
  /** Lazily initialized key store (some services are unavailable at server startup). */
  private KeyStore keyStore;
  /** Creates a new LDAP trust manager provider. */
  public LDAPTrustManagerProvider()
  {
    // No implementation is required.
  }
  @Override
  public void initializeTrustManagerProvider(LDAPTrustManagerProviderCfg cfg) throws InitializationException
  {
    configure(cfg);
    cfg.addLDAPChangeListener(this);
  }
  private synchronized void configure(final LDAPTrustManagerProviderCfg cfg) throws InitializationException
  {
    keyStore = null;
    passwordFactory = newClearTextPasswordFactory(getTrustStorePIN(cfg));
    currentConfig = cfg;
  }
  private synchronized KeyStore getKeyStore()
  {
    if (keyStore == null)
    {
      final Options options = defaultOptions().set(GLOBAL_PASSWORD, passwordFactory);
      keyStore = newLDAPKeyStore(newRootConnectionFactory(), currentConfig.getBaseDN(), options);
    }
    return keyStore;
  }
  @Override
  public synchronized void finalizeTrustManagerProvider()
  {
    keyStore = null;
    currentConfig.removeLDAPChangeListener(this);
  }
  @Override
  public TrustManager[] getTrustManagers() throws DirectoryException
  {
    try
    {
      String trustManagerAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
      TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(trustManagerAlgorithm);
      trustManagerFactory.init(getKeyStore());
      TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
      TrustManager[] newTrustManagers = new TrustManager[trustManagers.length];
      for (int i=0; i < trustManagers.length; i++)
      {
        newTrustManagers[i] = new ExpirationCheckTrustManager((X509TrustManager) trustManagers[i]);
      }
      return newTrustManagers;
    }
    catch (Exception e)
    {
      LocalizableMessage message = ERR_LDAP_TRUSTMANAGER_CANNOT_CREATE_FACTORY.get(currentConfig.getBaseDN(),
                                                                                   getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, e);
    }
  }
  @Override
  public boolean isConfigurationAcceptable(TrustManagerProviderCfg cfg, List<LocalizableMessage> unacceptableReasons)
  {
    return isConfigurationChangeAcceptable((LDAPTrustManagerProviderCfg) cfg, unacceptableReasons);
  }
  @Override
  public boolean isConfigurationChangeAcceptable(LDAPTrustManagerProviderCfg cfg,
                                                 List<LocalizableMessage> unacceptableReasons)
  {
    try
    {
      getTrustStorePIN(cfg);
      return true;
    }
    catch (InitializationException e)
    {
      unacceptableReasons.add(e.getMessageObject());
      return false;
    }
  }
  @Override
  public ConfigChangeResult applyConfigurationChange(LDAPTrustManagerProviderCfg cfg)
  {
    final ConfigChangeResult ccr = new ConfigChangeResult();
    try
    {
      configure(cfg);
    }
    catch (InitializationException e)
    {
      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
      ccr.addMessage(e.getMessageObject());
    }
    return ccr;
  }
  private static char[] getTrustStorePIN(LDAPTrustManagerProviderCfg cfg) throws InitializationException
  {
    return getKeyStorePIN(cfg.getTrustStorePinProperty(),
                          cfg.getTrustStorePinEnvironmentVariable(),
                          cfg.getTrustStorePinFile(),
                          cfg.getTrustStorePin(),
                          cfg.dn(),
                          ERR_LDAP_TRUSTMANAGER_PIN_PROPERTY_NOT_SET,
                          ERR_LDAP_TRUSTMANAGER_PIN_ENVAR_NOT_SET,
                          ERR_LDAP_TRUSTMANAGER_PIN_NO_SUCH_FILE,
                          ERR_LDAP_TRUSTMANAGER_PIN_FILE_CANNOT_READ,
                          ERR_LDAP_TRUSTMANAGER_PIN_FILE_EMPTY);
  }
}
opendj-server-legacy/src/messages/org/opends/messages/extension.properties
@@ -953,8 +953,50 @@
 definition '%s' is invalid because the range '%s' is too short
ERR_NO_KEY_ENTRY_IN_KEYSTORE_636=There is no private key entry in keystore %s
INFO_MISSING_KEY_TYPE_IN_ALIASES_637=Handshake for '%s': cipher requires \
 the aliase(s) '%s' \ to contain key(s) of type(s) '%s'.
 the alias(es) '%s' to contain key(s) of type(s) '%s'.
ERR_PWSCHEME_INVALID_STORED_PASSWORD_638=An error occurred while attempting \
 to match a bcrypt hashed password value:  %s
ERR_LDAP_PTA_INVALID_FILTER_TEMPLATE_639=The mapped search filter template "%s" \
 could not be parsed as a valid LDAP filter
ERR_LDAP_KEYMANAGER_CANNOT_CREATE_FACTORY_640=An error occurred while \
 trying to create a key manager factory to access the contents of LDAP keystore \
 with base DN '%s': %s
ERR_LDAP_TRUSTMANAGER_CANNOT_CREATE_FACTORY_641=An error occurred while \
 trying to create a trust manager factory to access the contents of LDAP keystore \
 with base DN '%s': %s
ERR_LDAP_KEYMANAGER_PIN_PROPERTY_NOT_SET_642=Java property %s which is \
 specified in attribute ds-cfg-key-store-pin-property of configuration entry \
 %s should contain the PIN needed to access the LDAP key manager, but \
 this property is not set
ERR_LDAP_KEYMANAGER_PIN_ENVAR_NOT_SET_643=Environment variable %s which \
 is specified in attribute ds-cfg-key-store-pin-environment-variable of \
 configuration entry %s should contain the PIN needed to access the LDAP \
 key manager, but this property is not set
ERR_LDAP_KEYMANAGER_PIN_NO_SUCH_FILE_644=File %s specified in attribute \
 ds-cfg-key-store-pin-file of configuration entry %s should contain the PIN \
 needed to access the LDAP key manager, but this file does not exist
ERR_LDAP_KEYMANAGER_PIN_FILE_CANNOT_READ_645=An error occurred while \
 trying to read the keystore PIN from file %s specified in configuration \
 attribute ds-cfg-key-store-pin-file of configuration entry %s: %s
ERR_LDAP_KEYMANAGER_PIN_FILE_EMPTY_646=File %s specified in attribute \
 ds-cfg-key-store-pin-file of configuration entry %s should contain the PIN \
 needed to access the LDAP key manager, but this file is empty
ERR_LDAP_TRUSTMANAGER_PIN_PROPERTY_NOT_SET_647=Java property %s which \
 is specified in attribute ds-cfg-trust-store-pin-property of configuration \
 entry %s should contain the PIN needed to access the LDAP trust \
 manager, but this property is not set
ERR_LDAP_TRUSTMANAGER_PIN_ENVAR_NOT_SET_648=Environment variable %s \
 which is specified in attribute ds-cfg-trust-store-pin-environment-variable \
 of configuration entry %s should contain the PIN needed to access the \
 LDAP trust manager, but this property is not set
ERR_LDAP_TRUSTMANAGER_PIN_NO_SUCH_FILE_649=File %s specified in \
 attribute ds-cfg-trust-store-pin-file of configuration entry %s should \
 contain the PIN needed to access the LDAP trust manager, but this file \
 does not exist
ERR_LDAP_TRUSTMANAGER_PIN_FILE_CANNOT_READ_650=An error occurred while \
 trying to read the trust store PIN from file %s specified in configuration \
 attribute ds-cfg-trust-store-pin-file of configuration entry %s: %s
ERR_LDAP_TRUSTMANAGER_PIN_FILE_EMPTY_651=File %s specified in \
 attribute ds-cfg-trust-store-pin-file of configuration entry %s should \
 contain the PIN needed to access the LDAP trust manager, but this file \
 is empty