From 3897f253ba3cbcfda615c9233da49def1f71cabd Mon Sep 17 00:00:00 2001
From: david_page <david_page@localhost>
Date: Thu, 30 Aug 2007 03:59:38 +0000
Subject: [PATCH] Issue 466 partial.

---
 opends/src/ads/org/opends/admin/ads/ADSContext.java       |  212 ++++++++++-------------------------
 opends/src/ads/org/opends/admin/ads/ServerDescriptor.java |  101 +++++++++++++++-
 2 files changed, 151 insertions(+), 162 deletions(-)

diff --git a/opends/src/ads/org/opends/admin/ads/ADSContext.java b/opends/src/ads/org/opends/admin/ads/ADSContext.java
index 4f6a8df..74989dc 100644
--- a/opends/src/ads/org/opends/admin/ads/ADSContext.java
+++ b/opends/src/ads/org/opends/admin/ads/ADSContext.java
@@ -80,7 +80,12 @@
     /**
      * Boolean syntax.
      */
-    BOOLEAN
+    BOOLEAN,
+
+    /**
+     * Certificate;binary syntax.
+     */
+    CERTIFICATE_BINARY
   }
 
   /**
@@ -156,7 +161,18 @@
     /**
      * The groups to which this server belongs.
      */
-    GROUPS("memberofgroups",ADSPropertySyntax.STRING);
+    GROUPS("memberofgroups",ADSPropertySyntax.STRING),
+    /**
+     * The unique name of the instance key public-key certificate.
+     */
+    INSTANCE_KEY_ID("ds-cfg-key-id", ADSPropertySyntax.STRING),
+    /**
+     * The instance key-pair public-key certificate. Note: This attribute
+     * 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*/,
+            ADSPropertySyntax.CERTIFICATE_BINARY);
 
     private String attrName;
     private ADSPropertySyntax attSyntax;
@@ -393,10 +409,45 @@
   {
     LdapName dn = makeDNFromServerProperties(serverProperties);
     BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties);
+
+    /* Instance key-pair public-key certificate: generate a key-id attribute
+       for the server entry, then an instance key entry for the key. */
+    LdapName keyDn = null;
+    BasicAttributes keyAttrs = null;
+    if (serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT))
+    {
+      String keyID
+              = (String)serverProperties.get(ServerProperty.INSTANCE_KEY_ID);
+      if (null == keyID)
+      {
+        keyID = java.util.UUID.randomUUID().toString();
+      }
+      attrs.put(new BasicAttribute(
+                       ServerProperty.INSTANCE_KEY_ID.getAttributeName(),
+                       keyID));
+
+      String rdnStr = Rdn.escapeValue(keyID);
+      keyDn = nameFromDN(ServerProperty.INSTANCE_KEY_ID.getAttributeName()
+                          + "=" + rdnStr + "," + getInstanceKeysContainerDN());
+      keyAttrs = new BasicAttributes();
+      Attribute oc = new BasicAttribute("objectclass");
+      oc.add("top");
+      oc.add("ds-cfg-instance-key-OID");
+      keyAttrs.put(oc);
+      keyAttrs.put(new BasicAttribute(
+                          ServerProperty.INSTANCE_KEY_ID.getAttributeName(),
+                          rdnStr));
+      keyAttrs.put(new BasicAttribute(
+              ServerProperty.INSTANCE_KEY_CERT.getAttributeName() + ";binary",
+              serverProperties.get(ServerProperty.INSTANCE_KEY_CERT)));
+    }
+
     try
     {
       DirContext ctx = dirContext.createSubcontext(dn, attrs);
       ctx.close();
+      ctx = dirContext.createSubcontext(keyDn, keyAttrs);
+      ctx.close();
     }
     catch (NameAlreadyBoundException x)
     {
@@ -1303,14 +1354,17 @@
 
     switch(property)
     {
-    case GROUPS:
-      result = new BasicAttribute(ServerProperty.GROUPS.getAttributeName());
+      case INSTANCE_KEY_CERT:
+        result = null;  // used in separate instance key entry
+        break;
+      case GROUPS:
+        result = new BasicAttribute(ServerProperty.GROUPS.getAttributeName());
         for (Object o : ((Set) value)) {
             result.add(o);
         }
         break;
-    default:
-      result = new BasicAttribute(property.getAttributeName(), value);
+      default:
+        result = new BasicAttribute(property.getAttributeName(), value);
     }
     return result;
   }
@@ -1873,8 +1927,6 @@
     }
     helper.createAdministrationSuffix(getDirContext(), ben,
         getDbName(), getImportTemp());
-
-    retrieveLocalInstanceKeyCertificate();
   }
 
   /**
@@ -1909,150 +1961,6 @@
    */
 
   /**
-   * The enumeration consisting of properties of the instance-key public-key
-   * certificate entries in ADS.
-   */
-  public enum InstanceKeyProperty
-  {
-    /**
-     * The unique name of the instance key public-key certificate.
-     */
-    KEY_ID("ds-cfg-key-id",ADSPropertySyntax.STRING),
-
-    /**
-     * The public-key certificate of the instance key.
-     */
-    KEY_CERT("ds-cfg-public-key-certificate;binary",ADSPropertySyntax.STRING);
-
-    private String attrName;
-    private ADSPropertySyntax attrSyntax;
-
-    /**
-     * Private constructor.
-     * @param n the name of the attribute.
-     * @param s the name of the syntax.
-     */
-    private InstanceKeyProperty(String n, ADSPropertySyntax s)
-    {
-      attrName = n;
-      attrSyntax = s ;
-    }
-
-    /**
-     * Returns the attribute name.
-     * @return the attribute name.
-     */
-    public String getAttributeName()
-    {
-      return attrName;
-    }
-
-    /**
-     * Returns the attribute syntax.
-     * @return the attribute syntax.
-     */
-    public ADSPropertySyntax getAttributeSyntax()
-    {
-      return attrSyntax;
-    }
-  }
-
-  /*
-   * The instance-key public-key certificate from the local truststore of the
-   * instance bound by this context.
-   */
-  private byte[] localInstanceKeyCertificate = null;
-
-  /**
-   * 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.
-   *
-   * @throws ADSContextException if unable to retrieve certificate from bound
-   * instance.
-   */
-  private void retrieveLocalInstanceKeyCertificate() throws ADSContextException
-  {
-    if( ! isExistingEntry(nameFromDN("cn=ads-truststore")))
-    {
-      return; /* TODO: Once Andy commits the truststore backend, this case is
-                 an exceptional condition and will be caught below (i.e., remove
-                 this code). */
-    }
-
-    /* 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 dnStr = "ds-cfg-key-id=ads-certificate,cn=ads-truststore";
-    localInstanceKeyCertificate = null;
-    for (int i = 0; null == localInstanceKeyCertificate && i < 2 ; ++i ) {
-      /* If the entry does not exist in the instance's truststore backend, add
-         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 String attrIDs[] = { "ds-cfg-public-key-certificate;binary" };
-        sc.setReturningAttributes(attrIDs);
-        final SearchResult adsCertEntry
-           = dirContext.search(nameFromDN(dnStr), "(objectclass=*)", sc).next();
-        final Attribute certAttr = adsCertEntry.getAttributes().get(
-                                        "ds-cfg-public-key-certificate;binary");
-        if (null != certAttr) {
-          localInstanceKeyCertificate = (byte[])certAttr.get();
-        }
-      }
-      catch (NameNotFoundException x) {
-        if (0 == i) {
-          /* Poke CryptoManager to initialize truststore. Note that createEntry
-             wraps any JNDI exception with an ADSException. */
-          final BasicAttributes attrs = new BasicAttributes();
-          final Attribute oc = new BasicAttribute("objectclass");
-          oc.add("top");
-          oc.add("ds-cfg-self-signed-cert-request");
-          attrs.put(oc);
-          createEntry(dnStr, attrs);
-        }
-        else {
-          throw new ADSContextException(
-                  ADSContextException.ErrorType.ERROR_UNEXPECTED, x);
-        }
-      }
-      catch (NoPermissionException x) {
-        throw new ADSContextException(
-                ADSContextException.ErrorType.ACCESS_PERMISSION, x);
-      }
-      catch (javax.naming.NamingException x) {
-        throw new ADSContextException(
-                ADSContextException.ErrorType.ERROR_UNEXPECTED, x);
-      }
-    }
-
-    if (null == localInstanceKeyCertificate) {
-      throw new ADSContextException(
-              ADSContextException.ErrorType.ERROR_UNEXPECTED);
-    }
-  }
-
-  /**
-   * Returns the instance-key public-key certificate directly from the
-   * truststore backend of the instance referenced through this context.
-   *
-   * @return The public-key certificate of the instance.
-   *
-   * @throws ADSContextException if public-key certificate cannot be retrieved.
-   */
-  public byte[] getLocalInstanceKeyCertificate() throws ADSContextException
-  {
-    if (null == localInstanceKeyCertificate) {
-      retrieveLocalInstanceKeyCertificate();
-    }
-    return localInstanceKeyCertificate;
-  }
-
-  /**
    * Returns the parent entry of the server key entries in ADS.
    * @return the parent entry of the server key entries in ADS.
    */
diff --git a/opends/src/ads/org/opends/admin/ads/ServerDescriptor.java b/opends/src/ads/org/opends/admin/ads/ServerDescriptor.java
index 1e9061d..a955024 100644
--- a/opends/src/ads/org/opends/admin/ads/ServerDescriptor.java
+++ b/opends/src/ads/org/opends/admin/ads/ServerDescriptor.java
@@ -33,11 +33,14 @@
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.logging.Logger;
 
 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.DirContext;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 import javax.naming.ldap.InitialLdapContext;
@@ -119,10 +122,13 @@
     /**
      * The associated value is an Integer.
      */
-    REPLICATION_SERVER_ID
+    REPLICATION_SERVER_ID,
+    /**
+     * The instance key-pair public-key certificate. The associated value is a
+     * byte[] (ds-cfg-public-key-certificate;binary).
+     */
+    INSTANCE_PUBLIC_KEY_CERTIFICATE
   }
-  private static final Logger LOG =
-    Logger.getLogger(ServerDescriptor.class.getName());
 
   private ServerDescriptor()
   {
@@ -353,12 +359,10 @@
           ServerProperty.LDAP_PORT, ServerProperty.LDAPS_PORT,
           ServerProperty.LDAP_ENABLED, ServerProperty.LDAPS_ENABLED
       };
-      for (int i=0; i<props.length; i++)
-      {
-        ArrayList s = (ArrayList)serverProperties.get(props[i]);
-        for (Object o : s)
-        {
-          buf.append(":"+o);
+      for (ServerProperty prop : props) {
+        ArrayList s = (ArrayList) serverProperties.get(prop);
+        for (Object o : s) {
+          buf.append(":").append(o);
         }
       }
     }
@@ -385,6 +389,18 @@
   }
 
   /**
+   * Returns the instance-key public-key certificate retrieved from the
+   * truststore backend of the instance referenced through this descriptor.
+   *
+   * @return The public-key certificate of the instance.
+   */
+  public byte[] getInstancePublicKeyCertificate()
+  {
+    return((byte[])
+          serverProperties.get(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE));
+  }
+
+  /**
    * Returns the last exception that was encountered reading the configuration
    * of the server.  Returns null if there was no problem loading the
    * configuration of the server.
@@ -466,6 +482,8 @@
       }
     }
     adsProperties.put(ADSContext.ServerProperty.ID, getHostPort(true));
+    adsProperties.put(ADSContext.ServerProperty.INSTANCE_KEY_CERT,
+                      getInstancePublicKeyCertificate());
   }
 
   /**
@@ -502,6 +520,7 @@
     updateJmxConfiguration(desc, ctx);
     updateReplicas(desc, ctx);
     updateReplication(desc, ctx);
+    updatePublicKeyCertificate(desc, ctx);
 
     desc.serverProperties.put(ServerProperty.HOST_NAME,
         ConnectionUtils.getHostName(ctx));
@@ -801,6 +820,68 @@
   }
 
   /**
+   * 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
+  {
+    /* 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 dnStr = "ds-cfg-key-id=ads-certificate,cn=ads-truststore";
+    final LdapName dn = new LdapName(dnStr);
+    byte[] localInstanceKeyCertificate = null;
+    for (int i = 0; null == localInstanceKeyCertificate && i < 2 ; ++i ) {
+      /* If the entry does not exist in the instance's truststore backend, add
+         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 String attrIDs[] = { "ds-cfg-public-key-certificate;binary" };
+        sc.setReturningAttributes(attrIDs);
+        final SearchResult certEntry
+           = ctx.search(dn, "(objectclass=*)", sc).next();
+        final Attribute certAttr = certEntry.getAttributes().get(
+                                        "ds-cfg-public-key-certificate;binary");
+        if (null != certAttr) {
+          localInstanceKeyCertificate = (byte[])certAttr.get();
+        }
+      }
+      catch (NameNotFoundException x) {
+        if (0 == i) {
+          /* Poke CryptoManager to initialize truststore. Note the special
+             attribute in the request. */
+          final BasicAttributes attrs = new BasicAttributes();
+          final Attribute oc = new BasicAttribute("objectclass");
+          oc.add("top");
+          oc.add("ds-cfg-self-signed-cert-request");
+          attrs.put(oc);
+          DirContext pokeCtx = ctx.createSubcontext(dn, attrs);
+          pokeCtx.close();
+        }
+        else {
+          throw x;
+        }
+      }
+    }
+    desc.serverProperties.put(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE,
+            localInstanceKeyCertificate);
+  }
+
+
+  /**
    * Returns the number of entries in a given backend using the provided
    * InitialLdapContext.
    * @param ctx the InitialLdapContext to use to update the configuration.

--
Gitblit v1.10.0