From 39e4e3e348b24b6cc637aab9dc171ce17208d3e5 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Thu, 12 Sep 2024 08:19:01 +0000
Subject: [PATCH] [#393] FIX DIT SUP delimiter (#395)

---
 opendj-core/src/main/java/com/forgerock/opendj/util/SubstringReader.java                 |   10 +++++
 opendj-server-legacy/src/test/java/org/opends/server/backends/SchemaBackendTestCase.java |   88 ++++++++++++++++++++++++++++++++++++++++++++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java              |   10 +++-
 3 files changed, 105 insertions(+), 3 deletions(-)

diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/SubstringReader.java b/opendj-core/src/main/java/com/forgerock/opendj/util/SubstringReader.java
index f2abf40..6c8b93d 100644
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/SubstringReader.java
+++ b/opendj-core/src/main/java/com/forgerock/opendj/util/SubstringReader.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2009-2010 Sun Microsystems, Inc.
  * Portions copyright 2012-2015 ForgeRock AS.
+ * Portions Copyright 2024 3A Systems, LLC.
  */
 
 package com.forgerock.opendj.util;
@@ -141,6 +142,15 @@
         return skipped;
     }
 
+    public int skipDelims() {
+        int skipped = 0;
+        while (pos < length && (source.charAt(pos) == ' ' || source.charAt(pos) == '$')) {
+            skipped++;
+            pos++;
+        }
+        return skipped;
+    }
+
     @Override
     public String toString() {
         return getClass().getSimpleName() + "("
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
index 1b8bb4a..5195e65 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2009 Sun Microsystems, Inc.
  * Portions copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2024 3A Systems, LLC.
  */
 package org.forgerock.opendj.ldap.schema;
 
@@ -509,10 +510,13 @@
             if (c == '(') {
                 values = new LinkedHashSet<>();
                 do {
+                    if (!values.isEmpty()) {
+                        reader.reset();
+                    }
                     values.add(readRuleID(reader));
-
-                    // Skip over any trailing spaces
-                    reader.skipWhitespaces();
+                    // Skip over any delims spaces
+                    reader.skipDelims();
+                    reader.mark();
                 } while (reader.read() != ')');
                 values = Collections.unmodifiableSet(values);
             } else {
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/SchemaBackendTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/SchemaBackendTestCase.java
index f5574f9..439bc50 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/SchemaBackendTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/SchemaBackendTestCase.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2010 Sun Microsystems, Inc.
  * Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2024 3A Systems, LLC.
  */
 package org.opends.server.backends;
 
@@ -3430,6 +3431,93 @@
     }
   }
 
+  @Test
+  public void testAddDITStructureRuleSupSuccessful() throws Exception
+  {
+    String ldif = toLdif(
+            "dn: cn=schema",
+            "changetype: modify",
+            "add: nameForms",
+            "nameForms: ( 1.3.6.1.4.1.56521.999.8.1.7 NAME 'commonNameForm' DESC 'Name Form for a commonName orgRole structure' OC organizationalRole MUST cn )",
+            "-",
+            "add: ditStructureRules",
+            "dITStructureRules: ( 150 NAME 'commonNameStructureRule'  FORM commonNameForm )",
+            "dITStructureRules: ( 151 NAME 'commonNameStructureRule2' FORM commonNameForm )",
+            "dITStructureRules: ( 152 NAME 'commonNameStructureRule3' FORM commonNameForm SUP ( 150 $ 151 ) )"
+
+            );
+
+    int ruleID = 152;
+    assertSchemaHasDITStructureRule(ruleID, false);
+
+    try
+    {
+      runModify(argsNotPermissive(), ldif, System.err, SUCCESS);
+      assertSchemaHasDITStructureRule(ruleID, true);
+    }
+    finally
+    {
+      // delete in reverse order
+      String ldif2 = toLdif(
+              "dn: cn=schema",
+              "changetype: modify",
+              "delete: ditStructureRules",
+              "dITStructureRules: ( 152 NAME 'commonNameStructureRule3' FORM commonNameForm SUP ( 150 151 ) )",
+              "dITStructureRules: ( 150 NAME 'commonNameStructureRule'  FORM commonNameForm )",
+              "dITStructureRules: ( 151 NAME 'commonNameStructureRule2' FORM commonNameForm )",
+              "-",
+              "delete: nameForms",
+              "nameForms: ( 1.3.6.1.4.1.56521.999.8.1.7 NAME 'commonNameForm' DESC 'Name Form for a commonName orgRole structure' OC organizationalRole MUST cn )"
+              );
+      runModify(argsNotPermissive(), ldif2, System.err, SUCCESS);
+      assertSchemaHasDITStructureRule(ruleID, false);
+    }
+  }
+
+  @Test
+  public void testAddDITStructureRuleSupSuccessful2() throws Exception
+  {
+    String ldif = toLdif(
+            "dn: cn=schema",
+            "changetype: modify",
+            "add: nameForms",
+            "nameForms: ( 1.3.6.1.4.1.56521.999.8.1.7 NAME 'commonNameForm' DESC 'Name Form for a commonName orgRole structure' OC organizationalRole MUST cn )",
+            "-",
+            "add: ditStructureRules",
+            "dITStructureRules: ( 150 NAME 'commonNameStructureRule'  FORM commonNameForm )",
+            "dITStructureRules: ( 151 NAME 'commonNameStructureRule2' FORM commonNameForm )",
+            "dITStructureRules: ( 152 NAME 'commonNameStructureRule3' FORM commonNameForm )",
+            "dITStructureRules: ( 153 NAME 'commonNameStructureRule4' FORM commonNameForm SUP ( 150 151 152 ) )"
+
+    );
+
+    int ruleID = 153;
+    assertSchemaHasDITStructureRule(ruleID, false);
+
+    try
+    {
+      runModify(argsNotPermissive(), ldif, System.err, SUCCESS);
+      assertSchemaHasDITStructureRule(ruleID, true);
+    }
+    finally
+    {
+      // delete in reverse order
+      String ldif2 = toLdif(
+              "dn: cn=schema",
+              "changetype: modify",
+              "delete: ditStructureRules",
+              "dITStructureRules: ( 153 NAME 'commonNameStructureRule4' FORM commonNameForm SUP ( 150 $ 151 $ 152 ) )",
+              "dITStructureRules: ( 150 NAME 'commonNameStructureRule'  FORM commonNameForm )",
+              "dITStructureRules: ( 151 NAME 'commonNameStructureRule2' FORM commonNameForm )",
+              "dITStructureRules: ( 152 NAME 'commonNameStructureRule3' FORM commonNameForm )",
+              "-",
+              "delete: nameForms",
+              "nameForms: ( 1.3.6.1.4.1.56521.999.8.1.7 NAME 'commonNameForm' DESC 'Name Form for a commonName orgRole structure' OC organizationalRole MUST cn )"
+      );
+      runModify(argsNotPermissive(), ldif2, System.err, SUCCESS);
+      assertSchemaHasDITStructureRule(ruleID, false);
+    }
+  }
   private void assertSchemaHasDITStructureRule(int ruleID, boolean expected)
   {
     boolean hasDITStructureRule = getSchema().hasDITStructureRule(ruleID);

--
Gitblit v1.10.0