From fb4283af8d6b52a99199e88b4db0adc84739ae93 Mon Sep 17 00:00:00 2001
From: david_page <david_page@localhost>
Date: Sat, 01 Sep 2007 04:19:31 +0000
Subject: [PATCH] Issue 466 partial.

---
 opends/src/ads/org/opends/admin/ads/ADSContext.java                  |   77 ++++++++++++++++--
 opends/src/ads/org/opends/admin/ads/SuffixDescriptor.java            |    2 
 opends/src/ads/org/opends/admin/ads/ServerDescriptor.java            |  100 ++++++++++++++++++------
 opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java |   26 +++---
 4 files changed, 155 insertions(+), 50 deletions(-)

diff --git a/opends/src/ads/org/opends/admin/ads/ADSContext.java b/opends/src/ads/org/opends/admin/ads/ADSContext.java
index 5b76525..608433e 100644
--- a/opends/src/ads/org/opends/admin/ads/ADSContext.java
+++ b/opends/src/ads/org/opends/admin/ads/ADSContext.java
@@ -173,7 +173,7 @@
      * belongs to an instance key entry, separate from the server entry and
      * named by the ds-cfg-key-id attribute from the server entry.
      */
-    INSTANCE_KEY_CERT("ds-cfg-public-key-certificate"/*;binary*/,
+    INSTANCE_PUBLIC_KEY_CERTIFICATE("ds-cfg-public-key-certificate"/*;binary*/,
             ADSPropertySyntax.CERTIFICATE_BINARY);
 
     private String attrName;
@@ -418,7 +418,8 @@
     try
     {
       dirContext.createSubcontext(dn, attrs).close();
-      if (serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT))
+      if (serverProperties.containsKey(
+                                ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE))
       {
         registerInstanceKeyCertificate(serverProperties, dn);
       }
@@ -462,7 +463,8 @@
       BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties);
       dirContext.modifyAttributes(dn, InitialLdapContext.REPLACE_ATTRIBUTE,
           attrs);
-      if (serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT))
+      if (serverProperties.containsKey(
+                                ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE))
       {
         registerInstanceKeyCertificate(serverProperties, dn);
       }
@@ -481,7 +483,8 @@
 
   /**
    * Method called to unregister a server in the ADS. Note that the server's
-   * instance key-pair public-key certificate entry (created in registerServer)
+   * instance key-pair public-key certificate entry (created in
+   * <tt>registerServer()</tt>)
    * is left untouched.
    * @param serverProperties the properties of the server.
    * @throws ADSContextException if the server could not be unregistered.
@@ -1400,7 +1403,7 @@
 
     switch(property)
     {
-      case INSTANCE_KEY_CERT:
+      case INSTANCE_PUBLIC_KEY_CERTIFICATE:
         result = null;  // used in separate instance key entry
         break;
       case GROUPS:
@@ -2017,8 +2020,8 @@
    */
 
   /**
-   * Returns the parent entry of the server key entries in ADS.
-   * @return the parent entry of the server key entries in ADS.
+   Returns the parent entry of the server key entries in ADS.
+   @return the parent entry of the server key entries in ADS.
    */
   private static String getInstanceKeysContainerDN()
   {
@@ -2041,8 +2044,10 @@
           Map<ServerProperty, Object> serverProperties,
           LdapName serverEntryDn) throws NamingException
   {
-    assert serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT);
-    if (! serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT)) {
+    assert serverProperties.containsKey(
+                                ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE);
+    if (! serverProperties.containsKey(
+                              ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) {
       return;
     }
 
@@ -2061,8 +2066,10 @@
               ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID));
     }
     keyAttrs.put(new BasicAttribute(
-            ServerProperty.INSTANCE_KEY_CERT.getAttributeName() + ";binary",
-            serverProperties.get(ServerProperty.INSTANCE_KEY_CERT)));
+            ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.getAttributeName()
+                    + ";binary",
+            serverProperties.get(
+                    ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)));
 
     /* search for public-key certificate entry in ADS DIT */
     final String attrIDs[] = { "ds-cfg-key-id" };
@@ -2076,6 +2083,12 @@
         keyID = (String)keyIdAttr.get();
       }
     }
+    /* TODO: It is possible (but unexpected) that the caller specifies a
+       ds-cfg-key-id value for which there is a certificate entry in ADS, but
+       the certificate value does not match that supplied by the caller. The
+       above search would not return the entry, but the below attempt to add
+       an new entry with the supplied ds-cfg-key-id will fail (throw a
+       NameAlreadyBoundException) */
     else {
       /* create key ID, if it was not supplied in serverProperties */
       if (null == keyID) {
@@ -2098,4 +2111,46 @@
             (new BasicAttributes(
                    ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID)));
   }
+
+  /**
+   Return the set of valid (i.e., not tagged as compromised) instance key-pair
+   public-key certificate entries in ADS.
+   @return The set of valid (i.e., not tagged as compromised) instance key-pair
+   public-key certificate entries in ADS represented as a Map from ds-cfg-key-id
+   value to ds-cfg-public-key-certificate;binary value Note that the collection
+   might be empty.
+   @throws ADSContextException in case of problems with the entry search.
+   */
+  public Map<String,byte[]> getTrustedCertificates()
+          throws ADSContextException
+  {
+    Map<String, byte[]> keyEntryMap = new HashMap<String, byte[]>();
+    try {
+      final LdapName baseDN = new LdapName(getInstanceKeysContainerDN());
+      final String searchFilter =
+       "(&(objectclass=ds-cfg-instance-key)(!(ds-cfg-key-compromised-time=*)))";
+      final SearchControls searchControls = new SearchControls();
+      searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+      final String attrIDs[]= {
+              ADSContext.ServerProperty.INSTANCE_KEY_ID.getAttributeName(),
+              ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE
+                      .getAttributeName() + ";binary"};
+      searchControls.setReturningAttributes(attrIDs);
+      NamingEnumeration<SearchResult> keyEntries
+              = dirContext.search(baseDN, searchFilter, searchControls);
+      while (keyEntries.hasMore()) {
+        final SearchResult entry = keyEntries.next();
+        final Attributes attrs = entry.getAttributes();
+        final Attribute keyIDAttr = attrs.get(attrIDs[0]);
+        final Attribute keyCertAttr = attrs.get(attrIDs[1]);
+        if (null == keyIDAttr || null == keyCertAttr) continue; // schema viol.
+        keyEntryMap.put((String)keyIDAttr.get(), (byte[])keyCertAttr.get());
+      }
+    }
+    catch (NamingException x) {
+      throw new ADSContextException(
+              ADSContextException.ErrorType.ERROR_UNEXPECTED, x);
+    }
+    return keyEntryMap;
+  }
 }
diff --git a/opends/src/ads/org/opends/admin/ads/ServerDescriptor.java b/opends/src/ads/org/opends/admin/ads/ServerDescriptor.java
index b69f3a3..ca818f4 100644
--- a/opends/src/ads/org/opends/admin/ads/ServerDescriptor.java
+++ b/opends/src/ads/org/opends/admin/ads/ServerDescriptor.java
@@ -37,13 +37,11 @@
 import javax.naming.NameNotFoundException;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.directory.*;
 import javax.naming.ldap.InitialLdapContext;
 import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
 
 import org.opends.admin.ads.util.ConnectionUtils;
 
@@ -338,6 +336,7 @@
       }
       catch (Throwable t)
       {
+        /* ignore */
       }
     }
     return host + ":" + port;
@@ -481,7 +480,7 @@
       }
     }
     adsProperties.put(ADSContext.ServerProperty.ID, getHostPort(true));
-    adsProperties.put(ADSContext.ServerProperty.INSTANCE_KEY_CERT,
+    adsProperties.put(ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE,
                       getInstancePublicKeyCertificate());
   }
 
@@ -717,6 +716,7 @@
     }
     catch (NameNotFoundException nse)
     {
+      /* ignore */
     }
     desc.serverProperties.put(ServerProperty.IS_REPLICATION_ENABLED,
         replicationEnabled ? Boolean.TRUE : Boolean.FALSE);
@@ -769,6 +769,7 @@
     }
     catch (NameNotFoundException nse)
     {
+      /* ignore */
     }
 
     ctls = new SearchControls();
@@ -815,23 +816,22 @@
     }
     catch (NameNotFoundException nse)
     {
+      /* ignore */
     }
   }
 
   /**
-   * Updates the instance key public-key certificate value of this context from
-   * the local truststore of the instance bound by this context. Any current
-   * value of the certificate is overwritten. The intent of this method is to
-   * retrieve the instance-key public-key certificate when this context is bound
-   * to an instance, and cache it for later use in registering the instance into
-   * ADS.
-   *
-   * @param desc The map to update with the instance key-pair public-key
-   * certificate.
-   * @param ctx The bound server instance.
-   *
-   * @throws NamingException if unable to retrieve certificate from bound
-   * instance.
+   Updates the instance key public-key certificate value of this context from
+   the local truststore of the instance bound by this context. Any current
+   value of the certificate is overwritten. The intent of this method is to
+   retrieve the instance-key public-key certificate when this context is bound
+   to an instance, and cache it for later use in registering the instance into
+   ADS.
+   @param desc The map to update with the instance key-pair public-key
+   certificate.
+   @param ctx The bound server instance.
+   @throws NamingException if unable to retrieve certificate from bound
+   instance.
    */
   private static void updatePublicKeyCertificate(ServerDescriptor desc,
       InitialLdapContext ctx) throws NamingException
@@ -845,12 +845,12 @@
          it (which induces the CryptoManager to create the public-key
          certificate attribute), then repeat the search. */
       try {
-        final SearchControls sc = new SearchControls();
-        sc.setSearchScope(SearchControls.OBJECT_SCOPE);
+        final SearchControls searchControls = new SearchControls();
+        searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
         final String attrIDs[] = { "ds-cfg-public-key-certificate;binary" };
-        sc.setReturningAttributes(attrIDs);
-        final SearchResult certEntry
-           = ctx.search(dn, "(objectclass=ds-cfg-instance-key)", sc).next();
+        searchControls.setReturningAttributes(attrIDs);
+        final SearchResult certEntry = ctx.search(dn,
+                   "(objectclass=ds-cfg-instance-key)", searchControls).next();
         final Attribute certAttr = certEntry.getAttributes().get(attrIDs[0]);
         if (null != certAttr) {
           /* attribute ds-cfg-public-key-certificate is a MUST in the schema */
@@ -864,7 +864,7 @@
         if (0 == i) {
           /* Poke CryptoManager to initialize truststore. Note the special
              attribute in the request. */
-          final BasicAttributes attrs = new BasicAttributes();
+          final Attributes attrs = new BasicAttributes();
           final Attribute oc = new BasicAttribute("objectclass");
           oc.add("top");
           oc.add("ds-cfg-self-signed-cert-request");
@@ -878,6 +878,53 @@
     }
   }
 
+  /**
+   Seeds the bound instance's local ads-truststore with a set of instance
+   key-pair public key certificates. The result is the instance will trust any
+   instance posessing the private key corresponding to one of the public-key
+   certificates. This trust is necessary at least to initialize replication,
+   which uses the trusted certificate entries in the ads-truststore for server
+   authentication.
+   @param ctx The bound instance.
+   @param keyEntryMap The set of valid (i.e., not tagged as compromised)
+   instance key-pair public-key certificate entries in ADS represented as a map
+   from keyID to public-key certificate (binary).
+   @throws NamingException in case an error occurs while updating the instance's
+   ads-truststore via LDAP.
+   */
+  public static void seedAdsTrustStore(
+          InitialLdapContext ctx,
+          Map<String, byte[]> keyEntryMap)
+          throws NamingException
+  {
+    /* TODO: this DN is declared in some core constants file. Create a
+       constants file for the installer and import it into the core. */
+    final String truststoreDnStr = "cn=ads-truststore";
+    final Attribute oc = new BasicAttribute("objectclass");
+    oc.add("top");
+    oc.add("ds-cfg-instance-key");
+    for (Map.Entry<String, byte[]> keyEntry : keyEntryMap.entrySet()){
+      final BasicAttributes keyAttrs = new BasicAttributes();
+      keyAttrs.put(oc);
+      final Attribute rdnAttr = new BasicAttribute(
+              ADSContext.ServerProperty.INSTANCE_KEY_ID.getAttributeName(),
+              keyEntry.getKey());
+      keyAttrs.put(rdnAttr);
+      keyAttrs.put(new BasicAttribute(
+              ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.
+                      getAttributeName() + ";binary", keyEntry.getValue()));
+      final LdapName keyDn = new LdapName((new StringBuilder(rdnAttr.getID()))
+              .append("=").append(Rdn.escapeValue(rdnAttr.get())).append(",")
+              .append(truststoreDnStr).toString());
+      try {
+        ctx.createSubcontext(keyDn, keyAttrs).close();
+      }
+      catch(NameAlreadyBoundException x){
+        ctx.destroySubcontext(keyDn);
+        ctx.createSubcontext(keyDn, keyAttrs).close();
+      }
+    }
+  }
 
   /**
    * Returns the number of entries in a given backend using the provided
@@ -915,7 +962,7 @@
     }
     catch (Exception ex)
     {
-
+      /* ignore */
     }
     return nEntries;
 
@@ -972,6 +1019,7 @@
       areDnsEqual = name1.equals(name2);
     } catch (Exception ex)
     {
+      /* ignore */
     }
     return areDnsEqual;
   }
diff --git a/opends/src/ads/org/opends/admin/ads/SuffixDescriptor.java b/opends/src/ads/org/opends/admin/ads/SuffixDescriptor.java
index 8bade66..baaaf92 100644
--- a/opends/src/ads/org/opends/admin/ads/SuffixDescriptor.java
+++ b/opends/src/ads/org/opends/admin/ads/SuffixDescriptor.java
@@ -114,7 +114,7 @@
     buf.append(getDN());
     for (ReplicaDescriptor replica : getReplicas())
     {
-      buf.append("-"+replica.getServer().getId());
+      buf.append("-").append(replica.getServer().getId());
     }
 
     return buf.toString();
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java b/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
index 9995e93..f26e545 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -1867,9 +1867,9 @@
   protected void updateADS() throws ApplicationException
   {
     DataReplicationOptions repl = getUserData().getReplicationOptions();
-    boolean remoteServer =
+    boolean isRemoteServer =
             repl.getType() == DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY;
-    AuthenticationData auth = (remoteServer) ? repl.getAuthenticationData()
+    AuthenticationData auth = (isRemoteServer) ? repl.getAuthenticationData()
                                              : null;
     InitialLdapContext remoteCtx = null; // Bound to remote ADS host (if any).
     InitialLdapContext localCtx = null; // Bound to local server.
@@ -1879,7 +1879,7 @@
        ADSContextException to ApplicationException and clean up JNDI contexts.*/
     try
     {
-      if (remoteServer)
+      if (isRemoteServer)
       {
         /* In case the user specified an existing topology... */
         String ldapUrl = getLdapUrl(auth);
@@ -1921,7 +1921,7 @@
       /* Act on local server depending on if using remote or local ADS */
       notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CREATING_ADS.get()));
       localCtx = createLocalContext();
-      if (remoteServer)
+      if (isRemoteServer)
       {
         /* Create an empty ADS suffix on the local server. */
         ADSContext localAdsContext = new ADSContext(localCtx);
@@ -1938,14 +1938,16 @@
       /* Register new server in ADS. */
       ServerDescriptor server = ServerDescriptor.createStandalone(localCtx);
       server.updateAdsPropertiesWithServerProperties();
-      if (0 != adsContext.registerOrUpdateServer(server.getAdsProperties()))
-      {
+      if (0 == adsContext.registerOrUpdateServer(server.getAdsProperties())) {
+        if (isRemoteServer) registeredNewServerOnRemote = true;
+      } else {
         LOG.log(Level.WARNING, "Server was already registered. Updating " +
                 "server registration.");
       }
-      else if (remoteServer)
+      if (isRemoteServer)
       {
-        registeredNewServerOnRemote = true;
+        ServerDescriptor.seedAdsTrustStore(localCtx,
+                                           adsContext.getTrustedCertificates());
       }
       notifyListeners(getFormattedDone());
       notifyListeners(getLineBreak());
@@ -1960,7 +1962,7 @@
                   INFO_PROGRESS_CREATING_ADMINISTRATOR.get()));
           adsContext.createAdministrator(getAdministratorProperties(
                   getUserData()));
-          if (remoteServer && !createdRemoteAds) createdAdministrator = true;
+          if (isRemoteServer && !createdRemoteAds) createdAdministrator = true;
           notifyListeners(getFormattedDone());
           notifyListeners(getLineBreak());
           checkAbort();
@@ -1982,7 +1984,7 @@
     }
     catch (NoPermissionException ne)
     {
-      if (remoteServer)
+      if (isRemoteServer)
       {
         throw new ApplicationException(
                 ReturnCode.CONFIGURATION_ERROR,
@@ -2001,7 +2003,7 @@
     }
     catch (NamingException ne)
     {
-      if (remoteServer)
+      if (isRemoteServer)
       {
         throw new ApplicationException(
                 ReturnCode.CONFIGURATION_ERROR,
@@ -2019,7 +2021,7 @@
     {
       throw new ApplicationException(
               ReturnCode.CONFIGURATION_ERROR,
-              ((remoteServer)
+              ((isRemoteServer)
                       ? INFO_REMOTE_ADS_EXCEPTION.get(
                       getHostDisplay(auth), ace.getReason())
                       : INFO_ADS_EXCEPTION.get(ace.toString())), ace);

--
Gitblit v1.10.0