Skip to content

[ZEPPELIN-6171] Resolve nested LDAP groups on FreeIPA via memberOf - #5505

Open
HwangRock wants to merge 2 commits into
apache:masterfrom
HwangRock:ZEPPELIN-6171-freeipa-memberof-nested-groups
Open

HwangRock wants to merge 2 commits into
apache:masterfrom
HwangRock:ZEPPELIN-6171-freeipa-memberof-nested-groups

Conversation

@HwangRock

Copy link
Copy Markdown
Contributor

What is this PR for?

LdapRealm resolves a user's groups in one of two ways today: the Active Directory LDAP_MATCHING_RULE_IN_CHAIN operator, or a group search over the member attribute. Neither works for nested groups on FreeIPA / 389 Directory Server — the AD matching rule isn't supported there, and the plain member search only sees direct members. So if a user is in dev and dev is a member of eng, the user's eng membership (and any role mapped to it) silently disappears.

This adds a third path. When ldapRealm.groupSearchEnableMemberOf = true, the realm reads the user entry's own memberOf attribute instead of walking the group tree. FreeIPA/389 DS already flattens direct and nested membership onto memberOf, so a single lookup of the user entry gives you the full set, nested groups included.

While adding it I split rolesFor() into three small per-strategy methods (matching-rule / group-membership / memberOf) so each path is readable on its own. The two existing paths are moved as-is, no behavior change.

New settings:

# resolve nested groups via the user's memberOf attribute (e.g. FreeIPA / 389 DS)
ldapRealm.groupSearchEnableMemberOf = true
ldapRealm.memberOfAttribute = memberOf

A few decisions worth calling out:

  • Precedence when both are on. If groupSearchEnableMatchingRuleInChain and groupSearchEnableMemberOf are both set, the matching-rule path wins and we log a one-time warning, rather than refusing to start. This keeps existing AD setups behaving exactly as before; the cost is that a contradictory config isn't hard-rejected, just warned.
  • Group name comes from the leaf RDN only. A memberOf value is a full group DN, and we take the group name from its leaf RDN without scanning ancestors. On FreeIPA a container on the path (cn=groups,cn=accounts,...) has the same cn= type as the group itself, so scanning would pick the wrong one. A malformed DN is skipped (and logged) instead of failing the login.
  • No behavior change for the existing paths. The matching-rule branch still doesn't populate the session group-name set the way the default branch does — that's pre-existing and I left it alone on purpose rather than "fixing" it in a refactor.

One prerequisite (documented in shiro_authentication.md): memberOf is only returned to an authenticated bind, which Zeppelin already does via systemUsername/systemPassword. Deployments that split groups and members across separate backends may also need server-side memberOf scope configuration.

What type of PR is it?

Improvement

Todos

  • memberOf-based group resolution path
  • split rolesFor() into per-strategy methods
  • unit tests
  • docs

What is the Jira issue?

ZEPPELIN-6171

How should this be tested?

LdapRealmTest (11 tests, mock-based) covers the memberOf path: nested resolution, matching-rule precedence, leaf-RDN fallback, and the empty / missing memberOf cases. The existing tests pass unchanged, which is what pins down that the two old paths still behave the same.

I also ran it end-to-end against a real 389 Directory Server (FreeIPA's LDAP engine) with a nested setup — alice ∈ dev, and dev ∈ eng:

# alice's memberOf at the directory level (server-flattened, ground truth)
$ ldapsearch ... -b 'uid=alice,ou=people,dc=example,dc=com' -s base memberOf
dn: uid=alice,ou=people,dc=example,dc=com
memberOf: cn=dev,ou=groups,dc=example,dc=com
memberOf: cn=eng,ou=groups,dc=example,dc=com

# LdapRealm.rolesFor(alice) against that server, only the new flag differs:
case A  groupSearchEnableMemberOf=false  ->  [dev]        # nested cn=eng missing
case B  groupSearchEnableMemberOf=true   ->  [dev, eng]   # nested cn=eng resolved

So the nested group is recovered only with the new flag on.

Questions:

  • Does the license files need to update? No
  • Is there breaking changes for older versions? No
  • Does this needs documentation? Yes — docs/setup/security/shiro_authentication.md is updated.

On FreeIPA (389 Directory Server) the AD LDAP_MATCHING_RULE_IN_CHAIN
operator isn't supported, and the default member-attribute search only
sees direct members, so a user's nested group memberships and their
roles were dropped.

Add a third resolution path: when groupSearchEnableMemberOf is set, read
the user entry's own memberOf attribute, which the directory pre-flattens
with nested membership. Split rolesFor() into three per-strategy private
methods so each path stays readable; the two existing paths are moved
unchanged and matchingRuleInChain keeps precedence when both are enabled.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant