From 70d9a179cdd8d975b44e1815c249e20d9f91097f Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Wed, 16 Sep 2026 08:10:15 +0000
Subject: [PATCH] [#912] Provision the ads-truststore from an existing key store at setup time (#984)

---
 opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/Installer.java |   94 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/Installer.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/Installer.java
index 661af28..91a495e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/Installer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/Installer.java
@@ -1214,19 +1214,27 @@
    */
   private void configureServer() throws ApplicationException
   {
-    notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CONFIGURING.get()));
     copyTemplateInstance();
     writeOpenDSJavaHome();
     writeHostName();
     checkAbort();
 
+    final SecurityOptions sec = getUserData().getSecurityOptions();
+    if (sec.getReplicationUsesKeyStore())
+    {
+      // Before the configuration and the certificates are written: the provisioning
+      // refuses key stores and certificate files it cannot use, and a refusal then
+      // leaves the configuration as the template had it.
+      provisionAdsTrustStore(sec);
+    }
+
+    notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CONFIGURING.get()));
     List<String> argList = CollectionUtils.newArrayList(
         "-c", getConfigurationFile(),
         "-h", getUserData().getHostName(),
         "-p", String.valueOf(getUserData().getServerPort()),
         "--adminConnectorPort", String.valueOf(getUserData().getAdminConnectorPort()));
 
-    final SecurityOptions sec = getUserData().getSecurityOptions();
     // TODO: even if the user does not configure SSL maybe we should choose
     // a secure port that is not being used and that we can actually use.
     if (sec.getEnableSSL())
@@ -1241,6 +1249,7 @@
     }
 
     addCertificateArguments(sec, argList);
+    addAdsCertificateArguments(sec, argList);
     // For the moment do not enable JMX
     if (getUserData().getServerJMXPort() > 0)
     {
@@ -1341,6 +1350,47 @@
     configureCertificate(sec);
   }
 
+  /**
+   * Provisions the trust store used for server to server communication from the key store
+   * the server certificate comes from.  Replication reads both the key pair it presents on
+   * its port and the certificates it trusts there from that trust store, and from nowhere
+   * else, so the key pair has to be copied into it while the server is stopped: the
+   * nickname to present is read once, when the crypto manager is created at startup.
+   *
+   * @param sec
+   *          the security options holding the key store to provision the trust store from.
+   * @throws ApplicationException
+   *           if the trust store cannot be provisioned.
+   */
+  private void provisionAdsTrustStore(SecurityOptions sec) throws ApplicationException
+  {
+    notifyListeners(getFormattedWithPoints(INFO_PROGRESS_UPDATING_ADS_TRUSTSTORE.get()));
+    final CertificateManager keyStore = new CertificateManager(
+        sec.getKeystorePath(), keyStoreTypeOf(sec), sec.getKeystorePassword());
+    new AdsTrustStoreProvisioner(getAdsTrustStorePath(), getAdsTrustStorePinPath())
+        .provision(keyStore, sec.getAliasesToUse(), sec.getReplicationCaCertFiles());
+    notifyListeners(getFormattedDoneWithLineBreak());
+  }
+
+  /** Returns the key store type of the provided security options, as CertificateManager names it. */
+  private static String keyStoreTypeOf(SecurityOptions sec)
+  {
+    switch (sec.getCertificateType())
+    {
+    case JKS:
+      return CertificateManager.KEY_STORE_TYPE_JKS;
+    case JCEKS:
+      return CertificateManager.KEY_STORE_TYPE_JCEKS;
+    case PKCS12:
+      return CertificateManager.KEY_STORE_TYPE_PKCS12;
+    case BCFKS:
+      return CertificateManager.KEY_STORE_TYPE_BCFKS;
+    default:
+      throw new IllegalStateException(
+          "No key store to read a key pair from: " + sec.getCertificateType());
+    }
+  }
+
   private void configureCertificate(SecurityOptions sec) throws ApplicationException
   {
     try
@@ -1545,6 +1595,24 @@
     }
   }
 
+  /**
+   * Adds the certificate nicknames the crypto manager is to present on the replication
+   * port.  The property is read once, when the crypto manager is created, so it is written
+   * to the configuration before the server is started for the first time rather than set
+   * with dsconfig afterwards.
+   */
+  private static void addAdsCertificateArguments(SecurityOptions sec, List<String> argList)
+  {
+    if (sec.getReplicationUsesKeyStore())
+    {
+      for (String alias : sec.getAliasesToUse())
+      {
+        argList.add("--adsCertNickName");
+        argList.add(alias);
+      }
+    }
+  }
+
   private static void addCertificateArguments(List<String> argList, SecurityOptions sec,
       Collection<String> aliasesInKeyStore, String keyStoreDN, String trustStoreDN)
   {
@@ -4122,6 +4190,28 @@
     return getPath2("keystore.pin");
   }
 
+  /**
+   * Returns the path of the trust store used for server to server communication, the one
+   * the replication port reads its key pair and its trusted certificates from.
+   *
+   * @return the path of the ads-truststore.
+   */
+  private String getAdsTrustStorePath()
+  {
+    return getPath2("ads-truststore");
+  }
+
+  /**
+   * Returns the path of the file holding the PIN of the trust store used for server to
+   * server communication.
+   *
+   * @return the path of the ads-truststore PIN file.
+   */
+  private String getAdsTrustStorePinPath()
+  {
+    return getPath2("ads-truststore.pin");
+  }
+
   private String getPath2(String relativePath)
   {
     String parentFile = getPath(getInstancePath(), Installation.CONFIG_PATH_RELATIVE);

--
Gitblit v1.10.0