[
https://issues.apache.org/jira/browse/KNOX-3337?focusedWorklogId=1023496&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1023496
]
ASF GitHub Bot logged work on KNOX-3337:
----------------------------------------
Author: ASF GitHub Bot
Created on: 03/Jun/26 12:24
Start Date: 03/Jun/26 12:24
Worklog Time Spent: 10m
Work Description: smolnar82 opened a new pull request, #1247:
URL: https://github.com/apache/knox/pull/1247
[KNOX-3337](https://issues.apache.org/jira/browse/KNOX-3337) - Introduce
LDAP Role Lookup Service
## What changes were proposed in this pull request?
This PR introduces a new LDAPRolesLookupService to Apache Knox, allowing for
dynamic mapping of users and groups to specific roles during the authentication
process. This is particularly useful for downstream services that require
fine-grained role information (e.g., `platform:admin`, `workspace:viewer`)
rather than just raw LDAP groups.
Key changes include:
- New Service Architecture: Implementation of `LDAPRolesLookupService`
with a pluggable strategy pattern.
- Lookup Strategies:
- `FileBasedLdapRolesLookup`: Maps roles based on a local JSON
configuration file.
- `RestApiLdapRolesLookup`: Queries an external REST API to retrieve
role assignments.
- `KnoxLDAPService` Integration: Updated the embedded LDAP service to
optionally utilize the role lookup service, allowing it to return resolved
roles in place of groups.
- `Header Propagation`: Updated AbstractAuthResource (used by `PreAuth`
and `ExtAuthz` resources) to populate a new `X-Knox-Actor-Roles` HTTP header
when role lookups are successful.
- Configuration: Added new `GatewayConfig` properties to configure the
lookup strategy, file paths, and API endpoints.
## How was this patch tested?
The changes were verified through both existing and newly added unit tests:
1. Unit Tests for Lookup Logic:
- `FileBasedLdapRolesLookupTest`: Verified JSON mapping logic for users
and groups.
- `RestApiLdapRolesLookupTest`: Verified REST API integration using mocked
HTTP clients.
2. Service Integration Tests:
- `KnoxLDAPServiceTest`: Updated to ensure `getUserGroups` correctly
integrates with the lookup service when enabled.
3. Authentication Resource Tests:
- `PreAuthResourceTest`: Added `testPopulatingRolesHeader` to verify
`X-Knox-Actor-Roles` is set correctly.
- `ExtAuthzResourceTest`: Added `testPopulatingRolesHeader` to verify role
propagation in external authorization flows.
## Integration Tests
No automated test added this time, but I configured Knox with
[MockServer](https://www.mock-server.com/where/docker.html) as role lookup
provider
```
$ curl -X PUT "http://localhost:55000/mockserver/expectation" \
-H "Content-Type: application/json" \
-d '{
"httpRequest": {
"method": "POST",
"path": "/auth/roles"
},
"httpResponse": {
"statusCode": 200,
"headers": {
"Content-Type": ["application/json"]
},
"body": {
"user_id": "alice",
"roles": [
{
"scope": "platform",
"name": "awc-admin"
},
{
"scope": "ml-workspace-abc",
"name": "viewer"
}
]
}
}
}'
```
and set the following configs in `gateway-reloadable.xml`:
```
<configuration>
<property>
<name>gateway.ldap.roles.lookup.strategy</name>
<value>rest</value>
</property>
<property>
<name>gateway.ldap.roles.lookup.rest.api.endpoint</name>
<value>http://localhost:55000/auth/roles</value>
</property>
</configuration>
```
Verified that the LDAP roles loookup service (as well as the Knox LDAP
service) was reconfigured properly:
```
2026-06-03 11:31:25,224 INFO knox.gateway
(GatewayServer.java:refreshGatewayConfig(275)) - Refreshed gateway config
2026-06-03 11:31:25,225 INFO services.ldap
(DefaultLDAPRolesLookupService.java:onGatewayConfigChanged(66)) - Reloading
LDAP roles lookup configuration...
2026-06-03 11:31:25,235 INFO services.ldap
(DefaultLDAPRolesLookupService.java:logStatus(50)) - LDAP roles lookup is
disabled
2026-06-03 11:31:25,235 INFO services.ldap
(KnoxLDAPService.java:onGatewayConfigChanged(99)) - Reloading LDAP configuration
2026-06-03 11:31:25,235 INFO services.ldap
(KnoxLDAPServerManager.java:stop(193)) - Stopping LDAP service on port 33,390
2026-06-03 11:31:25,246 INFO services.ldap
(KnoxLDAPServerManager.java:stop(211)) - LDAP service stopped successfully
2026-06-03 11:31:25,247 INFO services.ldap
(BackendFactory.java:createBackend(39)) - Loading backend: ldap (via
ServiceLoader)
2026-06-03 11:31:25,247 INFO services.ldap
(LdapProxyBackend.java:initialize(148)) - Loading backend: ldap (via Proxying
dc=hadoop,dc=apache,dc=org to ldap://localhost:33389
(dc=hadoop,dc=apache,dc=org) with uid attribute using group searches with
recursive group resolution (max depth: 3))
...
2026-06-03 11:32:25,223 INFO knox.gateway
(GatewayServer.java:refreshGatewayConfig(275)) - Refreshed gateway config
2026-06-03 11:32:29,362 INFO services.ldap
(DefaultLDAPRolesLookupService.java:onGatewayConfigChanged(66)) - Reloading
LDAP roles lookup configuration...
2026-06-03 11:32:53,041 INFO services.ldap
(DefaultLDAPRolesLookupService.java:logStatus(48)) - LDAP roles lookup is
enabled with strategy: rest
2026-06-03 11:32:55,655 INFO services.ldap
(KnoxLDAPService.java:onGatewayConfigChanged(99)) - Reloading LDAP configuration
2026-06-03 11:32:55,655 INFO services.ldap
(KnoxLDAPServerManager.java:stop(193)) - Stopping LDAP service on port 33,390
2026-06-03 11:32:55,659 INFO services.ldap
(KnoxLDAPServerManager.java:stop(211)) - LDAP service stopped successfully
2026-06-03 11:32:55,661 INFO services.ldap
(BackendFactory.java:createBackend(39)) - Loading backend: ldap (via
ServiceLoader)
2026-06-03 11:32:55,661 INFO services.ldap
(LdapProxyBackend.java:initialize(148)) - Loading backend: ldap (via Proxying
dc=hadoop,dc=apache,dc=org to ldap://localhost:33389
(dc=hadoop,dc=apache,dc=org) with uid attribute using group searches with
recursive group resolution (max depth: 3))
```
Then issued the following `curl` commands:
```
$ curl -iu recursiveUser:recursiveUser-password
http://localhost:8443/gateway/sandbox/auth/api/v1/pre
HTTP/1.1 200 OK
Date: Wed, 03 Jun 2026 09:33:14 GMT
Set-Cookie: KNOXSESSIONID=node016p2r5x9xtju1sxddl59m3a210.node0;
Path=/gateway/sandbox; Secure; HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: rememberMe=deleteMe; Path=/gateway/sandbox; Max-Age=0;
Expires=Tue, 02-Jun-2026 09:33:14 GMT; SameSite=lax
X-Knox-Actor-ID: recursiveUser
X-Knox-Actor-Roles: platform:awc-admin
X-Knox-Actor-Roles: ml-workspace-abc:viewer
Content-Length: 0
$ curl -iku admin:admin-password
http://localhost:8443/gateway/sandbox/auth/api/v1/pre
HTTP/1.1 200 OK
Date: Wed, 03 Jun 2026 09:36:34 GMT
Set-Cookie: KNOXSESSIONID=node01tgpz4zn4diz91vp1eiwyymtud1.node0;
Path=/gateway/sandbox; Secure; HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: rememberMe=deleteMe; Path=/gateway/sandbox; Max-Age=0;
Expires=Tue, 02-Jun-2026 09:36:34 GMT; SameSite=lax
X-Knox-Actor-ID: admin
X-Knox-Actor-Roles: platform:awc-admin
X-Knox-Actor-Roles: ml-workspace-abc:viewer
Content-Length: 0
```
Checked the logs:
```
2026-06-03 11:33:14,804 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
knox.gateway (GatewayFilter.java:doFilter(130)) - Received request: GET
/auth/api/v1/pre
2026-06-03 11:33:14,813 58981090-581a-40cb-b5c8-782b8fa6455d INFO
knox.gateway (KnoxLdapRealm.java:getUserDn(688)) - Computed userDn:
uid=recursiveUser,ou=people,dc=hadoop,dc=apache,dc=org using dnTemplate for
principal: recursiveUser
2026-06-03 11:33:14,839 DEBUG services.ldap
(GroupLookupInterceptor.java:bind(144)) - LDAP Bind:
uid=recursiveUser,ou=people,dc=hadoop,dc=apache,dc=org
2026-06-03 11:33:14,848 DEBUG services.ldap
(LdapProxyBackend.java:authenticate(278)) - LDAP authentication succeeded for
user: uid=recursiveUser,ou=people,dc=hadoop,dc=apache,dc=org
2026-06-03 11:33:19,007 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
knox.gateway (AuthFilterUtils.java:saveImpersonationProvider(138)) - Creating
impersonation provider in sandbox / identity-assertion with prefix
hadoop.proxyuser and config {admin.groups=*, admin.hosts=*,
impersonation.enabled=true}
2026-06-03 11:33:19,009 58981090-581a-40cb-b5c8-782b8fa6455d INFO
knox.gateway (HadoopGroupProviderFilter.java:hadoopGroups(135)) - Using Knox
LDAP service to fetch groups...
2026-06-03 11:33:19,018 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
services.ldap (LdapProxyBackend.java:resolveGroupsRecursive(400)) - Recursive
group search enabled: true, max depth: 3
2026-06-03 11:33:19,018 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
services.ldap (LdapProxyBackend.java:logRecursiveSearchProgress(515)) -
Recursive group search for user recursiveUser found 1 group(s) (level1) at
depth 0
2026-06-03 11:33:19,019 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
services.ldap (LdapProxyBackend.java:updateCache(488)) - Added parent
cn=level2,ou=groups,dc=hadoop,dc=apache,dc=org to cache for group
cn=level1,ou=groups,dc=hadoop,dc=apache,dc=org
2026-06-03 11:33:19,020 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
services.ldap (LdapProxyBackend.java:logRecursiveSearchProgress(515)) -
Recursive group search for user recursiveUser found 1 group(s) (level2) at
depth 1
2026-06-03 11:33:19,020 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
services.ldap (LdapProxyBackend.java:updateCache(488)) - Added parent
cn=level3,ou=groups,dc=hadoop,dc=apache,dc=org to cache for group
cn=level2,ou=groups,dc=hadoop,dc=apache,dc=org
2026-06-03 11:33:19,021 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
services.ldap (LdapProxyBackend.java:logRecursiveSearchProgress(515)) -
Recursive group search for user recursiveUser found 1 group(s) (level3) at
depth 2
2026-06-03 11:33:19,021 58981090-581a-40cb-b5c8-782b8fa6455d WARN
services.ldap (LdapProxyBackend.java:resolveGroupsRecursive(458)) - Recursive
group search for user recursiveUser reached max depth 3
2026-06-03 11:33:19,021 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
services.ldap (LdapProxyBackend.java:resolveGroupsRecursive(462)) - Recursive
group search for user recursiveUser completed. Total groups found: 3
2026-06-03 11:33:19,086 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
services.ldap (KnoxLDAPService.java:getUserGroups(149)) - LDAP roles lookup for
user recursiveUser and groups level1,level2,level3 returned roles:
platform:awc-admin,ml-workspace-abc:viewer
2026-06-03 11:33:19,086 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
knox.gateway (HadoopGroupProviderFilter.java:mapGroupPrincipals(115)) - Found
groups for principal recursiveUser : [platform:awc-admin,
ml-workspace-abc:viewer]
2026-06-03 11:33:19,087 58981090-581a-40cb-b5c8-782b8fa6455d DEBUG
knox.gateway (VirtualGroupMapper.java:mapGroups(59)) - User recursiveUser (with
group(s) [platform:awc-admin, ml-workspace-abc:viewer]) added to group(s) []
2026-06-03 11:34:07,954 DEBUG services.ldap
(GroupLookupInterceptor.java:bind(144)) - LDAP Bind:
uid=recursiveUser,ou=people,dc=hadoop,dc=apache,dc=org
2026-06-03 11:34:07,956 DEBUG services.ldap
(LdapProxyBackend.java:authenticate(278)) - LDAP authentication succeeded for
user: uid=recursiveUser,ou=people,dc=hadoop,dc=apache,dc=org
2026-06-03 11:34:07,958 DEBUG services.ldap
(GroupLookupInterceptor.java:search(79)) - LDAP Search:
dc=hadoop,dc=apache,dc=org | (|(uid=recursiveUser)(objectClass=referral))
2026-06-03 11:34:07,959 INFO services.ldap
(GroupLookupInterceptor.java:search(119)) - Loaded user from backend:
recursiveUser
2026-06-03 11:34:07,962 DEBUG services.ldap
(LdapProxyBackend.java:resolveGroupsRecursive(400)) - Recursive group search
enabled: true, max depth: 3
2026-06-03 11:34:07,962 DEBUG services.ldap
(LdapProxyBackend.java:logRecursiveSearchProgress(515)) - Recursive group
search for user recursiveUser found 1 group(s) (level1) at depth 0
2026-06-03 11:34:07,962 DEBUG services.ldap
(LdapProxyBackend.java:updateCache(488)) - Added parent
cn=level2,ou=groups,dc=hadoop,dc=apache,dc=org to cache for group
cn=level1,ou=groups,dc=hadoop,dc=apache,dc=org
2026-06-03 11:34:07,963 DEBUG services.ldap
(LdapProxyBackend.java:logRecursiveSearchProgress(515)) - Recursive group
search for user recursiveUser found 1 group(s) (level2) at depth 1
2026-06-03 11:34:07,963 DEBUG services.ldap
(LdapProxyBackend.java:updateCache(488)) - Added parent
cn=level3,ou=groups,dc=hadoop,dc=apache,dc=org to cache for group
cn=level2,ou=groups,dc=hadoop,dc=apache,dc=org
2026-06-03 11:34:07,963 DEBUG services.ldap
(LdapProxyBackend.java:logRecursiveSearchProgress(515)) - Recursive group
search for user recursiveUser found 1 group(s) (level3) at depth 2
2026-06-03 11:34:07,963 WARN services.ldap
(LdapProxyBackend.java:resolveGroupsRecursive(458)) - Recursive group search
for user recursiveUser reached max depth 3
2026-06-03 11:34:07,963 DEBUG services.ldap
(LdapProxyBackend.java:resolveGroupsRecursive(462)) - Recursive group search
for user recursiveUser completed. Total groups found: 3
...
2026-06-03 11:36:34,540 e394d849-9a41-4313-9e48-2505599077c4 DEBUG
knox.gateway (GatewayFilter.java:doFilter(130)) - Received request: GET
/auth/api/v1/pre
2026-06-03 11:36:34,541 e394d849-9a41-4313-9e48-2505599077c4 INFO
knox.gateway (KnoxLdapRealm.java:getUserDn(688)) - Computed userDn:
uid=admin,ou=people,dc=hadoop,dc=apache,dc=org using dnTemplate for principal:
admin
2026-06-03 11:36:34,543 DEBUG services.ldap
(GroupLookupInterceptor.java:bind(144)) - LDAP Bind:
uid=admin,ou=people,dc=hadoop,dc=apache,dc=org
2026-06-03 11:36:34,546 DEBUG services.ldap
(LdapProxyBackend.java:authenticate(278)) - LDAP authentication succeeded for
user: uid=admin,ou=people,dc=hadoop,dc=apache,dc=org
2026-06-03 11:36:34,547 e394d849-9a41-4313-9e48-2505599077c4 INFO
knox.gateway (HadoopGroupProviderFilter.java:hadoopGroups(135)) - Using Knox
LDAP service to fetch groups...
2026-06-03 11:36:34,549 e394d849-9a41-4313-9e48-2505599077c4 DEBUG
services.ldap (LdapProxyBackend.java:resolveGroupsRecursive(400)) - Recursive
group search enabled: true, max depth: 3
2026-06-03 11:36:34,549 e394d849-9a41-4313-9e48-2505599077c4 DEBUG
services.ldap (LdapProxyBackend.java:logRecursiveSearchProgress(515)) -
Recursive group search for user admin found 1 group(s) (admin) at depth 0
2026-06-03 11:36:34,550 e394d849-9a41-4313-9e48-2505599077c4 DEBUG
services.ldap (LdapProxyBackend.java:logRecursiveSearchProgress(515)) -
Recursive group search for user admin found 0 group(s) () at depth 1
2026-06-03 11:36:34,550 e394d849-9a41-4313-9e48-2505599077c4 DEBUG
services.ldap (LdapProxyBackend.java:resolveGroupsRecursive(462)) - Recursive
group search for user admin completed. Total groups found: 1
2026-06-03 11:36:34,560 e394d849-9a41-4313-9e48-2505599077c4 DEBUG
services.ldap (KnoxLDAPService.java:getUserGroups(149)) - LDAP roles lookup for
user admin and groups admin returned roles:
platform:awc-admin,ml-workspace-abc:viewer
2026-06-03 11:36:34,561 e394d849-9a41-4313-9e48-2505599077c4 DEBUG
knox.gateway (HadoopGroupProviderFilter.java:mapGroupPrincipals(115)) - Found
groups for principal admin : [platform:awc-admin, ml-workspace-abc:viewer]
2026-06-03 11:36:34,561 e394d849-9a41-4313-9e48-2505599077c4 DEBUG
knox.gateway (VirtualGroupMapper.java:mapGroups(59)) - User admin (with
group(s) [platform:awc-admin, ml-workspace-abc:viewer]) added to group(s) []
```
I also ran the new KnoxCLI command:
```
$ bin/knoxcli.sh ldap-user-groups-test --u recursiveUser
Querying KnoxLDAPService for groups of user: recursiveUser
recursiveUser is a member of: platform:awc-admin, ml-workspace-abc:viewer
```
## UI changes
N/A
Issue Time Tracking
-------------------
Worklog Id: (was: 1023496)
Remaining Estimate: 0h
Time Spent: 10m
> Enhance KnoxLdapService with Pluggable Role Lookup Support
> ----------------------------------------------------------
>
> Key: KNOX-3337
> URL: https://issues.apache.org/jira/browse/KNOX-3337
> Project: Apache Knox
> Issue Type: Improvement
> Components: Server
> Affects Versions: 3.0.0
> Reporter: Sandor Molnar
> Assignee: Sandor Molnar
> Priority: Critical
> Fix For: 3.0.0
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> Currently, the KnoxLdapService provides user and group information directly
> from its configured LDAP backend. In many deployment scenarios, particularly
> in modern cloud-native environments, there is a requirement to map these
> LDAP-authenticated identities and their group memberships to higher-level
> application roles managed by an external source.
> This JIRA introduces a pluggable role lookup mechanism within KnoxLdapService
> that allows Knox to intercept group resolution and instead populate roles
> from either a local configuration file (for testing purposes) or a remote
> REST API.
> *Key Features*
> 1. *Pluggable Interface:* Introduction of LdapRolesLookup to allow for
> extensible lookup strategies.
> 2. *REST Implementation:* A client implementation that POSTs user ID and
> group lists to a configured endpoint to retrieve role mappings, following a
> specific OpenAPI schema.
> 3. *File-based Implementation:* A JSON-based lookup strategy for static
> environments, using the same data structure as the REST API.
> 4. *Configuration-driven:* New gateway-site.xml properties to toggle
> lookup types and configure endpoints or file paths.
> *Proposed Configuration*
> * {{{}gateway.ldap.roles.lookup.strategy{}}}: Enables the lookup (file or
> rest).
> * {{{}gateway.ldap.roles.lookup.rest.api.endpoint{}}}: The destination URL
> for REST lookups.
> * {{{}gateway.ldap.roles.lookup.file.path{}}}: the file path which points to
> the JSON mapping file.
> *Data Contract:*
> The implementation will exchange JSON payloads containing a user_id and an
> array of groups, receiving a response containing a list of RoleAssignment
> objects (consisting of scope and name).
>
> This enhancement will allow for more dynamic and flexible authorization
> workflows in Knox-managed environments.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)