Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,6 @@ def test_list_all_roles_by_objectclass_presence(self) -> None:
groups = self.rdn_values(self.search(PROXY_GROUPS_BASE, "(objectClass=*)"))
self.assertEqual(ALL_ROLES, set(groups))

# ApacheDS hands the interceptors (|(objectClass=groupOfNames)(objectClass=referral)), which
# the roles lookup does not take for a list search from an ancestor of ou=groups. So the
# backend groups are translated instead and roles assigned only to users (platform:deployer)
# are missing.
@unittest.skip("root-level role listing misses roles assigned only to users")
def test_list_all_roles_from_proxy_root_with_group_filter(self) -> None:
"""Searching from the proxy root with a group objectClass filter lists all roles."""
entries = self.search(PROXY_BASE_DN, "(objectClass=groupOfNames)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ public EntryFilteringCursor search(SearchOperationContext ctx) throws LdapExcept
private boolean isAllGroupsSearch(SearchOperationContext ctx) throws LdapException {
Dn proxyGroupSearchBaseDn = new Dn(schemaManager, proxyGroupSearchBase);
Dn searchDn = ctx.getDn();
ExprNode searchFilter = ctx.getFilter();
ExprNode rawSearchFilter = ctx.getFilter();
ExprNode searchFilter = removeReferral(rawSearchFilter);

if (searchDn == null) {
return false;
Expand All @@ -135,6 +136,22 @@ private boolean isAllGroupsSearch(SearchOperationContext ctx) throws LdapExcepti
&& isAllGroupsFilterForAncestor(searchFilter);
}

private ExprNode removeReferral(ExprNode rawSearchFilter) {
if (rawSearchFilter instanceof OrNode) {
OrNode orNode = (OrNode) rawSearchFilter;
if (orNode.getChildren().size() == 2) {
List<ExprNode> children = orNode.getChildren();
if (isReferralObjectClassFilter(children.get(0))) {
return children.get(1);
}
if (isReferralObjectClassFilter(children.get(1))) {
return children.get(0);
}
}
}
return rawSearchFilter;
}

private boolean isGroupObjectClassFilter(ExprNode filter) {
if (filter instanceof EqualityNode) {
EqualityNode<?> eqNode = (EqualityNode<?>) filter;
Expand All @@ -147,6 +164,17 @@ private boolean isGroupObjectClassFilter(ExprNode filter) {
return false;
}

private boolean isReferralObjectClassFilter(ExprNode filter) {
if (filter instanceof EqualityNode) {
EqualityNode<?> eqNode = (EqualityNode<?>) filter;
if ("objectClass".equalsIgnoreCase(eqNode.getAttribute())) {
String value = eqNode.getValue().toString();
return "referral".equalsIgnoreCase(value);
}
}
return false;
}

private boolean isAllGroupsFilterForAncestor(ExprNode filter) {
// Case 1: Simple objectClass evaluation (e.g., objectClass=groupOfNames)
if (isGroupObjectClassFilter(filter)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,12 @@ public void testAllGroupsSearchFromRootWithGroupObjectClassFilter() throws Excep
"(objectClass=groupOfUniqueNames)",
"(&(objectClass=groupOfNames)(cn=*))",
"(&(objectClass=groupOfNames)(|(cn=viewer)(cn=*)))",
"(|(objectClass=groupOfUniqueNames)(objectClass=groupOfNames))")) {
"(|(objectClass=groupOfUniqueNames)(objectClass=groupOfNames))",
"(|(objectClass=groupOfNames)(objectClass=referral))",

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.

These two cases hand-write the wrapped form for the simple filters only. The other entries in this list (the AND and nested-OR ones) still go to the interceptor unwrapped, which never happens in production unless the client sends ManageDsaIT. That's the same blind spot the JIRA describes. Could we add a helper that wraps the way ApacheDS does, e.g. new OrNode(FilterParser.parse(schemaManager, filter), FilterParser.parse(schemaManager, "(objectClass=referral)")), and use it for every filter in this test? The JIRA also asks for the negative side: please wrap the filters in testRootSearchWithNonGroupFilterIsNotAllGroupsSearch (line 688) as well, so non-group filters are still not treated as listings once wrapped.

"(|(objectClass=groupOfUniqueNames)(objectClass=referral))",
"(|(&(objectClass=groupOfNames)(cn=*))(objectClass=referral))",
"(|(&(objectClass=groupOfNames)(|(cn=viewer)(cn=*)))(objectClass=referral))",
"(|(|(objectClass=groupOfUniqueNames)(objectClass=groupOfNames))(objectClass=referral))")) {
final LDAPRolesLookupService rolesService = EasyMock.createMock(LDAPRolesLookupService.class);
expect(rolesService.listRoles()).andReturn(List.of("viewer"));
replay(rolesService);
Expand Down