From 214f451ba73df3e9233471a0dbe636314f5cb3bb Mon Sep 17 00:00:00 2001
From: Violette Roche-Montane <violette.roche-montane@forgerock.com>
Date: Thu, 23 Jan 2014 10:47:40 +0000
Subject: [PATCH] OPENDJ-1284 CryptoManager error when starting server after an upgrade

---
 opends/src/server/org/opends/server/tools/upgrade/UpgradeTasks.java |   41 ++++----
 opends/src/messages/messages/tools.properties                       |    9 +
 opends/src/server/org/opends/server/tools/upgrade/UpgradeUtils.java |  205 +++++++++++++++++++++++-----------------
 opends/src/server/org/opends/server/tools/upgrade/Upgrade.java      |   23 +++-
 4 files changed, 162 insertions(+), 116 deletions(-)

diff --git a/opends/src/messages/messages/tools.properties b/opends/src/messages/messages/tools.properties
index f6cdcd6..7f2d49d 100644
--- a/opends/src/messages/messages/tools.properties
+++ b/opends/src/messages/messages/tools.properties
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #      Copyright 2006-2010 Sun Microsystems, Inc.
-#      Portions Copyright 2011-2013 ForgeRock AS
+#      Portions Copyright 2011-2014 ForgeRock AS
 
 
 
@@ -2498,8 +2498,8 @@
 INFO_UPGRADE_DISPLAY_CONFIRM_START_1814=The upgrade is ready to proceed. Do you \
 wish to continue?
 INFO_UPGRADE_ABORTED_BY_USER_1815=The upgrade has been canceled
-SEVERE_ERR_UPGRADE_UNKNOWN_OC_ATT_1816=The %s %s doesn't exist \
-in the template configuration (possible typo or template corruption)
+SEVERE_ERR_UPGRADE_UNKNOWN_OC_ATT_1816=No %s with OID %s exists in \
+the schema
 SEVERE_ERR_UPGRADE_CONFIG_ERROR_UPGRADE_FOLDER_1817=An error occurred when \
 trying to upgrade the config/upgrade folder: %s
 INFO_UPGRADE_REQUIREMENTS_1818=Preparing to upgrade
@@ -2580,3 +2580,6 @@
  regression in the ds-sync-hist ordering index. This index has to be rebuilt and this could take a long time \
  to proceed. Do you want to launch this process at automatically at the end of the upgrade?
 SEVERE_ERR_TASK_TOOL_LDAP_ERROR_10020=ERROR:  The server rejected the task for the following reason: %s
+INFO_UPGRADE_TASK_10133_1_SUMMARY_10021=Changing matching rule for 'userCertificate' and \
+ 'caCertificate' to CertificateExactMatch
+INFO_UPGRADE_TASK_10133_2_SUMMARY_10022=Configuring 'CertificateExactMatch' matching rule
diff --git a/opends/src/server/org/opends/server/tools/upgrade/Upgrade.java b/opends/src/server/org/opends/server/tools/upgrade/Upgrade.java
index 215a039..396b02f 100644
--- a/opends/src/server/org/opends/server/tools/upgrade/Upgrade.java
+++ b/opends/src/server/org/opends/server/tools/upgrade/Upgrade.java
@@ -21,7 +21,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2013 ForgeRock AS
+ *      Copyright 2013-2014 ForgeRock AS
  */
 
 package org.opends.server.tools.upgrade;
@@ -134,7 +134,7 @@
 
     register("2.5.0.7748",
         newAttributeTypes(INFO_UPGRADE_TASK_7748_1_SUMMARY.get(),
-        "00-core.ldif", "etag"),
+        "00-core.ldif", "1.3.6.1.4.1.36733.2.1.1.59"), //etag
         addConfigEntry(INFO_UPGRADE_TASK_7748_2_SUMMARY.get(),
         "dn: cn=etag,cn=Virtual Attributes,cn=config",
         "changetype: add",
@@ -279,7 +279,7 @@
 
     register("2.5.0.8985",
         newAttributeTypes(INFO_UPGRADE_TASK_8985_1_SUMMARY.get(),
-        "00-core.ldif", "emailAddress"),
+        "00-core.ldif", "1.2.840.113549.1.9.1"), // emailAddress
         modifyConfigEntry(INFO_UPGRADE_TASK_8985_2_SUMMARY.get(),
         "&(ds-cfg-java-class=org.opends.server.extensions." +
         "SubjectAttributeToUserAttributeCertificateMapper)" +
@@ -290,13 +290,26 @@
         "add:ds-cfg-subject-attribute-mapping",
         "ds-cfg-subject-attribute-mapping: emailAddress:mail"));
 
-    /* See OPENDJ-992 */
+    /** See OPENDJ-992 */
     register("2.5.0.9013",
         regressionInVersion("2.5.0.7640",
             rebuildSingleIndex(INFO_UPGRADE_TASK_9013_DESCRIPTION.get(),
                 "ds-sync-hist")));
 
-
+    /** See OPENDJ-1284*/
+    register("2.7.0.10133", // userCertificate OID / cACertificate OID
+        newAttributeTypes(INFO_UPGRADE_TASK_10133_1_SUMMARY.get(),
+        "00-core.ldif", "2.5.4.36", "2.5.4.37"),
+        addConfigEntry(INFO_UPGRADE_TASK_10133_2_SUMMARY.get(),
+        "dn: cn=Certificate Exact Matching Rule,cn=Matching Rules,cn=config",
+        "changetype: add",
+        "objectClass: top",
+        "objectClass: ds-cfg-matching-rule",
+        "objectClass: ds-cfg-equality-matching-rule",
+        "cn: Certificate Exact Matching Rule",
+        "ds-cfg-java-class: "
+            + "org.opends.server.schema.CertificateExactMatchingRuleFactory",
+        "ds-cfg-enabled: true"));
 
     /*
      * All upgrades will refresh the server configuration schema and generate
diff --git a/opends/src/server/org/opends/server/tools/upgrade/UpgradeTasks.java b/opends/src/server/org/opends/server/tools/upgrade/UpgradeTasks.java
index d668e7b..9b9cef9 100644
--- a/opends/src/server/org/opends/server/tools/upgrade/UpgradeTasks.java
+++ b/opends/src/server/org/opends/server/tools/upgrade/UpgradeTasks.java
@@ -21,7 +21,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2013 ForgeRock AS
+ *      Copyright 2013-2014 ForgeRock AS
  */
 
 package org.opends.server.tools.upgrade;
@@ -47,7 +47,6 @@
 import javax.security.auth.callback.TextOutputCallback;
 
 import org.forgerock.opendj.ldap.Filter;
-import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
 import org.opends.messages.Message;
 import org.opends.server.tools.ClientException;
 import org.opends.server.tools.RebuildIndex;
@@ -257,22 +256,23 @@
    * <pre>
    * register(&quot;2.5.0.7192&quot;,
    *   newAttributeTypes(Message.raw(&quot;New attribute etag&quot;),
-   *   false, &quot;00-core.ldif&quot;, &quot;etag&quot;));
+   *   false, &quot;00-core.ldif&quot;,
+   *   &quot;1.3.6.1.4.1.36733.2.1.1.59&quot;));
    * </pre>
    *
    * @param summary
    *          The summary of the task.
    * @param fileName
    *          The file where to add the new attribute types. This file must be
-   *          contained in the config/schema folder.
-   * @param names
-   *          The names of the new attributes to add to.
+   *          contained in the configuration/schema folder.
+   * @param attributeOids
+   *          The OIDs of the new attributes to add to.
    * @return An upgrade task which adds new attribute types, defined previously
-   *         in the config template files, reads the definition and adds it onto
-   *         the specified file in parameter.
+   *         in the configuration template files, reads the definition
+   *         and adds it onto the specified file in parameter.
    */
   public static UpgradeTask newAttributeTypes(final Message summary,
-      final String fileName, final String... names)
+      final String fileName, final String... attributeOids)
   {
     return new AbstractUpgradeTask()
     {
@@ -293,7 +293,7 @@
         {
           final int changeCount =
               updateSchemaFile(schemaFileTemplate, pathDestination,
-                  names, null);
+                  attributeOids, null);
 
           displayChangeCount(pathDestination.getPath(), changeCount);
 
@@ -304,7 +304,7 @@
           manageTaskException(context, ERR_UPGRADE_ADDATTRIBUTE_FAILS.get(
               schemaFileTemplate.getName(), e.getMessage()), pnc);
         }
-        catch (final UnknownSchemaElementException e)
+        catch (final IllegalStateException e)
         {
           manageTaskException(context, ERR_UPGRADE_ADDATTRIBUTE_FAILS.get(
               schemaFileTemplate.getName(), e.getMessage()), pnc);
@@ -322,15 +322,16 @@
    *          The summary of the task.
    * @param fileName
    *          The file where to add the new object classes. This file must be
-   *          contained in the config/schema folder.
-   * @param names
-   *          The names of the new object classes to add to.
+   *          contained in the configuration/schema folder.
+   * @param objectClassesOids
+   *          The OIDs of the new object classes to add to.
    * @return An upgrade task which adds new object classes, defined previously
-   *         in the config template files, reads the definition and adds it onto
-   *         the specified file in parameter.
+   *         in the configuration template files,
+   *         reads the definition and adds it onto the specified file in
+   *         parameter.
    */
   public static UpgradeTask newObjectClasses(final Message summary,
-      final String fileName, final String... names)
+      final String fileName, final String... objectClassesOids)
   {
     return new AbstractUpgradeTask()
     {
@@ -354,7 +355,7 @@
         {
           final int changeCount =
               updateSchemaFile(schemaFileTemplate, pathDestination,
-                  null, names);
+                  null, objectClassesOids);
 
           displayChangeCount(pathDestination.getPath(), changeCount);
 
@@ -365,9 +366,9 @@
           manageTaskException(context, ERR_UPGRADE_ADDOBJECTCLASS_FAILS.get(
               schemaFileTemplate.getName(), e.getMessage()), pnc);
         }
-        catch (final UnknownSchemaElementException e)
+        catch (final IllegalStateException e)
         {
-          manageTaskException(context, ERR_UPGRADE_ADDOBJECTCLASS_FAILS.get(
+          manageTaskException(context, ERR_UPGRADE_ADDATTRIBUTE_FAILS.get(
               schemaFileTemplate.getName(), e.getMessage()), pnc);
         }
       }
diff --git a/opends/src/server/org/opends/server/tools/upgrade/UpgradeUtils.java b/opends/src/server/org/opends/server/tools/upgrade/UpgradeUtils.java
index a46a23f..e5dd73c 100644
--- a/opends/src/server/org/opends/server/tools/upgrade/UpgradeUtils.java
+++ b/opends/src/server/org/opends/server/tools/upgrade/UpgradeUtils.java
@@ -21,7 +21,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2013 ForgeRock AS
+ *      Copyright 2013-2014 ForgeRock AS
  */
 package org.opends.server.tools.upgrade;
 
@@ -37,9 +37,9 @@
 import org.forgerock.opendj.ldap.requests.Requests;
 import org.forgerock.opendj.ldap.requests.SearchRequest;
 import org.forgerock.opendj.ldap.schema.CoreSchema;
+import org.forgerock.opendj.ldap.schema.MatchingRule;
 import org.forgerock.opendj.ldap.schema.Schema;
 import org.forgerock.opendj.ldap.schema.SchemaBuilder;
-import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
 import org.forgerock.opendj.ldif.EntryReader;
 import org.forgerock.opendj.ldif.LDIF;
 import org.forgerock.opendj.ldif.LDIFEntryReader;
@@ -51,12 +51,11 @@
 import org.opends.server.util.StaticUtils;
 
 import static org.opends.messages.ConfigMessages.INFO_CONFIG_FILE_HEADER;
-import static org.opends.messages.ToolMessages.ERR_UPGRADE_UNKNOWN_OC_ATT;
 import static org.opends.messages.ToolMessages.ERR_UPGRADE_CORRUPTED_TEMPLATE;
+import static org.opends.messages.ToolMessages.ERR_UPGRADE_UNKNOWN_OC_ATT;
 import static org.opends.server.tools.upgrade.FileManager.deleteRecursively;
 import static org.opends.server.tools.upgrade.FileManager.rename;
 import static org.opends.server.tools.upgrade.Installation.*;
-import static org.opends.server.util.ServerConstants.EOL;
 
 /**
  * Common utility methods needed by the upgrade.
@@ -571,54 +570,52 @@
    *         is inserted successfully to the destination file.
    * @throws IOException
    *           If an unexpected IO error occurred while reading the entry.
-   * @throws UnknownSchemaElementException
+   * @throws IllegalStateException
    *           Failure to find an attribute in the template schema indicates
    *           either a programming error (e.g. typo in the attribute name) or
    *           template corruption. Upgrade should stop.
    */
   static int updateSchemaFile(final File templateFile, final File destination,
       final String[] attributes, final String[] objectClasses)
-      throws IOException, UnknownSchemaElementException
+      throws IOException, IllegalStateException
   {
     int changeCount = 0;
-    LDIFEntryReader reader = null;
-    BufferedReader br = null;
-    FileWriter fw = null;
+    LDIFEntryReader templateReader = null;
+    LDIFEntryReader destinationReader = null;
+    LDIFEntryWriter destinationWriter = null;
     File copy = null;
     try
     {
-      reader = new LDIFEntryReader(new FileInputStream(templateFile));
-
-      if (!reader.hasNext())
+      templateReader = new LDIFEntryReader(new FileInputStream(templateFile));
+      if (!templateReader.hasNext())
       {
         // Unless template are corrupted, this should not happen.
         throw new IOException(ERR_UPGRADE_CORRUPTED_TEMPLATE.get(
             templateFile.getPath()).toString());
       }
-      final LinkedList<String> definitionsList = new LinkedList<String>();
+      final Entry templateSchemaEntry = templateReader.readEntry();
 
-      final Entry schemaEntry = reader.readEntry();
+      destinationReader = new LDIFEntryReader(
+          new FileInputStream(destination));
+      if (!destinationReader.hasNext())
+      {
+        // Unless template are corrupted, this should not happen.
+        throw new IOException(ERR_UPGRADE_CORRUPTED_TEMPLATE.get(
+            destination.getPath()).toString());
+      }
+      final Entry destinationSchemaEntry = destinationReader.readEntry();
 
-      Schema schema =
-          new SchemaBuilder(Schema.getCoreSchema())
-              .addSchema(schemaEntry, true).toSchema();
       if (attributes != null)
       {
         for (final String att : attributes)
         {
-          try
-          {
-            final String definition =
-                "attributeTypes: " + schema.getAttributeType(att);
-            definitionsList.add(definition);
-            LOG.log(Level.INFO, String.format("Added %s", definition));
-          }
-          catch (UnknownSchemaElementException e)
-          {
-            LOG.log(Level.SEVERE, ERR_UPGRADE_UNKNOWN_OC_ATT.get("attribute",
-                att).toString());
-            throw e;
-          }
+          final ByteString attributeType =
+              getSchemaElement(templateSchemaEntry, "attributeTypes", att);
+          destinationSchemaEntry.getAttribute("attributeTypes").add(
+              attributeType);
+          changeCount++;
+          LOG.log(Level.INFO, String.format("Added %s", attributeType
+              .toString()));
         }
       }
 
@@ -626,50 +623,35 @@
       {
         for (final String oc : objectClasses)
         {
-          try
-          {
-            final String definition =
-                "objectClasses: " + schema.getObjectClass(oc);
-            definitionsList.add(definition);
-            LOG.log(Level.INFO, String.format("Added %s", definition));
-          }
-          catch (UnknownSchemaElementException e)
-          {
-            LOG.log(Level.SEVERE, ERR_UPGRADE_UNKNOWN_OC_ATT.get(
-                "object class", oc).toString());
-            throw e;
-          }
+          final ByteString objectClass =
+              getSchemaElement(templateSchemaEntry, "objectClasses", oc);
+          destinationSchemaEntry.getAttribute("objectClasses").add(objectClass);
+          changeCount++;
+          LOG.log(Level.INFO,
+              String.format("Added %s", objectClass.toString()));
         }
       }
-      // Then, open the destination file and write the new attribute
-      // or objectClass definitions
+
+      // Then writes the new schema entry.
       copy =
           File.createTempFile("copySchema", ".tmp",
               destination.getParentFile());
-      br = new BufferedReader(new FileReader(destination));
-      fw = new FileWriter(copy);
-      String line = br.readLine();
-      while (line != null && !"".equals(line))
-      {
-        fw.write(line + EOL);
-        line = br.readLine();
-      }
-      for (final String definition : definitionsList)
-      {
-        writeLine(fw, definition, 80);
-        changeCount++;
-      }
-      // Must be ended with a blank line
-      fw.write(EOL);
+      final FileOutputStream fos = new FileOutputStream(copy);
+      destinationWriter = new LDIFEntryWriter(fos);
+      destinationWriter.setWrapColumn(79);
+      // Copy comments to fos (get License and first comments only).
+      writeFileHeaderComments(templateFile, destinationWriter);
+      // Writes the entry after.
+      destinationWriter.writeEntry(destinationSchemaEntry);
     }
     finally
     {
-      // The reader and writer must be close before writing files.
+      // Readers and writer must be close before writing files.
       // This causes exceptions under windows OS.
-      StaticUtils.close(br, fw, reader);
+      StaticUtils.close(templateReader, destinationReader, destinationWriter);
     }
 
-    // Writes the schema file.
+    // Renames the copy to make it the new schema file.
     try
     {
       rename(copy, destination);
@@ -685,6 +667,78 @@
   }
 
   /**
+   * Gets and writes the first comments of a file.
+   *
+   * @param file
+   *          The selected file to get the comments.
+   * @param writer
+   *          The writer which is going to write the comments.
+   * @throws IOException
+   *           If an error occurred with the file.
+   */
+  private static void writeFileHeaderComments(final File file,
+      final LDIFEntryWriter writer) throws IOException
+  {
+    BufferedReader br = null;
+    try
+    {
+      br = new BufferedReader(new FileReader(file));
+      String comment = br.readLine();
+
+      while (comment != null && comment.startsWith("#"))
+      {
+        writer.writeComment(comment.replaceAll("# ", "").replaceAll("#", ""));
+        comment = br.readLine();
+      }
+    }
+    catch (IOException ex)
+    {
+      throw ex;
+    }
+    finally
+    {
+      StaticUtils.close(br);
+    }
+  }
+  /**
+   * Returns the definition of the selected attribute / object class OID.
+   *
+   * @param schemaEntry
+   *          The selected schema entry to search on.
+   * @param type
+   *          The type of the research. ("objectClasses" or "attributeTypes")
+   * @param oid
+   *          The OID of the element to search for.
+   * @return The byte string definition of the element.
+   */
+  private static ByteString getSchemaElement(final Entry schemaEntry,
+      final String type, final String oid)
+  {
+    final Attribute attribute = schemaEntry.getAttribute(type);
+    final MatchingRule mrule =
+        CoreSchema.getObjectIdentifierFirstComponentMatchingRule();
+    Assertion assertion;
+    try
+    {
+      assertion = mrule.getAssertion(ByteString.valueOf(oid));
+      for (final ByteString value : attribute)
+      {
+        final ByteString nvalue = mrule.normalizeAttributeValue(value);
+        if (assertion.matches(nvalue).toBoolean())
+        {
+          return value;
+        }
+      }
+    }
+    catch (DecodeException e)
+    {
+      throw new IllegalStateException(e);
+    }
+    throw new IllegalStateException(ERR_UPGRADE_UNKNOWN_OC_ATT.get(type, oid)
+        .toString());
+  }
+
+  /**
    * Creates a new file in the config/upgrade folder. The new file is a
    * concatenation of entries of all files contained in the config/schema
    * folder.
@@ -833,31 +887,6 @@
     return modifiedLines;
   }
 
-  private static void writeLine(final FileWriter fw, final String line,
-      final int wrapColumn) throws IOException
-  {
-    final int length = line.length();
-    if (length > wrapColumn)
-    {
-      fw.write(line.subSequence(0, wrapColumn).toString());
-      fw.write(EOL);
-      int pos = wrapColumn;
-      while (pos < length)
-      {
-        final int writeLength = Math.min(wrapColumn - 1, length - pos);
-        fw.write(" ");
-        fw.write(line.subSequence(pos, pos + writeLength).toString());
-        fw.write(EOL);
-        pos += wrapColumn - 1;
-      }
-    }
-    else
-    {
-      fw.write(line);
-      fw.write(EOL);
-    }
-  }
-
   // Prevent instantiation.
   private UpgradeUtils()
   {

--
Gitblit v1.10.0