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

coulbeck
05.44.2007 2f9f867e65cb1e6aab842cde5133dfa557654641
Enable replication session authentication.
- Adds a thread to synchronize the server instance certificates from the admin data branch to the local trust store backend.
- Replaces the blind trust managers in the replication session with trust managers that use the local trust store.

Note that replication must be configured using either setup-gui or the dsreplication command.
1 files added
5 files modified
883 ■■■■■ changed files
opendj-sdk/opends/src/messages/messages/backend.properties 17 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/messages/messages/core.properties 8 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/TrustStoreBackend.java 142 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java 3 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/core/TrustStoreSyncThread.java 708 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/replication/protocol/ReplSessionSecurity.java 5 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/messages/messages/backend.properties
@@ -877,9 +877,8 @@
SEVERE_ERR_TRUSTSTORE_DN_DOES_NOT_SPECIFY_CERTIFICATE_302=Unable to process \
 entry %s in the trust store backend because the requested DN is one level \
 below the base DN but does not specify a certificate name
SEVERE_ERR_TRUSTSTORE_INVALID_CERTIFICATE_303=Unable to retrieve entry %s \
 from the trust store backend because the requested certificate is invalid: \
 %s
SEVERE_ERR_TRUSTSTORE_CANNOT_RETRIEVE_CERT_303=Error while trying to retrieve \
 certificate %s from the trust store file %s: %s
SEVERE_ERR_TRUSTSTORE_MODIFY_NOT_SUPPORTED_304=Modify operations are not \
 supported in the trust store backend
SEVERE_ERR_TRUSTSTORE_MODIFY_DN_NOT_SUPPORTED_305=Modify DN operations are not \
@@ -897,10 +896,9 @@
SEVERE_ERR_TRUSTSTORE_INVALID_TYPE_310=The trust store type %s \
 specified in attribute ds-cfg-trust-store-type of configuration entry %s is \
 not valid:  %s
SEVERE_ERR_TRUSTSTORE_PIN_NO_SUCH_FILE_311=File %s specified in \
 attribute ds-cfg-trust-store-pin-file of configuration entry %s should \
 contain the PIN needed to access the trust store, but this file \
 does not exist
SEVERE_ERR_TRUSTSTORE_PIN_FILE_CANNOT_CREATE_311=An error occurred while \
 trying to create the PIN file %s specified in attribute \
 ds-cfg-trust-store-pin-file of configuration entry %s
SEVERE_ERR_TRUSTSTORE_PIN_FILE_CANNOT_READ_312=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
@@ -962,4 +960,7 @@
 replace the value of the ds-task-state attribute with "cancel"
INFO_TASKBE_RUNNING_TASK_CANCELLED_336=Task processing was interrupted by a \
 modify request to cancel the task
SEVERE_ERR_TRUSTSTORE_CANNOT_DELETE_CERT_337=Error while trying to delete \
 certificate %s from the trust store file %s: %s
SEVERE_ERR_TRUSTSTORE_CERTIFICATE_NOT_FOUND_338=Unable to retrieve entry %s \
 from the trust store backend because the certificate %s does not exist
opendj-sdk/opends/src/messages/messages/core.properties
@@ -1655,3 +1655,11 @@
INFO_DSCORE_DESCRIPTION_LASTKNOWNGOODCFG_652=Attempt to start using the \
 configuration that was in place at the last successful startup (if it is \
 available) rather than using the current active configuration
INFO_TRUSTSTORESYNC_ADMIN_SUFFIX_SEARCH_FAILED_653=Error while searching base \
 %s to synchronize the trust store: %s
SEVERE_ERR_TRUSTSTORESYNC_EXCEPTION_654=An error occurred in the trust store \
 synchronization thread: %s
INFO_TRUSTSTORESYNC_ADD_FAILED_655=Error while trying to add entry %s \
 to the trust store: %s
INFO_TRUSTSTORESYNC_DELETE_FAILED_656=Error while trying to delete entry %s \
 from the trust store: %s
opendj-sdk/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
@@ -41,7 +41,6 @@
import java.security.KeyStoreException;
import org.opends.server.api.Backend;
import org.opends.server.api.TrustManagerProvider;
import org.opends.server.config.ConfigException;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
@@ -60,16 +59,18 @@
import static org.opends.server.util.StaticUtils.*;
import org.opends.server.util.Validator;
import org.opends.server.util.CertificateManager;
import org.opends.server.util.ExpirationCheckTrustManager;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.TrustStoreBackendCfg;
import org.opends.server.admin.Configuration;
import org.opends.server.extensions.BlindTrustManagerProvider;
import org.opends.messages.Message;
import static org.opends.messages.BackendMessages.*;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import javax.naming.ldap.Rdn;
import java.security.cert.Certificate;
import java.net.UnknownHostException;
@@ -247,7 +248,7 @@
            }
            catch (Exception e)
            {
              Message message = ERR_TRUSTSTORE_PIN_NO_SUCH_FILE.get(
              Message message = ERR_TRUSTSTORE_PIN_FILE_CANNOT_CREATE.get(
                   String.valueOf(pinFilePath), String.valueOf(configEntryDN));
              throw new InitializationException(message);
            }
@@ -537,11 +538,17 @@
                                   baseDN, null);
    }
    String certAlias = v.getStringValue();
    ByteString certValue;
    try
    {
      Certificate cert = certificateManager.getCertificate(v.getStringValue());
      Certificate cert = certificateManager.getCertificate(certAlias);
      if (cert == null)
      {
        Message message = ERR_TRUSTSTORE_CERTIFICATE_NOT_FOUND.get(
            String.valueOf(entryDN), certAlias);
        throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
      }
      certValue = new ASN1OctetString(cert.getEncoded());
    }
    catch (Exception e)
@@ -551,12 +558,11 @@
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_TRUSTSTORE_INVALID_CERTIFICATE.get(
          String.valueOf(entryDN), e.getMessage());
      Message message = ERR_TRUSTSTORE_CANNOT_RETRIEVE_CERT.get(
          certAlias, trustStoreFile, e.getMessage());
      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
    }
    // Construct the certificate entry to return.
    LinkedHashMap<ObjectClass,String> ocMap =
        new LinkedHashMap<ObjectClass,String>(2);
@@ -642,8 +648,22 @@
  public void deleteEntry(DN entryDN, DeleteOperation deleteOperation)
         throws DirectoryException
  {
    Message message = ERR_TRUSTSTORE_DELETE_NOT_SUPPORTED.get();
    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
    if (entryDN.equals(baseDN))
    {
      Message message = ERR_TRUSTSTORE_INVALID_BASE.get(
           String.valueOf(entryDN));
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
    }
    DN parentDN = entryDN.getParentDNInSuffix();
    if (parentDN == null || !parentDN.equals(baseDN))
    {
      Message message = ERR_TRUSTSTORE_INVALID_BASE.get(
           String.valueOf(entryDN));
      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
    }
    deleteCertificate(entryDN);
  }
@@ -664,7 +684,7 @@
   * {@inheritDoc}
   */
  public void renameEntry(DN currentDN, Entry entry,
                                   ModifyDNOperation modifyDNOperation)
                          ModifyDNOperation modifyDNOperation)
         throws DirectoryException
  {
    Message message = ERR_TRUSTSTORE_MODIFY_DN_NOT_SUPPORTED.get();
@@ -866,7 +886,7 @@
   * {@inheritDoc}
   */
  public void createBackup(BackupConfig backupConfig)
  throws DirectoryException
       throws DirectoryException
  {
    // This backend does not provide a backup/restore mechanism.
    Message message = ERR_TRUSTSTORE_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
@@ -1170,7 +1190,7 @@
            {
              resultCode = DirectoryServer.getServerErrorResultCode();
              messages.add(ERR_TRUSTSTORE_PIN_NO_SUCH_FILE.get(
              messages.add(ERR_TRUSTSTORE_PIN_FILE_CANNOT_CREATE.get(
                      String.valueOf(newPINFile),
                      String.valueOf(configEntryDN)));
            }
@@ -1360,10 +1380,57 @@
  public TrustManager[] getTrustManagers()
         throws DirectoryException
  {
    // TODO Temporary until the trust store is populated with the certificates
    // TODO   of all the servers in the ADS topology.
    TrustManagerProvider trustManagerProvider = new BlindTrustManagerProvider();
    return trustManagerProvider.getTrustManagers();
    KeyStore trustStore;
    try
    {
      trustStore = KeyStore.getInstance(trustStoreType);
      FileInputStream inputStream =
           new FileInputStream(getFileForPath(trustStoreFile));
      trustStore.load(inputStream, trustStorePIN);
      inputStream.close();
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_TRUSTSTORE_CANNOT_LOAD.get(
          trustStoreFile, getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
    try
    {
      String trustManagerAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
      TrustManagerFactory trustManagerFactory =
           TrustManagerFactory.getInstance(trustManagerAlgorithm);
      trustManagerFactory.init(trustStore);
      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)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_TRUSTSTORE_CANNOT_CREATE_FACTORY.get(
          trustStoreFile, getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
  }
@@ -1387,7 +1454,7 @@
    try
    {
      if (certificateManager.aliasInUse(v.getStringValue()))
      if (certificateManager.aliasInUse(certAlias))
      {
        Message message = ERR_TRUSTSTORE_ALIAS_IN_USE.get(
             String.valueOf(entryDN));
@@ -1498,6 +1565,45 @@
  }
  private void deleteCertificate(DN entryDN)
       throws DirectoryException
  {
    // Make sure that the DN specifies a certificate alias.
    AttributeType t =
         DirectoryServer.getAttributeType(ATTR_CERT_ALIAS, true);
    AttributeValue v = entryDN.getRDN().getAttributeValue(t);
    if (v == null)
    {
      Message message = ERR_TRUSTSTORE_DN_DOES_NOT_SPECIFY_CERTIFICATE.get(
           String.valueOf(entryDN));
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message,
                                   baseDN, null);
    }
    String certAlias = v.getStringValue();
    try
    {
      if (!certificateManager.aliasInUse(certAlias))
      {
        Message message = ERR_TRUSTSTORE_INVALID_BASE.get(
             String.valueOf(entryDN));
        throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
                                     message);
      }
      certificateManager.removeCertificate(certAlias);
    }
    catch (Exception e)
    {
      Message message = ERR_TRUSTSTORE_CANNOT_DELETE_CERT.get(
           certAlias, trustStoreFile, getExceptionMessage(e));
      throw new DirectoryException(
           DirectoryServer.getServerErrorResultCode(), message, e);
    }
  }
  /**
   * Returns the validity period to be used to generate the ADS certificate.
   * @return The validity period to be used to generate the ADS certificate.
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -1435,6 +1435,9 @@
      }
      // Start a thread to synchronize the trust store.
      new TrustStoreSyncThread().start();
      // If we should write a copy of the config on successful startup, then do
      // so now.
      if (saveConfigOnSuccessfulStartup)
opendj-sdk/opends/src/server/org/opends/server/core/TrustStoreSyncThread.java
New file
@@ -0,0 +1,708 @@
/*
 * 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.
 */
package org.opends.server.core;
import org.opends.server.api.DirectoryThread;
import org.opends.server.api.Backend;
import org.opends.server.api.BackendInitializationListener;
import org.opends.server.api.ServerShutdownListener;
import org.opends.server.api.ChangeNotificationListener;
import org.opends.server.loggers.debug.DebugTracer;
import static org.opends.server.loggers.debug.DebugLogger.getTracer;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.loggers.ErrorLogger;
import org.opends.server.types.*;
import org.opends.server.types.operation.PostResponseAddOperation;
import org.opends.server.types.operation.PostResponseDeleteOperation;
import org.opends.server.types.operation.PostResponseModifyOperation;
import org.opends.server.types.operation.PostResponseModifyDNOperation;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import static org.opends.server.util.ServerConstants.OC_TOP;
import static org.opends.server.util.ServerConstants.
     OID_ENTRY_CHANGE_NOTIFICATION;
import org.opends.server.config.ConfigConstants;
import static org.opends.server.config.ConfigConstants.OC_INSTANCE_KEY;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.internal.InternalSearchListener;
import org.opends.server.controls.PersistentSearchChangeType;
import org.opends.server.controls.EntryChangeNotificationControl;
import static org.opends.messages.CoreMessages.*;
import org.opends.messages.Message;
import org.opends.admin.ads.ADSContext;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.LinkedHashSet;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.HashMap;
/**
 * This class defines a thread that synchronizes certificates from the admin
 * data branch into the trust store backend.
 */
public class TrustStoreSyncThread extends DirectoryThread
     implements ServerShutdownListener, BackendInitializationListener,
     InternalSearchListener, ChangeNotificationListener
{
  /**
   * The debug log tracer for this object.
   */
  private static final DebugTracer TRACER = getTracer();
  // A lock and condition for notifying this thread.
  private Lock lock;
  private Condition condition;
  // The DN of the administration suffix.
  private DN adminSuffixDN;
  // The DN of the instance keys container within the admin suffix.
  private DN instanceKeysDN;
  // The DN of the trust store root.
  private DN trustStoreRootDN;
  // The attribute type that is used to specify a server instance certificate.
  AttributeType attrCert;
  // The attribute type that holds a server certificate identifier.
  AttributeType attrAlias;
  // The attribute type that holds the time a key was compromised.
  AttributeType attrCompromisedTime;
  // A filter on the instance key object class.
  private SearchFilter instanceKeyFilter;
  // Indicates whether the ADS suffix backend is initialized.
  private boolean adminBackendInitialized;
  // Indicates whether the trust store backend is initialized.
  private boolean trustStoreBackendInitialized;
  // Indicates whether a shutdown request has been received.
  private boolean shutdownRequested;
  // Indicates whether the initial search has been done.
  private boolean searchDone;
  /**
   * Creates a new instance of this trust store synchronization thread.
   */
  public TrustStoreSyncThread()
  {
    super("Trust Store Synchronization Thread");
    setDaemon(true);
    shutdownRequested = false;
    adminBackendInitialized = false;
    trustStoreBackendInitialized = false;
    searchDone = false;
    DirectoryServer.registerShutdownListener(this);
    DirectoryServer.registerBackendInitializationListener(this);
    lock = new ReentrantLock();
    condition = lock.newCondition();
    try
    {
      adminSuffixDN = DN.decode(ADSContext.getAdministrationSuffixDN());
      instanceKeysDN = adminSuffixDN.concat(DN.decode("cn=instance keys"));
      trustStoreRootDN = DN.decode(ConfigConstants.DN_TRUST_STORE_ROOT);
      instanceKeyFilter =
           SearchFilter.createFilterFromString(
                "(objectclass=" + ConfigConstants.OC_INSTANCE_KEY + ")");
    }
    catch (DirectoryException e)
    {
      //
    }
    attrCert = DirectoryServer.getAttributeType(
         ConfigConstants.ATTR_ADS_CERTIFICATE, true);
    attrAlias = DirectoryServer.getAttributeType(
         ConfigConstants.ATTR_CERT_ALIAS, true);
    attrCompromisedTime = DirectoryServer.getAttributeType(
         "ds-cfg-key-compromised-time", true);
    if (DirectoryServer.getBackendWithBaseDN(adminSuffixDN) != null)
    {
      adminBackendInitialized = true;
    }
    if (DirectoryServer.getBackendWithBaseDN(trustStoreRootDN) != null)
    {
      trustStoreBackendInitialized = true;
    }
  }
//  We would need this to detect changes if the admin branch was remote.
//  private SearchOperation runPersistentSearch()
//  {
//    InternalClientConnection conn =
//         InternalClientConnection.getRootConnection();
//    LinkedHashSet<String> attributes = new LinkedHashSet<String>(0);
//
//    // Specify the persistent search control.
//    Set<PersistentSearchChangeType> changeTypes =
//         new HashSet<PersistentSearchChangeType>();
//    changeTypes.add(PersistentSearchChangeType.ADD);
//    changeTypes.add(PersistentSearchChangeType.DELETE);
//    changeTypes.add(PersistentSearchChangeType.MODIFY);
//
//    boolean changesOnly = false;
//    boolean returnECs = true;
//
//    PersistentSearchControl psc =
//         new PersistentSearchControl(changeTypes, changesOnly, returnECs);
//    ArrayList<Control> controls = new ArrayList<Control>(1);
//    controls.add(psc);
//
//    InternalSearchOperation searchOperation =
//         new InternalSearchOperation(
//              conn,
//              InternalClientConnection.nextOperationID(),
//              InternalClientConnection.nextMessageID(),
//              controls,
//              adminSuffixDN, SearchScope.WHOLE_SUBTREE,
//              DereferencePolicy.NEVER_DEREF_ALIASES,
//              0, 0,
//              false, instanceKeyFilter, attributes,
//              this);
//
//    searchOperation.run();
//
//    return searchOperation;
//  }
  private SearchOperation runSearch()
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    LinkedHashSet<String> attributes = new LinkedHashSet<String>(0);
    ArrayList<Control> controls = new ArrayList<Control>(0);
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(conn,
                                     InternalClientConnection.nextOperationID(),
                                     InternalClientConnection.nextMessageID(),
                                     controls,
                                     adminSuffixDN, SearchScope.WHOLE_SUBTREE,
                                     DereferencePolicy.NEVER_DEREF_ALIASES,
                                     0, 0,
                                     false, instanceKeyFilter, attributes,
                                     this);
    searchOperation.run();
    return searchOperation;
  }
  /**
   * Performs an initial search on the ADS branch when enabled, then listens
   * for changes within the branch, writing certificates from instance key
   * entries to the trust store backend.
   */
  public void run()
  {
    while (!shutdownRequested)
    {
      try
      {
        if (!searchDone && adminBackendInitialized &&
             trustStoreBackendInitialized)
        {
          SearchOperation searchOperation = runSearch();
          ResultCode resultCode = searchOperation.getResultCode();
          if (resultCode != ResultCode.SUCCESS)
          {
            Message message =
                 INFO_TRUSTSTORESYNC_ADMIN_SUFFIX_SEARCH_FAILED.get(
                      String.valueOf(adminSuffixDN),
                      searchOperation.getErrorMessage().toString());
            ErrorLogger.logError(message);
          }
          searchDone = true;
          DirectoryServer.registerChangeNotificationListener(this);
        }
        // Wait until a backend changes state or a shutdown is requested.
        awaitCondition();
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_TRUSTSTORESYNC_EXCEPTION.get(
             stackTraceToSingleLineString(e));
        ErrorLogger.logError(message);
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  public String getShutdownListenerName()
  {
    return "Trust Store Synchronization Thread";
  }
  /**
   * {@inheritDoc}
   */
  public void processServerShutdown(Message reason)
  {
    shutdownRequested = true;
    notifyCondition();
  }
  private void notifyCondition()
  {
    lock.lock();
    try
    {
      condition.signalAll();
    }
    finally
    {
      lock.unlock();
    }
  }
  private void awaitCondition()
  {
    lock.lock();
    try
    {
      condition.await();
    }
    catch (InterruptedException e)
    {
      // ignore
    }
    finally
    {
      lock.unlock();
    }
  }
  /**
   * {@inheritDoc}
   */
  public void performBackendInitializationProcessing(Backend backend)
  {
    boolean notify = false;
    DN[] baseDNs = backend.getBaseDNs();
    if (baseDNs != null)
    {
      for (DN baseDN : baseDNs)
      {
        if (baseDN.equals(adminSuffixDN))
        {
          adminBackendInitialized = true;
          notify = true;
        }
        else if (baseDN.equals(trustStoreRootDN))
        {
          trustStoreBackendInitialized = true;
          notify = true;
        }
      }
    }
    if (notify)
    {
      notifyCondition();
    }
  }
  /**
   * {@inheritDoc}
   */
  public void performBackendFinalizationProcessing(Backend backend)
  {
    boolean notify = false;
    DN[] baseDNs = backend.getBaseDNs();
    if (baseDNs != null)
    {
      for (DN baseDN : baseDNs)
      {
        if (baseDN.equals(adminSuffixDN))
        {
          adminBackendInitialized = false;
          notify = true;
        }
        else if (baseDN.equals(trustStoreRootDN))
        {
          adminBackendInitialized = false;
          notify = true;
        }
      }
    }
    if (notify)
    {
      notifyCondition();
    }
  }
  /**
   * {@inheritDoc}
   */
  public void handleInternalSearchEntry(InternalSearchOperation searchOperation,
                                        SearchResultEntry searchEntry)
       throws DirectoryException
  {
    RDN srcRDN = searchEntry.getDN().getRDN();
    // Only process the entry if it has the expected form of RDN.
    if (!srcRDN.isMultiValued() &&
         srcRDN.getAttributeType(0).equals(attrAlias))
    {
      DN dstDN = trustStoreRootDN.concat(srcRDN);
      // Extract any change notification control.
      EntryChangeNotificationControl ecn = null;
      List<Control> controls = searchEntry.getControls();
      try
      {
        for (Control c : controls)
        {
          if (c.getOID().equals(OID_ENTRY_CHANGE_NOTIFICATION))
          {
            ecn = EntryChangeNotificationControl.decodeControl(c);
          }
        }
      }
      catch (LDAPException e)
      {
        // ignore
      }
      // Get any existing local trust store entry.
      Entry dstEntry = DirectoryServer.getEntry(dstDN);
      if (ecn != null &&
           ecn.getChangeType() == PersistentSearchChangeType.DELETE)
      {
        // The entry was deleted so we should remove it from the local trust
        // store.
        if (dstEntry != null)
        {
          deleteEntry(dstDN);
        }
      }
      else if (searchEntry.hasAttribute(attrCompromisedTime))
      {
        // The key was compromised so we should remove it from the local
        // trust store.
        if (dstEntry != null)
        {
          deleteEntry(dstDN);
        }
      }
      else
      {
        // The entry was added or modified.
        if (dstEntry == null)
        {
          addEntry(searchEntry, dstDN);
        }
        else
        {
          modifyEntry(searchEntry, dstEntry);
        }
      }
    }
  }
  /**
   * Modify an entry in the local trust store if it differs from an entry in
   * the ADS branch.
   * @param srcEntry The instance key entry in the ADS branch.
   * @param dstEntry The local trust store entry.
   */
  private void modifyEntry(Entry srcEntry, Entry dstEntry)
  {
    List<Attribute> srcList;
    srcList = srcEntry.getAttribute(attrCert);
    List<Attribute> dstList;
    dstList = dstEntry.getAttribute(attrCert);
    // Check for changes to the certificate value.
    boolean differ = false;
    if (srcList == null)
    {
      if (dstList != null)
      {
        differ = true;
      }
    }
    else if (dstList == null)
    {
      differ = true;
    }
    else if (srcList.size() != dstList.size())
    {
      differ = true;
    }
    else
    {
      if (!srcList.equals(dstList))
      {
        differ = true;
      }
    }
    if (differ)
    {
      // The trust store backend does not implement modify so we need to
      // delete then add.
      DN dstDN = dstEntry.getDN();
      deleteEntry(dstDN);
      addEntry(srcEntry, dstDN);
    }
  }
  /**
   * Delete an entry from the local trust store.
   * @param dstDN The DN of the entry to be deleted in the local trust store.
   */
  private void deleteEntry(DN dstDN)
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    DeleteOperation delOperation = conn.processDelete(dstDN);
    if (delOperation.getResultCode() != ResultCode.SUCCESS)
    {
      Message message = INFO_TRUSTSTORESYNC_DELETE_FAILED.get(
           String.valueOf(dstDN),
           String.valueOf(delOperation.getErrorMessage()));
      ErrorLogger.logError(message);
    }
  }
  /**
   * Add an entry to the local trust store.
   * @param srcEntry The instance key entry in the ADS branch.
   * @param dstDN The DN of the entry to be added in the local trust store.
   */
  private void addEntry(Entry srcEntry, DN dstDN)
  {
    ObjectClass instanceKeyOC =
         DirectoryServer.getObjectClass(OC_INSTANCE_KEY, true);
    LinkedHashMap<ObjectClass,String> ocMap =
         new LinkedHashMap<ObjectClass,String>(2);
    ocMap.put(DirectoryServer.getTopObjectClass(), OC_TOP);
    ocMap.put(instanceKeyOC, OC_INSTANCE_KEY);
    HashMap<AttributeType, List<Attribute>> userAttrs =
         new HashMap<AttributeType, List<Attribute>>();
    List<Attribute> attrList;
    attrList = srcEntry.getAttribute(attrAlias);
    if (attrList != null)
    {
      userAttrs.put(attrAlias, attrList);
    }
    attrList = srcEntry.getAttribute(attrCert);
    if (attrList != null)
    {
      userAttrs.put(attrCert, attrList);
    }
    Entry addEntry = new Entry(dstDN, ocMap, userAttrs, null);
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    AddOperation addOperation = conn.processAdd(addEntry);
    if (addOperation.getResultCode() != ResultCode.SUCCESS)
    {
      Message message = INFO_TRUSTSTORESYNC_ADD_FAILED.get(
           String.valueOf(dstDN),
           String.valueOf(addOperation.getErrorMessage()));
      ErrorLogger.logError(message);
    }
  }
  /**
   * {@inheritDoc}
   */
  public void handleInternalSearchReference(
       InternalSearchOperation searchOperation,
       SearchResultReference searchReference) throws DirectoryException
  {
    // No implementation required.
  }
  /**
   * {@inheritDoc}
   */
  public void handleAddOperation(PostResponseAddOperation addOperation,
                                 Entry entry)
  {
    if (!addOperation.getEntryDN().isDescendantOf(instanceKeysDN))
    {
      return;
    }
    RDN srcRDN = entry.getDN().getRDN();
    // Only process the entry if it has the expected form of RDN.
    if (!srcRDN.isMultiValued() &&
         srcRDN.getAttributeType(0).equals(attrAlias))
    {
      DN dstDN = trustStoreRootDN.concat(srcRDN);
      if (!entry.hasAttribute(attrCompromisedTime))
      {
        addEntry(entry, dstDN);
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  public void handleDeleteOperation(PostResponseDeleteOperation deleteOperation,
                                    Entry entry)
  {
    if (!deleteOperation.getEntryDN().isDescendantOf(instanceKeysDN))
    {
      return;
    }
    RDN srcRDN = entry.getDN().getRDN();
    // Only process the entry if it has the expected form of RDN.
    if (!srcRDN.isMultiValued() &&
         srcRDN.getAttributeType(0).equals(attrAlias))
    {
      DN dstDN = trustStoreRootDN.concat(srcRDN);
      deleteEntry(dstDN);
    }
  }
  /**
   * {@inheritDoc}
   */
  public void handleModifyOperation(PostResponseModifyOperation modifyOperation,
                                    Entry oldEntry, Entry newEntry)
  {
    if (!modifyOperation.getEntryDN().isDescendantOf(instanceKeysDN))
    {
      return;
    }
    RDN srcRDN = newEntry.getDN().getRDN();
    // Only process the entry if it has the expected form of RDN.
    if (!srcRDN.isMultiValued() &&
         srcRDN.getAttributeType(0).equals(attrAlias))
    {
      DN dstDN = trustStoreRootDN.concat(srcRDN);
      // Get any existing local trust store entry.
      Entry dstEntry = null;
      try
      {
        dstEntry = DirectoryServer.getEntry(dstDN);
      }
      catch (DirectoryException e)
      {
        // ignore
      }
      if (newEntry.hasAttribute(attrCompromisedTime))
      {
        // The key was compromised so we should remove it from the local
        // trust store.
        if (dstEntry != null)
        {
          deleteEntry(dstDN);
        }
      }
      else
      {
        if (dstEntry == null)
        {
          addEntry(newEntry, dstDN);
        }
        else
        {
          modifyEntry(newEntry, dstEntry);
        }
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  public void handleModifyDNOperation(
       PostResponseModifyDNOperation modifyDNOperation, Entry oldEntry,
       Entry newEntry)
  {
    // No implementation required.
  }
}
opendj-sdk/opends/src/server/org/opends/server/replication/protocol/ReplSessionSecurity.java
@@ -272,6 +272,11 @@
      // Force TLS negotiation now.
      secureSocket.startHandshake();
//      SSLSession sslSession = secureSocket.getSession();
//      System.out.println("Peer      = " + sslSession.getPeerHost() + ":" +
//           sslSession.getPeerPort());
//      System.out.println("Principal = " + sslSession.getPeerPrincipal());
      return new TLSSocketSession(socket, secureSocket);
    }
    else