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/SaslPlainStrategy.java | 28 ++++++++++++++++------------
1 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/SaslPlainStrategy.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/SaslPlainStrategy.java
index 58b7b09..a883844 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/SaslPlainStrategy.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/authz/SaslPlainStrategy.java
@@ -12,6 +12,7 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.forgerock.opendj.rest2ldap.authz;
@@ -20,19 +21,17 @@
import static org.forgerock.services.context.SecurityContext.AUTHZID_ID;
import static org.forgerock.util.Reject.checkNotNull;
import static org.forgerock.opendj.rest2ldap.authz.Utils.close;
+import static org.forgerock.opendj.rest2ldap.authz.Utils.formatBindDn;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
-import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
-import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.DecodeOptions;
import org.forgerock.opendj.ldap.LdapException;
-import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.controls.AuthorizationIdentityRequestControl;
import org.forgerock.opendj.ldap.controls.AuthorizationIdentityResponseControl;
import org.forgerock.opendj.ldap.responses.BindResult;
@@ -42,6 +41,7 @@
import org.forgerock.util.AsyncFunction;
import org.forgerock.util.Function;
import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.Promises;
/** Bind using a computed DN from a template and the current request/context. */
final class SaslPlainStrategy implements AuthenticationStrategy {
@@ -56,7 +56,8 @@
* Factory used to get {@link Connection} receiving the sasl-bind requests
* @param authcIdTemplate
* Authentication identity template containing a single %s which will be replaced by the authenticating
- * user's name. (i.e: (u:%s)
+ * user's name. (i.e: (u:%s). After a "dn:" prefix the template is a bind DN template: just %s takes the
+ * user name as the DN, otherwise the user name is escaped as an attribute value.
* @param schema
* Schema used to perform DN validation.
* @throws NullPointerException
@@ -68,14 +69,12 @@
checkNotNull(schema, "schema cannot be null");
checkNotNull(authcIdTemplate, "authcIdTemplate cannot be null");
if (authcIdTemplate.startsWith("dn:")) {
+ // As AuthzIdTemplate does, ignore spaces after the key: "dn: {username}" is "dn:{username}".
+ final String dnTemplate = authcIdTemplate.substring("dn:".length()).trim();
formatter = new Function<String, String, LdapException>() {
@Override
public String apply(String value) throws LdapException {
- try {
- return DN.format(authcIdTemplate, schema, value).toString();
- } catch (LocalizedIllegalArgumentException e) {
- throw LdapException.newLdapException(ResultCode.INVALID_DN_SYNTAX, e.getMessageObject(), e);
- }
+ return "dn:" + formatBindDn(dnTemplate, schema, value);
}
};
} else {
@@ -91,6 +90,12 @@
@Override
public Promise<SecurityContext, LdapException> authenticate(final String username, final String password,
final Context parentContext) {
+ final String authcId;
+ try {
+ authcId = formatter.apply(username);
+ } catch (final LdapException e) {
+ return Promises.newExceptionPromise(e);
+ }
final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
return connectionFactory
.getConnectionAsync()
@@ -98,15 +103,14 @@
@Override
public Promise<SecurityContext, LdapException> apply(Connection connection) throws LdapException {
connectionHolder.set(connection);
- return doSaslPlainBind(connection, parentContext, username, password);
+ return doSaslPlainBind(connection, parentContext, username, authcId, password);
}
}).thenFinally(close(connectionHolder));
}
private Promise<SecurityContext, LdapException> doSaslPlainBind(final Connection connection,
final Context parentContext, final String authzId,
- final String password) throws LdapException {
- final String authcId = formatter.apply(authzId);
+ final String authcId, final String password) {
return connection
.bindAsync(newPlainSASLBindRequest(authcId, password.toCharArray())
.addControl(AuthorizationIdentityRequestControl.newControl(true)))
--
Gitblit v1.10.0