Skip to content

KNOX-3328: Implement recursive group resolution for LDAP proxy#1236

Open
smolnar82 wants to merge 5 commits into
apache:masterfrom
smolnar82:KNOX-3328
Open

KNOX-3328: Implement recursive group resolution for LDAP proxy#1236
smolnar82 wants to merge 5 commits into
apache:masterfrom
smolnar82:KNOX-3328

Conversation

@smolnar82
Copy link
Copy Markdown
Contributor

KNOX-3328 - Support recursive group resolution in LDAP Proxy Service

What changes were proposed in this pull request?

This PR introduces recursive group resolution to the LdapProxyBackend. Key changes include:

  • Recursive Logic: Implemented Breadth-First Search (BFS) for group resolution. When enabled, Knox will traverse the group hierarchy to find all transitive memberships.
  • Cycle Detection: Uses a visited Set to track processed DNs, ensuring that circular group references (e.g., Group A -> Group B -> Group A) do not cause infinite loops.
  • Depth Limiting: Added a new configuration gateway.ldap.group.max.depth (default 10) to limit how deep the recursion goes, protecting the Gateway from excessive LDAP round-trips.
  • Group Enrichment: Updated LdapProxyBackend.getUser to search both the user and group search bases. This allows group entries to be returned as "proxy entries" enriched with their own memberOf attributes.
  • Optimized Attribute Fetching: Implemented a hybrid lookup strategy. Initial user/entry lookups fetch all attributes (*, +) to ensure complete profile data, while recursive steps specifically request only the memberOf and operational attributes (+) to minimize network payload and processing overhead.
  • New Configuration Properties:
    • gateway.ldap.recursive.group.resolution: Boolean to enable/disable the feature.
    • gateway.ldap.group.max.depth: Integer to control recursion depth.

How was this patch tested?

The patch was tested using the LdapProxyBackendTest suite with an embedded ApacheDS server.

  • Unit Tests: Added 4 new test cases to LdapProxyBackendTest:
    • testGetUserGroupsRecursive: Verifies 3-level deep nesting is resolved correctly.
    • testGetUserGroupsRecursiveCircular: Verifies that circular references are handled without errors.
    • testGetUserGroupsRecursiveMaxDepth: Verifies that the recursion stops at the configured depth.
    • testGetUserGroupsRecursiveUseMemberOf: Verifies recursive resolution when useMemberOf is set to true.
  • Test Data: Updated ldap-proxy-backend-test.ldif to include nested groups, circular groups, and groups with memberOf attributes.

Integration Tests

Automated unit tests were added to gateway-server. These tests use an embedded LDAP server to simulate a real-world proxy scenario, which provides high-fidelity verification of the recursive logic and LDAP protocol handling. No changes were required to .github/workflows/tests as the standard test suite covers these new unit tests.

UI changes

N/A

@smolnar82 smolnar82 self-assigned this May 20, 2026
@smolnar82
Copy link
Copy Markdown
Contributor Author

Cc. @handavid

@smolnar82 smolnar82 added the ldap label May 20, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 20, 2026

Test Results

21 tests   21 ✅  1s ⏱️
 1 suites   0 💤
 1 files     0 ❌

Results for commit 529e44d.

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown
Contributor

@lmccay lmccay left a comment

Choose a reason for hiding this comment

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

@smolnar82 - thanks for this improvement!
Mostly looks good.
I question the default depth of 10 and am also wondering about cursor leaks.
Cursor leaks may have been an issue prior to this PR but we should be sure that things do get cleaned up properly.

cursor.close();

// 2. Try search in group base if not found in user base
String groupFilter = "(cn=" + username + ")";
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.

Do we know for sure that this will always be common name?
Also, I think a little more description of what this groupFilter's affect on the search will be in the comment would go a long way for future readers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll introduce a configurable groupIdentifierAttribute, defaulting to cn, and add descriptive comments to clarify this search.

}
cursor.close();

return null;
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.

do we not need any logging here?
What affect does not getting an Entry for the getUser method have?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The return null is actually not new in this PR:
image
According to the JavaDoc of the parent class, this is perfectly ok:
image
On the other hand, I agree that it's good to have some DEBUG log.

@smolnar82 smolnar82 requested a review from lmccay May 21, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants