Skip to content

Validate LDAP_ENTRY_DN is within configured usersDn in searchLDAPByAt… - #51502

Merged
pedroigor merged 1 commit into
keycloak:mainfrom
sguilhen:51472-ldap-entry-dn-boundary
Aug 10, 2026
Merged

Validate LDAP_ENTRY_DN is within configured usersDn in searchLDAPByAt…#51502
pedroigor merged 1 commit into
keycloak:mainfrom
sguilhen:51472-ldap-entry-dn-boundary

Conversation

@sguilhen

@sguilhen sguilhen commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

…tributes

Closes #51472
Closes CVE-2026-16071

Copilot AI balanced review requested due to automatic review settings August 6, 2026 12:16
@sguilhen
sguilhen requested review from a team as code owners August 6, 2026 12:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents LDAP searches from accessing or importing users outside the configured usersDn boundary.

Changes:

  • Validates LDAP_ENTRY_DN before LDAP queries.
  • Adds regression coverage for out-of-scope DN searches.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java Enforces the configured LDAP user boundary.
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPSearchForUsersPaginationTest.java Tests rejection through provider and Admin API paths.

Copilot AI review requested due to automatic review settings August 6, 2026 19:17
@sguilhen
sguilhen force-pushed the 51472-ldap-entry-dn-boundary branch from 7399d14 to a722f57 Compare August 6, 2026 19:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

…tributes

Closes keycloak#51472
Closes CVE-2026-16071

Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
Copilot AI review requested due to automatic review settings August 10, 2026 16:07
@pedroigor
pedroigor force-pushed the 51472-ldap-entry-dn-boundary branch from a722f57 to 7281839 Compare August 10, 2026 16:07
@pedroigor
pedroigor enabled auto-merge (rebase) August 10, 2026 16:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPSearchForUsersPaginationTest.java:235

  • Stripping quotes via .replace("\"", "") is brittle (it can also alter legitimate DN contents if quotes appear, and it hides the actual contract of fetchString). Prefer returning a non-JSON-encoded value from the server helper (or using a helper that returns a raw string/structured response) so the test doesn’t need ad-hoc unquoting.
        String outOfScopeDn = testingClient.server().fetchString(session -> {
            LDAPTestContext ctx = LDAPTestContext.init(session);
            LDAPStorageProvider ldapProvider = ctx.getLdapProvider();
            LDAPTestUtils.addLdapOUinBaseDn(ldapProvider, "ServiceAccounts");

            LDAPObject ldapObject = new LDAPObject();
            ldapObject.setRdnAttributeName(ldapProvider.getLdapIdentityStore().getConfig().getRdnLdapAttribute());
            ldapObject.setObjectClasses(ldapProvider.getLdapIdentityStore().getConfig().getUserObjectClasses());
            ldapObject.setSingleAttribute(ldapProvider.getLdapIdentityStore().getConfig().getRdnLdapAttribute(), "outsideuser");
            ldapObject.setSingleAttribute(LDAPConstants.SN, "Outside");
            ldapObject.setSingleAttribute(LDAPConstants.CN, "outsideuser");
            ldapObject.setSingleAttribute(LDAPConstants.GIVENNAME, "Outside");
            ldapObject.setSingleAttribute("mail", "outsideuser@example.org");

            LDAPDn dn = LDAPDn.fromString(ldapProvider.getLdapIdentityStore().getConfig().getBaseDn());
            dn.addFirst("ou", "ServiceAccounts");
            dn.addFirst(ldapProvider.getLdapIdentityStore().getConfig().getRdnLdapAttribute(), "outsideuser");
            ldapObject.setDn(dn);
            ldapProvider.getLdapIdentityStore().add(ldapObject);

            // verify the entry exists in LDAP.
            try (LDAPQuery ldapQuery = LDAPUtils.createQueryForUserSearch(ldapProvider, ctx.getRealm())) {
                ldapQuery.setSearchDn(dn.toString());
                ldapQuery.setSearchScope(SearchControls.OBJECT_SCOPE);
                Assertions.assertNotNull(ldapQuery.getFirstResult(), "Out-of-scope LDAP entry should exist");
            }
            return dn.toString();
        }).replace("\"", "");

Comment on lines +562 to +567
LDAPDn entryDn = LDAPDn.fromString(entry.getValue());
LDAPDn usersDn = LDAPDn.fromString(ldapIdentityStore.getConfig().getUsersDn());
if (!entryDn.isDescendantOf(usersDn)) {
logger.debugf("LDAP_ENTRY_DN [%s] is not within configured usersDn [%s], returning empty stream", entry.getValue(), ldapIdentityStore.getConfig().getUsersDn());
return Stream.empty();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CVE-2026-16071 LDAP entry-dn user search bypasses configured users dn boundary

4 participants