Sandor Molnar created KNOX-3490:
-----------------------------------
Summary: LDAPRolesLookupInterceptor resolves the wrong username
when the LDAP client does not request the uid attribute, causing incorrect role
lookups
Key: KNOX-3490
URL: https://issues.apache.org/jira/browse/KNOX-3490
Project: Apache Knox
Issue Type: Bug
Components: Server
Affects Versions: 3.0.0
Reporter: Sandor Molnar
Assignee: Sandor Molnar
Fix For: 3.1.0
*Background*
Knox's embedded LDAP server supports a roles-lookup feature:
{{LDAPRolesLookupInterceptor}} intercepts search results, derives the user's
identity from the returned entry, calls the configured roles-lookup service
with that identity, and rewrites the entry's {{memberOf}} values to reflect the
resolved roles.
In a federated topology this embedded LDAP on a _central_ cluster is queried by
a _local_ cluster. The _local_ cluster resolves groups/roles via Hadoop's
{{LdapGroupsMapping}} (through {{{}HadoopGroupProviderFilter{}}}), connecting
to the central cluster's embedded LDAP over LDAPS.
*The bug*
The interceptor derives the username with:
{code:java}
final String username = LdapUtils.extractUsernameFromEntry(entry, "uid",
"cn");{code}
{{extractUsernameFromEntry}} reads attribute values from the entry, but the
entry has already been trimmed to the attributes the client requested.
{{LdapGroupsMapping}} requests only the attributes it needs for group
resolution (e.g. {{{}memberOf{}}}/{{{}group-name{}}} attributes) and does *not*
request {{{}uid{}}}. As a result, by the time the interceptor runs, the {{uid}}
attribute is gone and the code falls back to {{{}cn{}}}, which is a
human-readable display name rather than the stable login id.
The roles-lookup service is then called with the display name instead of the
{{{}uid{}}}, and returns the wrong set of roles (or none).
*Observed behavior*
For the same user, two paths produce different results against the same
roles-lookup service:
||Path 1||Attributes requested||user_id sent to lookup||Roles returned||
|_Central_ cluster (requests all attributes, *)|includes uid|<uid> (e.g.
[email protected])|correct (e.g. 4 roles)|
|_Local_ cluster via {{LdapGroupsMapping}}|uid *not* requested|cn display name
(e.g. John Doe)|wrong (e.g. 1 role)|
*Root cause*
The username is read from an attribute that may be absent depending on what the
client requested. The entry's DN ({{{}uid=…,ou=…{}}}), however, is always
present regardless of the requested attribute set, and already carries the
stable {{uid}} in its RDN.
*Steps to Reproduce*
1. Configure Knox's embedded LDAP with roles lookup enabled.
2. Perform an LDAP search that requests only group-related attributes and omits
{{uid}} (as Hadoop {{LdapGroupsMapping}} does).
3. Observe that the roles-lookup call is keyed on the {{cn}} display name,
returning the wrong roles.
4. Repeat the search requesting * (all attributes) and observe the correct
roles - confirming the discrepancy is driven purely by which attributes the
client requested.
*Expected Behavior*
Role lookup is keyed on the stable {{uid}} regardless of which attributes the
client requested, so all clients receive a consistent set of roles for the same
user.
*Proposed Fix*
Derive the username from the entry's DN first (always present), falling back to
entry attributes only if the DN does not yield a uid:
{code:java}
String username = LdapUtils.extractUsernameFromDn(entry.getDn());
if (username == null) {
username = LdapUtils.extractUsernameFromEntry(entry, "uid", "cn");
}{code}
{{LdapUtils.extractUsernameFromDn}} returns the RDN value when the RDN type is
{{{}uid{}}}, which is immune to attribute trimming. The fallback preserves
existing behavior for entries whose DN is not uid-based.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)