From 3f4deb91789189521d577457bd6da27de8fd75b1 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Wed, 07 Oct 2026 08:31:10 +0000
Subject: [PATCH] [#1153] Parse the whole DN string, and build or split DN strings through DN instead of string operations (#1171)

---
 opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java |   38 ++++++++++++++++++++++++++++++++------
 1 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java
index d93fea0..5275c41 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java
@@ -13,9 +13,11 @@
  *
  * Copyright 2008 Sun Microsystems, Inc.
  * Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.authorization.dseecompat;
 
+import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_DN_TRAILING_ESCAPE;
 import static org.opends.messages.AccessControlMessages.*;
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.util.CollectionUtils.*;
@@ -973,7 +975,13 @@
     // Look at the first character.  If it is an octothorpe (#), then
     // that means that the value should be a hex string.
     char c = dnString.charAt(pos++);
-    if (c == '#')
+    if (c == ',' || c == ';' || c == '+')
+    {
+      // The value is empty and followed by the next RDN or AVA, as DN.valueOf() reads it.
+      attributeValues.add(ByteString.empty());
+      return pos - 1;
+    }
+    else if (c == '#')
     {
       // The first two characters must be hex characters.
       StringBuilder hexString = new StringBuilder();
@@ -999,7 +1007,7 @@
 
       // The rest of the value must be a multiple of two hex
       // characters.  The end of the value may be designated by the
-      // end of the DN, a comma or semicolon, or a space.
+      // end of the DN, a comma or semicolon, a plus sign, or a space.
       while (pos < length)
       {
         c = dnString.charAt(pos++);
@@ -1026,7 +1034,7 @@
             throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
           }
         }
-        else if (c == ' ' || c == ',' || c == ';')
+        else if (c == ' ' || c == ',' || c == ';' || c == '+')
         {
           // This denotes the end of the value.
           pos--;
@@ -1063,6 +1071,7 @@
       // Keep reading until we find an unescaped closing quotation mark.
       boolean escaped = false;
       StringBuilder valueString = new StringBuilder();
+      StringBuilder hexChars = new StringBuilder();
       while (true)
       {
         if (pos >= length)
@@ -1076,9 +1085,18 @@
         c = dnString.charAt(pos++);
         if (escaped)
         {
-          // The previous character was an escape, so we'll take this
-          // one no matter what.
-          valueString.append(c);
+          // The previous character was an escape. As in an unquoted value, and as DN.valueOf() reads
+          // a quoted value, an escaped pair of hex digits is one byte of the UTF-8 encoded value.
+          if (isHexDigit(c) && pos < length && isHexDigit(dnString.charAt(pos)))
+          {
+            hexChars.append(c);
+            hexChars.append(dnString.charAt(pos++));
+          }
+          else
+          {
+            appendHexChars(dnString, valueString, hexChars);
+            valueString.append(c);
+          }
           escaped = false;
         }
         else if (c == '\\')
@@ -1090,12 +1108,14 @@
         else if (c == '"')
         {
           // This is the end of the value.
+          appendHexChars(dnString, valueString, hexChars);
           break;
         }
         else
         {
           // This is just a regular character that should be in the
           // value.
+          appendHexChars(dnString, valueString, hexChars);
           valueString.append(c);
         }
       }
@@ -1131,6 +1151,12 @@
       {
         if (pos >= length)
         {
+          if (escaped)
+          {
+            // A lone backslash at the end, which DN.valueOf() rejects with the same message.
+            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
+                ERR_ATTR_SYNTAX_DN_TRAILING_ESCAPE.get(dnString));
+          }
           // This is the end of the DN and therefore the end of the value.
           // If there are any hex characters, then we need to deal with them accordingly.
           appendHexChars(dnString, valueString, hexChars);

--
Gitblit v1.10.0