This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch karaf-4.4.x
in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/karaf-4.4.x by this push:
new 8e69e00bd4 Escape %u/%dn/%fqdn substitutions in LDAP search filters
(CWE-90) (#2881)
8e69e00bd4 is described below
commit 8e69e00bd43d6383003c77e3981b9a884c95f1a0
Author: JB Onofré <[email protected]>
AuthorDate: Fri Sep 11 16:08:15 2026 +0200
Escape %u/%dn/%fqdn substitutions in LDAP search filters (CWE-90) (#2881)
LDAPCache and LDAPBackingEngine.lookupUser built search filters by
substituting %u/%dn/%fqdn and only doubling backslashes, which does not
escape *, (, ), or NUL. LDAPLoginModule and LDAPPubkeyLoginModule masked
this by pre-escaping the username themselves, but GSSAPILdapLoginModule
and LDAPBackingEngine.lookupUser did not, so filter metacharacters in a
login name could widen a search (e.g. a username of "*" matches any
entry) and potentially over-grant roles.
Centralize proper RFC 4515 filter escaping in LDAPCache/LDAPBackingEngine
using the existing Util.doRFC2254Encoding helper, and drop the redundant
pre-escaping in LDAPLoginModule/LDAPPubkeyLoginModule so escaping happens
exactly once, at the point filters are built.
---
.../karaf/jaas/modules/ldap/LDAPBackingEngine.java | 4 ++--
.../org/apache/karaf/jaas/modules/ldap/LDAPCache.java | 10 ++++------
.../apache/karaf/jaas/modules/ldap/LDAPLoginModule.java | 2 +-
.../karaf/jaas/modules/ldap/LDAPPubkeyLoginModule.java | 2 +-
.../apache/karaf/jaas/modules/ldap/LdapCacheTest.java | 17 +++++++++++++++++
5 files changed, 25 insertions(+), 10 deletions(-)
diff --git
a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPBackingEngine.java
b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPBackingEngine.java
index 1039a60ee8..9a4528bdf2 100644
---
a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPBackingEngine.java
+++
b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPBackingEngine.java
@@ -31,6 +31,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -74,8 +75,7 @@ public class LDAPBackingEngine implements BackingEngine {
}
String filter = options.getUserFilter();
- filter = filter.replaceAll(Pattern.quote("%u"), username);
- filter = filter.replace("\\", "\\\\");
+ filter = filter.replaceAll(Pattern.quote("%u"),
Matcher.quoteReplacement(Util.doRFC2254Encoding(username)));
LOGGER.debug("Looking for user {} in LDAP with", username);
LOGGER.debug(" base DN: {}", options.getUserBaseDn());
diff --git
a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPCache.java
b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPCache.java
index 20759e8ee5..d459f6d61b 100644
---
a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPCache.java
+++
b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPCache.java
@@ -196,8 +196,7 @@ public class LDAPCache implements Closeable,
NamespaceChangeListener, ObjectChan
}
String filter = options.getUserFilter();
- filter = filter.replaceAll(Pattern.quote("%u"),
Matcher.quoteReplacement(user));
- filter = filter.replace("\\", "\\\\");
+ filter = filter.replaceAll(Pattern.quote("%u"),
Matcher.quoteReplacement(Util.doRFC2254Encoding(user)));
LOGGER.debug("Looking for the user in LDAP with ");
LOGGER.debug(" base DN: " + options.getUserBaseDn());
@@ -297,10 +296,9 @@ public class LDAPCache implements Closeable,
NamespaceChangeListener, ObjectChan
String filter = options.getRoleFilter();
if (filter != null) {
- filter = filter.replaceAll(Pattern.quote("%u"),
Matcher.quoteReplacement(user));
- filter = filter.replaceAll(Pattern.quote("%dn"),
Matcher.quoteReplacement(userDn));
- filter = filter.replaceAll(Pattern.quote("%fqdn"),
Matcher.quoteReplacement(userDnNamespace));
- filter = filter.replace("\\", "\\\\");
+ filter = filter.replaceAll(Pattern.quote("%u"),
Matcher.quoteReplacement(Util.doRFC2254Encoding(user)));
+ filter = filter.replaceAll(Pattern.quote("%dn"),
Matcher.quoteReplacement(Util.doRFC2254Encoding(userDn)));
+ filter = filter.replaceAll(Pattern.quote("%fqdn"),
Matcher.quoteReplacement(Util.doRFC2254Encoding(userDnNamespace)));
LOGGER.debug("Looking for the user roles in LDAP with ");
LOGGER.debug(" base DN: {}", options.getRoleBaseDn());
diff --git
a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java
b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java
index e64e36e3f9..c979e41cec 100644
---
a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java
+++
b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java
@@ -70,7 +70,7 @@ public class LDAPLoginModule extends AbstractKarafLoginModule
{
throw new LoginException(unsupportedCallbackException.getMessage()
+ " not available to obtain information from user.");
}
- user = Util.doRFC2254Encoding(((NameCallback) callbacks[0]).getName());
+ user = ((NameCallback) callbacks[0]).getName();
char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
diff --git
a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPPubkeyLoginModule.java
b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPPubkeyLoginModule.java
index 308763d8bc..3a45e2b932 100644
---
a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPPubkeyLoginModule.java
+++
b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPPubkeyLoginModule.java
@@ -69,7 +69,7 @@ public class LDAPPubkeyLoginModule extends
AbstractKarafLoginModule {
throw new LoginException(unsupportedCallbackException.getMessage()
+ " not available to obtain information from user.");
}
- user = Util.doRFC2254Encoding(((NameCallback) callbacks[0]).getName());
+ user = ((NameCallback) callbacks[0]).getName();
PublicKey remotePubkey = ((PublickeyCallback)
callbacks[1]).getPublicKey();
diff --git
a/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/ldap/LdapCacheTest.java
b/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/ldap/LdapCacheTest.java
index 1568ac532d..006b3003e3 100644
---
a/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/ldap/LdapCacheTest.java
+++
b/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/ldap/LdapCacheTest.java
@@ -19,6 +19,7 @@ import static
org.apache.karaf.jaas.modules.PrincipalHelper.names;
import static org.apache.karaf.jaas.modules.ldap.LdapPropsUpdater.ldapProps;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -120,6 +121,22 @@ public class LdapCacheTest extends AbstractLdapTestUnit {
}
}
+ @Test
+ public void testUserFilterInjectionDoesNotWidenSearch() throws Exception {
+ // "*" would widen (uid=%u) to (uid=*), matching any existing user,
unless
+ // the substituted value is properly filter-escaped (CWE-90).
+ Properties options = ldapLoginModuleOptions();
+ LDAPCache cache = LDAPCache.getCache(new LDAPOptions(options));
+ assertNull(cache.getUserDnAndNamespace("*"));
+ }
+
+ @Test
+ public void testBackingEngineUserFilterInjectionDoesNotWidenSearch()
throws Exception {
+ Properties options = ldapLoginModuleOptions();
+ LDAPBackingEngine engine = new LDAPBackingEngine(options);
+ assertNull(engine.lookupUser("*"));
+ }
+
@Test
public void testLDAPCacheHashCode() throws Exception {
Properties options = ldapLoginModuleOptions();