From b4dfa93c8d9b6e08d5b5ca1f59697a17f75d0460 Mon Sep 17 00:00:00 2001 From: thanicz Date: Wed, 8 Jul 2026 10:12:51 +0200 Subject: [PATCH] KNOX-3374: Fix inherited roles missing from auth headers when LDAP roles-lookup interceptor is active --- .../services/ldap/KnoxLDAPServerManager.java | 5 ++ .../ldap/KnoxLDAPServerManagerTest.java | 49 ++++++++++++++++++- .../ConfigurableEntriesTestInterceptor.java | 2 +- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/KnoxLDAPServerManager.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/KnoxLDAPServerManager.java index 2c24426864..5d58b42e54 100644 --- a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/KnoxLDAPServerManager.java +++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/KnoxLDAPServerManager.java @@ -45,6 +45,7 @@ import org.apache.knox.gateway.config.GatewayConfig; import org.apache.knox.gateway.i18n.messages.MessagesFactory; import org.apache.knox.gateway.services.ldap.control.RolesLookupBypassControlFactory; +import org.apache.knox.gateway.services.ldap.control.RolesLookupBypassControlImpl; import org.apache.knox.gateway.services.ldap.interceptor.InterceptorFactory; import org.apache.knox.gateway.services.security.AliasService; @@ -377,6 +378,10 @@ public List getUserGroups(String username) throws Exception { searchRequest.setFilter("(uid=" + username + ")"); searchRequest.addAttributes("*"); + RolesLookupBypassControlImpl bypassControl = new RolesLookupBypassControlImpl(); + bypassControl.setBypassRolesLookup(true); + searchRequest.addControl(bypassControl); + List groups = new ArrayList<>(); try (Cursor cursor = directoryService.getAdminSession().search(searchRequest)) { if (cursor.next()) { diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/KnoxLDAPServerManagerTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/KnoxLDAPServerManagerTest.java index 8fc51bcbee..b277cb8351 100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/KnoxLDAPServerManagerTest.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/KnoxLDAPServerManagerTest.java @@ -19,16 +19,21 @@ import org.apache.directory.api.ldap.codec.api.ControlFactory; import org.apache.directory.api.ldap.model.cursor.EntryCursor; +import org.apache.directory.api.ldap.model.entry.DefaultEntry; +import org.apache.directory.api.ldap.model.entry.Entry; import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException; import org.apache.directory.api.ldap.model.exception.LdapException; import org.apache.directory.api.ldap.model.message.Control; import org.apache.directory.api.ldap.model.message.SearchScope; +import org.apache.directory.api.ldap.model.schema.SchemaManager; import org.apache.directory.ldap.client.api.LdapConnection; import org.apache.directory.ldap.client.api.LdapNetworkConnection; import org.apache.directory.server.core.api.interceptor.Interceptor; import org.apache.knox.gateway.config.GatewayConfig; import org.apache.knox.gateway.services.security.AliasService; import org.apache.knox.gateway.services.ldap.control.RolesLookupBypassControlFactory; +import org.apache.knox.gateway.services.ldap.interceptor.ConfigurableEntriesTestInterceptor; +import org.apache.knox.gateway.services.ldap.interceptor.LDAPRolesLookupInterceptor; import org.apache.knox.gateway.services.ldap.model.constants.SchemaConstants; import org.easymock.EasyMock; import org.apache.directory.api.ldap.model.name.Dn; @@ -40,12 +45,15 @@ import java.io.File; import java.net.ServerSocket; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.anyString; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.junit.Assert.assertEquals; @@ -408,6 +416,45 @@ public void testStartRegistersRolesLookupBypassControl() throws Exception { assertTrue(controlFactoryMap.get(SchemaConstants.ROLES_LOOKUP_BYPASS_CONTROL_OID) instanceof RolesLookupBypassControlFactory); } + @Test + public void testGetUserGroupsReturnsRawGroupsEvenWhenRolesInterceptorRewritesMemberOf() throws Exception { + GatewayConfig mockConfig = EasyMock.createNiceMock(GatewayConfig.class); + expect(mockConfig.getGatewayDataDir()).andReturn(tempWorkDir.getParent()).anyTimes(); + expect(mockConfig.getLDAPPort()).andReturn(port).anyTimes(); + expect(mockConfig.getLDAPBaseDN()).andReturn("dc=test,dc=com").anyTimes(); + expect(mockConfig.getLDAPInterceptorNames()).andReturn(List.of()).anyTimes(); + replay(mockConfig); + + serverManager.initialize(mockConfig); + serverManager.start(); + + SchemaManager schemaManager = serverManager.directoryService.getSchemaManager(); + Entry userEntry = new DefaultEntry(schemaManager); + userEntry.setDn("uid=admin,ou=people,dc=test,dc=com"); + userEntry.add("uid", "admin"); + userEntry.add("memberOf", "cn=me-test-group-a,ou=groups,dc=test,dc=com"); + userEntry.add("memberOf", "cn=me-test-group-b,ou=groups,dc=test,dc=com"); + ConfigurableEntriesTestInterceptor entriesInterceptor = new ConfigurableEntriesTestInterceptor("testEntries"); + entriesInterceptor.setEntries(List.of(userEntry)); + entriesInterceptor.init(serverManager.directoryService); + + LDAPRolesLookupService mockRolesService = EasyMock.createNiceMock(LDAPRolesLookupService.class); + expect(mockRolesService.lookupRoles(anyString(), anyObject())) + .andReturn(Arrays.asList("console:admin", "ws-1:viewer", "ws-2:user")).anyTimes(); + replay(mockRolesService); + LDAPRolesLookupInterceptor rolesInterceptor = new LDAPRolesLookupInterceptor(mockRolesService); + rolesInterceptor.init(serverManager.directoryService); + + List chain = new ArrayList<>(serverManager.directoryService.getInterceptors()); + chain.add(0, rolesInterceptor); + chain.add(1, entriesInterceptor); + serverManager.directoryService.setInterceptors(chain); + + List groups = serverManager.getUserGroups("admin"); + + assertEquals(Arrays.asList("me-test-group-a", "me-test-group-b"), groups); + } + @Test(expected = LdapException.class) public void testBindRequiredRejectsAnonymous() throws Exception { useBindPassword(BIND_PASSWORD); @@ -539,4 +586,4 @@ private void deleteRecursively(File file) { } file.delete(); } -} \ No newline at end of file +} diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/ConfigurableEntriesTestInterceptor.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/ConfigurableEntriesTestInterceptor.java index 27ac17f86b..a8507c614f 100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/ConfigurableEntriesTestInterceptor.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/ConfigurableEntriesTestInterceptor.java @@ -35,7 +35,7 @@ public class ConfigurableEntriesTestInterceptor extends BaseInterceptor { private List entries; private EntryFilteringCursor cursor; - ConfigurableEntriesTestInterceptor(String name) { + public ConfigurableEntriesTestInterceptor(String name) { super(name); }