From 81bc6cd81b347f178a1a2b85e33b7101d1241c41 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Mon, 05 Oct 2026 12:38:31 +0000
Subject: [PATCH] [#1155] Make the rest2ldap bind templates and HTTP Basic credentials work as documented (#1165)

---
 opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/AuthzIdTemplate.java |   16 ++++++++++++----
 1 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/AuthzIdTemplate.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/AuthzIdTemplate.java
index 096ad78..dc5b653 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/AuthzIdTemplate.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/AuthzIdTemplate.java
@@ -12,6 +12,7 @@
  * information: "Portions copyright [year] [name of copyright owner]".
  *
  * Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.forgerock.opendj.rest2ldap.authz;
 
@@ -48,6 +49,10 @@
         public String formatAsAuthzId(final AuthzIdTemplate t, final Object[] templateVariables) {
             // We're not interested in matching and place-holder attribute types can be tolerated,
             // so we can just use the core schema.
+            // A template which is just one placeholder takes the principal as the DN, rather than as one RDN value.
+            if ("%s".equals(t.formatString)) {
+                return DN.valueOf(String.valueOf(templateVariables[0]), Schema.getCoreSchema()).toString();
+            }
             return DN.format(t.formatString, Schema.getCoreSchema(), templateVariables).toString();
         }
     };
@@ -126,14 +131,17 @@
     }
 
     private String formatTemplate(final String template) {
-        // Parse the template keys and replace them with %s for formatting.
+        // Parse the template keys and replace them with %s for formatting. Escape any '%' around them, which
+        // String.format() would read as a format specifier.
         final Matcher matcher = TEMPLATE_KEY_RE.matcher(template);
-        final StringBuffer buffer = new StringBuffer(template.length());
+        final StringBuilder buffer = new StringBuilder(template.length());
+        int fixedPartStart = 0;
         while (matcher.find()) {
-            matcher.appendReplacement(buffer, "%s");
+            buffer.append(template.substring(fixedPartStart, matcher.start()).replace("%", "%%")).append("%s");
             keys.add(matcher.group(1));
+            fixedPartStart = matcher.end();
         }
-        matcher.appendTail(buffer);
+        buffer.append(template.substring(fixedPartStart).replace("%", "%%"));
         return type.removeTemplateKey(buffer.toString());
     }
 

--
Gitblit v1.10.0