[
https://issues.apache.org/jira/browse/KNOX-3406?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18109857#comment-18109857
]
ASF subversion and git services commented on KNOX-3406:
-------------------------------------------------------
Commit 232bc25664956bbf92b6a22f352e4a6c1cb02407 in knox's branch
refs/heads/v3.0.0 from David Han
[ https://gitbox.apache.org/repos/asf?p=knox.git;h=232bc2566 ]
KNOX-3406: LDAP Proxy backend improve error handling (#1355)
* KNOX-3406: LDAP Proxy backend improve error handling
The LdapProxyBackend.getUser code was modified to ensure that the search
cursor is closed before attempting to augment the entry with group memberships
to avoid having simultaneously open cursors.
The error handling in performPagedSearch was improved such that unsuccessful
paging calls will result in exceptions for the caller to handle.
* add null-handling for SearchResultDone
> Fix intermittent LDAP proxy search truncation
> ---------------------------------------------
>
> Key: KNOX-3406
> URL: https://issues.apache.org/jira/browse/KNOX-3406
> Project: Apache Knox
> Issue Type: Bug
> Components: Server
> Affects Versions: 3.0.0
> Reporter: Tamás Marcinkovics
> Assignee: David Han
> Priority: Minor
> Time Spent: 1h 10m
> Remaining Estimate: 0h
>
> Problem: CI intermittently fails test_search_all_groups_by_objectclass — an
> LDAP
> subtree search for (objectClass=groupOfNames) returns only ['level1']
> instead of all 6 groups.
> [https://github.com/apache/knox/actions/runs/30453311904/attempts/1]
> test_knox_ldap_proxy_search.py::TestKnoxLdapProxySearch::test_search_all_groups_by_objectclass
> ests-1 | =================================== FAILURES
> ===================================
> tests-1 | ________
> TestKnoxLdapProxySearch.test_search_all_groups_by_objectclass _________
> tests-1 |
> tests-1 | self = <test_knox_ldap_proxy_search.TestKnoxLdapProxySearch
> testMethod=test_search_all_groups_by_objectclass>
> tests-1 |
> tests-1 | def test_search_all_groups_by_objectclass(self) -> None:
> tests-1 | """All groupOfNames entries under ou=groups are returned."""
> tests-1 | groups = self.rdn_values(GROUPS_BASE, "(objectClass=groupOfNames)")
> tests-1 | for expected in ("analyst", "scientist", "admin", "level1",
> "level2", "level3"):
> tests-1 | > self.assertIn(expected, groups)
> tests-1 | E AssertionError: 'analyst' not found in ['level1']
> tests-1 |
> tests-1 | test_knox_ldap_proxy_search.py:97: AssertionError
>
> I could reproduce this on an ubuntu vm.
>
> Root cause:
> LdapProxyBackend.search() opens an EntryCursor
> over the outer search, then inside the while (cursor.next()) loop calls
> addGroupMemberships(entry, connection, ...) which, when
> useMemberOf=false, calls getUserGroupsInternal(connection, ...)
> , opening a second EntryCursor on the same LdapConnection.
> The Apache Directory LDAP client is not designed for two concurrent
> SearchRequests on one connection: the SearchResultDone PDU from the inner
> search is consumed
> by the outer cursor, which interprets it as "no more entries" and
> terminates early after only 1 result.
> This is a nested/concurrent cursor problem. It is intermittent because the
> inner search's response must race ahead of the outer cursor's next() call —
> which is CPU/network-scheduling dependent and more likely in CI's
> faster-burst containers.
> Fix:
> Drain the outer cursor first, then enrich.
> In search(), collect all raw entries into a list before calling
> addGroupMemberships on any of them. This ensures the outer EntryCursor is
> fully consumed and closed before any secondary LDAP operation is issued on
> the connection.
> Three methods need fixing:
> 1. searchUsers — outer while (cursor.next()) loop calls addGroupMemberships
> on each iteration. Fix: collect all sourceEntry objects into a list inside
> the cursor block, then iterate that list after the cursor closes.
> 2. search — same pattern as searchUsers. Same fix.
> 3. getUser — outer cursor does cursor.next() then calls addGroupMemberships
> before the cursor is closed. Since it only reads one entry though, this is
> lower risk: the inner search fires after cursor.next() returns, while the
> outer cursor is still open. The fix: copy the entry out, close the cursor
> (let the try-with-resources do it naturally by moving addGroupMemberships
> after the try block), then call addGroupMemberships.
> getUserGroupsEntries also open cursors, but those are called from
> addGroupMemberships — they are the inner cursors, not the outer ones. This
> does not need to be changed.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)