From 2f9f867e65cb1e6aab842cde5133dfa557654641 Mon Sep 17 00:00:00 2001
From: coulbeck <coulbeck@localhost>
Date: Wed, 05 Sep 2007 19:44:39 +0000
Subject: [PATCH] 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.
---
opendj-sdk/opends/src/server/org/opends/server/backends/TrustStoreBackend.java | 142 ++++++++-
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java | 3
opendj-sdk/opends/src/messages/messages/backend.properties | 17
opendj-sdk/opends/src/messages/messages/core.properties | 8
opendj-sdk/opends/src/server/org/opends/server/core/TrustStoreSyncThread.java | 708 +++++++++++++++++++++++++++++++++++++++++++++++
opendj-sdk/opends/src/server/org/opends/server/replication/protocol/ReplSessionSecurity.java | 5
6 files changed, 857 insertions(+), 26 deletions(-)
diff --git a/opendj-sdk/opends/src/messages/messages/backend.properties b/opendj-sdk/opends/src/messages/messages/backend.properties
index 00aee65..1073a7a 100644
--- a/opendj-sdk/opends/src/messages/messages/backend.properties
+++ b/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
diff --git a/opendj-sdk/opends/src/messages/messages/core.properties b/opendj-sdk/opends/src/messages/messages/core.properties
index c65a87e..49a1ac4 100644
--- a/opendj-sdk/opends/src/messages/messages/core.properties
+++ b/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
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/TrustStoreBackend.java b/opendj-sdk/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
index 14ec3cb..32ef62d 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
+++ b/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.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index a6528b2..0b93dd2 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/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)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/TrustStoreSyncThread.java b/opendj-sdk/opends/src/server/org/opends/server/core/TrustStoreSyncThread.java
new file mode 100644
index 0000000..2b72403
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/TrustStoreSyncThread.java
@@ -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.
+ }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/ReplSessionSecurity.java b/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/ReplSessionSecurity.java
index f77f3a7..7cf2e29 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/ReplSessionSecurity.java
+++ b/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
--
Gitblit v1.10.0