This is an automated email from the ASF dual-hosted git repository.

smolnar82 pushed a commit to branch knox_idf
in repository https://gitbox.apache.org/repos/asf/knox.git

commit b4703a4691f427e01d302e328fd87f446ac625bb
Author: David Han <[email protected]>
AuthorDate: Mon Jun 15 05:13:08 2026 -0500

    KNOX-3340: Add Control for LDAPRolesLookupInterceptor (#1258)
    
    This commit adds a RolesLookupBypassControl for use with the 
LDAPRolesLookupInterceptor.
    The LDAPRolesLookupInterceptor will skip role mapping if this control is 
present and true
    in the request.
    
    (cherry picked from commit 644246b12564e40915dbc44d6eeddfb4c92ade3a)
---
 gateway-server/pom.xml                             |  10 ++
 .../services/ldap/KnoxLDAPServerManager.java       |  11 ++
 .../ldap/control/RolesLookupBypassControl.java     |  25 ++++
 .../control/RolesLookupBypassControlDecorator.java |  74 ++++++++++++
 .../control/RolesLookupBypassControlFactory.java   |  68 +++++++++++
 .../ldap/control/RolesLookupBypassControlImpl.java |  39 +++++++
 .../interceptor/LDAPRolesLookupInterceptor.java    |  14 +++
 .../ldap/interceptor/UserSearchInterceptor.java    |   6 -
 .../services/ldap/KnoxLDAPServerManagerTest.java   |  19 ++-
 .../RolesLookupBypassControlDecoratorTest.java     | 128 +++++++++++++++++++++
 .../RolesLookupBypassControlFactoryTest.java       |  99 ++++++++++++++++
 .../ConfigurableEntriesTestInterceptor.java        |  55 +++++++++
 .../DuplicateUserFilteringInterceptorTest.java     |  27 -----
 .../LDAPRolesLookupInterceptorTest.java            | 107 ++++++++++++++++-
 .../ldap/model/constants/SchemaConstants.java      |  29 +++++
 knox-site/docs/service_ldap_server.md              |  25 +++-
 pom.xml                                            |  10 ++
 17 files changed, 708 insertions(+), 38 deletions(-)

diff --git a/gateway-server/pom.xml b/gateway-server/pom.xml
index 41341bbfe..95bd6b24d 100644
--- a/gateway-server/pom.xml
+++ b/gateway-server/pom.xml
@@ -519,6 +519,16 @@
             <artifactId>api-ldap-client-api</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-codec-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-asn1-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.mina</groupId>
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 2cee21626..197a45a41 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
@@ -19,6 +19,8 @@ package org.apache.knox.gateway.services.ldap;
 
 import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
 import org.apache.directory.api.ldap.model.cursor.Cursor;
 import org.apache.directory.api.ldap.model.entry.Attribute;
 import org.apache.directory.api.ldap.model.entry.DefaultEntry;
@@ -42,6 +44,7 @@ import org.apache.directory.server.ldap.LdapServer;
 import org.apache.directory.server.protocol.shared.transport.TcpTransport;
 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.interceptor.InterceptorFactory;
 
 import java.io.File;
@@ -135,6 +138,14 @@ public class KnoxLDAPServerManager {
         directoryService = new DefaultDirectoryService();
         directoryService.setInstanceLayout(new InstanceLayout(workDir));
 
+        // Add RolesLookupBypassControlFactory
+        LdapApiService apiService = directoryService.getLdapCodecService();
+        if (apiService == null) {
+            apiService = LdapApiServiceFactory.getSingleton();
+        }
+        RolesLookupBypassControlFactory rolesLookupBypassControlFactory = new 
RolesLookupBypassControlFactory(apiService);
+        apiService.registerRequestControl(rolesLookupBypassControlFactory);
+
         // Create SchemaManager
         SchemaManager schemaManager = 
SchemaManagerFactory.createSchemaManager();
         directoryService.setSchemaManager(schemaManager);
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControl.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControl.java
new file mode 100644
index 000000000..78712fc38
--- /dev/null
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControl.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.services.ldap.control;
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+public interface RolesLookupBypassControl extends Control {
+    boolean isBypassRolesLookup();
+    void setBypassRolesLookup(boolean bypassRolesLookup);
+}
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlDecorator.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlDecorator.java
new file mode 100644
index 000000000..4821efc57
--- /dev/null
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlDecorator.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.services.ldap.control;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.util.Asn1Buffer;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+
+import java.nio.ByteBuffer;
+
+public class RolesLookupBypassControlDecorator extends 
ControlDecorator<RolesLookupBypassControl> implements RolesLookupBypassControl {
+
+    private final RolesLookupBypassControlFactory 
rolesLookupBypassControlFactory;
+
+    public RolesLookupBypassControlDecorator(LdapApiService codec, 
RolesLookupBypassControl decoratedControl, RolesLookupBypassControlFactory 
rolesLookupBypassControlFactory) {
+        super(codec, decoratedControl);
+        this.rolesLookupBypassControlFactory = rolesLookupBypassControlFactory;
+    }
+
+    @Override
+    public Asn1Object decode(byte[] bytes) throws DecoderException {
+        rolesLookupBypassControlFactory.decodeValue(getDecorated(), bytes);
+        return this;
+    }
+
+    @Override
+    public int computeLength() {
+        return 3; // Tag, Length, Value
+    }
+
+    @Override
+    public ByteBuffer encode(ByteBuffer byteBuffer) throws EncoderException {
+        Asn1Buffer asn1Buffer = new Asn1Buffer();
+        rolesLookupBypassControlFactory.encodeValue(asn1Buffer, 
getDecorated());
+
+        // reverse the byte ordering because Asn1Buffers store bytes in reverse
+        ByteBuffer factoryBuffer = asn1Buffer.getBytes();
+        int totalBytes = factoryBuffer.remaining();
+        byte[] factoryBytes = factoryBuffer.array();
+        for (int i = totalBytes - 1; i >= 0; i-- ) {
+            byteBuffer.put(factoryBytes[i]);
+        }
+
+        return byteBuffer;
+    }
+
+    @Override
+    public boolean isBypassRolesLookup() {
+        return getDecorated().isBypassRolesLookup();
+    }
+
+    @Override
+    public void setBypassRolesLookup(boolean bypassRolesLookup) {
+        getDecorated().setBypassRolesLookup(bypassRolesLookup);
+    }
+}
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlFactory.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlFactory.java
new file mode 100644
index 000000000..b700664bb
--- /dev/null
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlFactory.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.services.ldap.control;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.util.Asn1Buffer;
+import org.apache.directory.api.ldap.codec.api.AbstractControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.knox.gateway.services.ldap.model.constants.SchemaConstants;
+
+public class RolesLookupBypassControlFactory extends 
AbstractControlFactory<RolesLookupBypassControl> {
+    public static final byte BOOLEAN_TAG_BYTE = 0x01;
+
+    public RolesLookupBypassControlFactory(LdapApiService codec) {
+        super(codec, SchemaConstants.ROLES_LOOKUP_BYPASS_CONTROL_OID);
+    }
+
+    @Override
+    public Control newControl() {
+        return new RolesLookupBypassControlDecorator(codec, new 
RolesLookupBypassControlImpl(), this);
+    }
+
+    @Override
+    public void decodeValue(Control control, byte[] controlBytes) throws 
DecoderException {
+        if (control instanceof RolesLookupBypassControl) {
+            RolesLookupBypassControl rolesLookupBypassControl = 
(RolesLookupBypassControl) control;
+            if (controlBytes == null || controlBytes.length < 3) {
+                throw new DecoderException("Invalid BER encoding for Boolean 
Control");
+            }
+
+            if (controlBytes[0] != BOOLEAN_TAG_BYTE) {
+                throw new DecoderException("Expected Boolean Tag (0x01), 
found: " + controlBytes[0]);
+            }
+
+            boolean value = (controlBytes[2] != 0x00);
+            rolesLookupBypassControl.setBypassRolesLookup(value);
+        } else {
+            throw new DecoderException("Cannot decode into "  + 
control.getClass().getSimpleName() + ". Control must be instance of 
RolesLookupBypassControl.");
+        }
+    }
+
+    @Override
+    public void encodeValue(Asn1Buffer buffer, Control control) {
+        if (control instanceof RolesLookupBypassControl) {
+            RolesLookupBypassControl rolesLookupBypassControl = 
(RolesLookupBypassControl) control;
+
+            buffer.put(BOOLEAN_TAG_BYTE);
+            buffer.put((byte) 1); // Value is one byte long
+            buffer.put((byte) (rolesLookupBypassControl.isBypassRolesLookup() 
? 0xFF : 0x00));
+        }
+    }
+}
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlImpl.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlImpl.java
new file mode 100644
index 000000000..403ad85d0
--- /dev/null
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.services.ldap.control;
+
+import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+import org.apache.knox.gateway.services.ldap.model.constants.SchemaConstants;
+
+public class RolesLookupBypassControlImpl extends AbstractControl implements 
RolesLookupBypassControl {
+    private boolean bypassRolesLookup;
+
+    public RolesLookupBypassControlImpl() {
+        super(SchemaConstants.ROLES_LOOKUP_BYPASS_CONTROL_OID);
+    }
+
+    @Override
+    public boolean isBypassRolesLookup() {
+        return bypassRolesLookup;
+    }
+
+    @Override
+    public void setBypassRolesLookup(boolean bypassRolesLookup) {
+        this.bypassRolesLookup = bypassRolesLookup;
+    }
+}
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/interceptor/LDAPRolesLookupInterceptor.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/interceptor/LDAPRolesLookupInterceptor.java
index a860c2a4e..c5a5a6abe 100644
--- 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/interceptor/LDAPRolesLookupInterceptor.java
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/interceptor/LDAPRolesLookupInterceptor.java
@@ -23,6 +23,7 @@ import org.apache.directory.api.ldap.model.entry.Entry;
 import org.apache.directory.api.ldap.model.entry.Value;
 import org.apache.directory.api.ldap.model.exception.LdapException;
 import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.Control;
 import org.apache.directory.api.ldap.model.name.Dn;
 import org.apache.directory.api.ldap.model.name.Rdn;
 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
@@ -33,6 +34,8 @@ import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.services.ldap.LDAPRolesLookupService;
 import org.apache.knox.gateway.services.ldap.LdapMessages;
 import org.apache.knox.gateway.services.ldap.LdapUtils;
+import org.apache.knox.gateway.services.ldap.control.RolesLookupBypassControl;
+import org.apache.knox.gateway.services.ldap.model.constants.SchemaConstants;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -46,6 +49,7 @@ import java.util.Set;
  */
 public class LDAPRolesLookupInterceptor extends BaseInterceptor {
     private static final LdapMessages LOG = 
MessagesFactory.get(LdapMessages.class);
+
     private final LDAPRolesLookupService rolesLookupService;
 
     public LDAPRolesLookupInterceptor(LDAPRolesLookupService 
rolesLookupService) {
@@ -54,6 +58,16 @@ public class LDAPRolesLookupInterceptor extends 
BaseInterceptor {
 
     @Override
     public EntryFilteringCursor search(SearchOperationContext ctx) throws 
LdapException {
+        if 
(ctx.hasRequestControl(SchemaConstants.ROLES_LOOKUP_BYPASS_CONTROL_OID)) {
+            Control control = 
ctx.getRequestControl(SchemaConstants.ROLES_LOOKUP_BYPASS_CONTROL_OID);
+            if (control instanceof RolesLookupBypassControl) {
+                RolesLookupBypassControl rolesLookupBypassControl = 
(RolesLookupBypassControl) control;
+                if (rolesLookupBypassControl.isBypassRolesLookup()) {
+                    return next(ctx);
+                }
+            }
+        }
+
         final List<Entry> entries = new ArrayList<>();
         try (EntryFilteringCursor cursor = next(ctx)) {
             while (cursor.next()) {
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/interceptor/UserSearchInterceptor.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/interceptor/UserSearchInterceptor.java
index 0f67f2575..03743d959 100644
--- 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/interceptor/UserSearchInterceptor.java
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/ldap/interceptor/UserSearchInterceptor.java
@@ -22,7 +22,6 @@ import org.apache.directory.api.ldap.model.cursor.ListCursor;
 import org.apache.directory.api.ldap.model.entry.Entry;
 import org.apache.directory.api.ldap.model.exception.LdapException;
 import org.apache.directory.server.core.api.CoreSession;
-import org.apache.directory.server.core.api.DirectoryService;
 import org.apache.directory.server.core.api.LdapPrincipal;
 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
 import org.apache.directory.server.core.api.filtering.EntryFilteringCursorImpl;
@@ -63,11 +62,6 @@ public class UserSearchInterceptor extends BaseInterceptor {
         return backend;
     }
 
-    @Override
-    public void init(DirectoryService directoryService) throws LdapException {
-        super.init(directoryService);
-    }
-
     @Override
     public Entry lookup(LookupOperationContext ctx) throws LdapException {
         Entry entry = next(ctx);
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 b9ffdcda1..77229054e 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
@@ -17,8 +17,12 @@
  */
 package org.apache.knox.gateway.services.ldap;
 
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.model.message.Control;
 import org.apache.directory.server.core.api.interceptor.Interceptor;
 import org.apache.knox.gateway.config.GatewayConfig;
+import 
org.apache.knox.gateway.services.ldap.control.RolesLookupBypassControlFactory;
+import org.apache.knox.gateway.services.ldap.model.constants.SchemaConstants;
 import org.easymock.EasyMock;
 import org.apache.directory.api.ldap.model.name.Dn;
 import org.apache.knox.gateway.services.ldap.interceptor.UserSearchInterceptor;
@@ -374,8 +378,21 @@ public class KnoxLDAPServerManagerTest {
     }
 
     @Test
-    public void testGetUserGroups() {
+    public void testStartRegistersRolesLookupBypassControl() 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();
 
+        Map<String, ControlFactory<? extends Control>> controlFactoryMap = 
serverManager.directoryService.getLdapCodecService().getRequestControlFactories();
+        
assertTrue(controlFactoryMap.containsKey(SchemaConstants.ROLES_LOOKUP_BYPASS_CONTROL_OID));
+        
assertTrue(controlFactoryMap.get(SchemaConstants.ROLES_LOOKUP_BYPASS_CONTROL_OID)
 instanceof RolesLookupBypassControlFactory);
     }
 
     private Map<String, String> createFileBackendInterceptorConfig() {
diff --git 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlDecoratorTest.java
 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlDecoratorTest.java
new file mode 100644
index 000000000..2b6c3f44b
--- /dev/null
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlDecoratorTest.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.services.ldap.control;
+
+import static org.easymock.EasyMock.mock;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public class RolesLookupBypassControlDecoratorTest {
+
+    private RolesLookupBypassControl rolesLookupBypassControl;
+    private LdapApiService mockLdapApiService;
+    private RolesLookupBypassControlFactory rolesLookupBypassControlFactory;
+
+    private RolesLookupBypassControlDecorator 
rolesLookupBypassControlDecorator;
+
+    @Before
+    public void setUp() throws Exception {
+        mockLdapApiService = mock(LdapApiService.class);
+        replay(mockLdapApiService);
+
+        rolesLookupBypassControl = new RolesLookupBypassControlImpl();
+        rolesLookupBypassControlFactory = new 
RolesLookupBypassControlFactory(mockLdapApiService);
+
+        rolesLookupBypassControlDecorator = new 
RolesLookupBypassControlDecorator(mockLdapApiService, rolesLookupBypassControl, 
rolesLookupBypassControlFactory);
+    }
+
+    @Test
+    public void testDecodeFalseValue() throws Exception {
+        byte[] bytes = new byte[]{0x01, 0x01, 0x00};
+        rolesLookupBypassControlDecorator.decode(bytes);
+
+        assertFalse(rolesLookupBypassControl.isBypassRolesLookup());
+    }
+
+    @Test
+    public void testDecodeTrueValue() throws Exception {
+        byte[] bytes = new byte[]{0x01, 0x01, (byte) 0xff};
+        rolesLookupBypassControlDecorator.decode(bytes);
+
+        assertTrue(rolesLookupBypassControl.isBypassRolesLookup());
+    }
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeWrongTag() throws Exception {
+        byte[] bytes = new byte[]{0x02, 0x01, 0x00};
+        rolesLookupBypassControlDecorator.decode(bytes);
+    }
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeWrongLength() throws Exception {
+        byte[] bytes = new byte[]{0x02, 0x02, 0x00, 0x00};
+        rolesLookupBypassControlDecorator.decode(bytes);
+    }
+
+
+    @Test
+    public void testComputeLength() {
+        assertEquals("Length must always be 3", 3, 
rolesLookupBypassControlDecorator.computeLength());
+    }
+
+    @Test
+    public void testEncodeTrueValue() throws Exception {
+        testEncode(true);
+    }
+
+    @Test
+    public void testEncodeFalseValue() throws Exception {
+        testEncode(false);
+    }
+
+    private void testEncode(boolean encodeValue) throws Exception {
+        byte byteValue = encodeValue ? (byte) 0xff : 0x00;
+        rolesLookupBypassControlDecorator.setBypassRolesLookup(encodeValue);
+
+        byte[] expectedBytes = new byte[] {0x01, 0x01, byteValue};
+        ByteBuffer byteBuffer = ByteBuffer.allocate(3);
+        ByteBuffer encodedBuffer = 
rolesLookupBypassControlDecorator.encode(byteBuffer);
+        // transition from write mode to read mode
+        encodedBuffer.flip();
+        byte[] encodedBytes = new byte[encodedBuffer.remaining()];
+        encodedBuffer.get(encodedBytes);
+        assertArrayEquals(expectedBytes, encodedBytes);
+    }
+
+    @Test
+    public void testIsBypassRolesLookup() {
+        // Set value on the decorated instance and check that the decorator 
matches.
+        rolesLookupBypassControl.setBypassRolesLookup(true);
+        assertEquals("isBypassRolesLookup should match the value from the 
decorated Impl", true, rolesLookupBypassControlDecorator.isBypassRolesLookup());
+        rolesLookupBypassControl.setBypassRolesLookup(false);
+        assertEquals("isBypassRolesLookup should match the value from the 
decorated Impl", false, 
rolesLookupBypassControlDecorator.isBypassRolesLookup());
+    }
+
+    @Test
+    public void testSetBypassRolesLookup() {
+        // Set value on the decorator and check that the decorated instance 
matches.
+        rolesLookupBypassControlDecorator.setBypassRolesLookup(true);
+        assertEquals("Decorated instance value should be updated by the 
decorator", true, rolesLookupBypassControl.isBypassRolesLookup());
+        rolesLookupBypassControlDecorator.setBypassRolesLookup(false);
+        assertEquals("Decorated instance value should be updated by the 
decorator", false, rolesLookupBypassControl.isBypassRolesLookup());
+    }
+}
\ No newline at end of file
diff --git 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlFactoryTest.java
 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlFactoryTest.java
new file mode 100644
index 000000000..7e26224dc
--- /dev/null
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/control/RolesLookupBypassControlFactoryTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.services.ldap.control;
+
+import static org.easymock.EasyMock.mock;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.asn1.util.Asn1Buffer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public class RolesLookupBypassControlFactoryTest {
+
+    private LdapApiService mockLdapApiService;
+    private RolesLookupBypassControlFactory rolesLookupBypassControlFactory;
+
+    @Before
+    public void setUp() throws Exception {
+        mockLdapApiService = mock(LdapApiService.class);
+        replay(mockLdapApiService);
+        rolesLookupBypassControlFactory = new 
RolesLookupBypassControlFactory(mockLdapApiService);
+    }
+
+    @Test
+    public void testNewControl() {
+        Control control = rolesLookupBypassControlFactory.newControl();
+        assertTrue("Control must be a RolesLookupBypassControlDecorator", 
control instanceof RolesLookupBypassControlDecorator);
+    }
+
+    @Test
+    public void testDecodeFalseValue() throws Exception {
+        RolesLookupBypassControl control = new RolesLookupBypassControlImpl();
+        byte[] bytes = new byte[]{0x01, 0x01, 0x00};
+
+        rolesLookupBypassControlFactory.decodeValue(control, bytes);
+
+        assertFalse(control.isBypassRolesLookup());
+    }
+
+    @Test
+    public void testDecodeTrueValue() throws Exception {
+        RolesLookupBypassControl control = new RolesLookupBypassControlImpl();
+        byte[] bytes = new byte[]{0x01, 0x01, (byte) 0xff};
+
+        rolesLookupBypassControlFactory.decodeValue(control, bytes);
+
+        assertTrue(control.isBypassRolesLookup());
+    }
+
+    @Test
+    public void testEncodeTrueValue() {
+        testEncode(true);
+    }
+
+    @Test
+    public void testEncodeFalseValue() {
+        testEncode(false);
+    }
+
+    private void testEncode(boolean encodeValue) {
+        byte byteValue = encodeValue ? (byte) 0xff : 0x00;
+
+        Asn1Buffer asn1Buffer = new Asn1Buffer();
+        RolesLookupBypassControl control = new RolesLookupBypassControlImpl();
+        control.setBypassRolesLookup(encodeValue);
+
+        rolesLookupBypassControlFactory.encodeValue(asn1Buffer, control);
+
+        // expectedBytes in reverse because Asn1Buffer stores bytes in reverse 
order
+        byte[] expectedBytes = new byte[]{byteValue, 0x01, 0x01};
+        System.out.println(asn1Buffer.toString());
+        ByteBuffer encodedBuffer = asn1Buffer.getBytes();
+        byte[] encodedBytes = new byte[encodedBuffer.remaining()];
+        encodedBuffer.get(encodedBytes);
+        assertArrayEquals(expectedBytes, encodedBytes);
+    }
+}
\ 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
new file mode 100644
index 000000000..27ac17f86
--- /dev/null
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/ConfigurableEntriesTestInterceptor.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.services.ldap.interceptor;
+
+import org.apache.directory.api.ldap.model.cursor.ListCursor;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursorImpl;
+import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
+import 
org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
+
+import java.util.List;
+
+/**
+ * Interceptor for testing. This interceptor will return a Cursor of a List
+ * of configured Entries.
+ */
+public class ConfigurableEntriesTestInterceptor extends BaseInterceptor {
+    private List<Entry> entries;
+    private EntryFilteringCursor cursor;
+
+    ConfigurableEntriesTestInterceptor(String name) {
+        super(name);
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public EntryFilteringCursor getCursor() {
+        return cursor;
+    }
+
+    @Override
+    public EntryFilteringCursor search(SearchOperationContext searchContext) 
throws LdapException {
+        cursor = new EntryFilteringCursorImpl(new ListCursor<>(entries), 
searchContext, schemaManager);
+        return cursor;
+    }
+}
diff --git 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/DuplicateUserFilteringInterceptorTest.java
 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/DuplicateUserFilteringInterceptorTest.java
index 828937074..d4088a15b 100644
--- 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/DuplicateUserFilteringInterceptorTest.java
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/DuplicateUserFilteringInterceptorTest.java
@@ -21,18 +21,14 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import org.apache.directory.api.ldap.model.cursor.ListCursor;
 import org.apache.directory.api.ldap.model.entry.Attribute;
 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.entry.Value;
-import org.apache.directory.api.ldap.model.exception.LdapException;
 import org.apache.directory.api.ldap.model.schema.SchemaManager;
 import org.apache.directory.server.core.api.CoreSession;
 import org.apache.directory.server.core.api.DirectoryService;
 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
-import org.apache.directory.server.core.api.filtering.EntryFilteringCursorImpl;
-import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
 import 
org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
 import org.apache.knox.gateway.security.ldap.SimpleDirectoryService;
 import org.apache.knox.gateway.services.ldap.SchemaManagerFactory;
@@ -140,27 +136,4 @@ public class DuplicateUserFilteringInterceptorTest {
         Value value = uidAttr.get();
         assertEquals("Uid should match " + uid, uid, value.getString());
     }
-
-    private static class ConfigurableEntriesTestInterceptor extends 
BaseInterceptor {
-        private List<Entry> entries;
-        private EntryFilteringCursor cursor;
-
-        ConfigurableEntriesTestInterceptor(String name) {
-            super(name);
-        }
-
-        public void setEntries(List<Entry> entries) {
-            this.entries = entries;
-        }
-
-        public EntryFilteringCursor getCursor() {
-            return cursor;
-        }
-
-        @Override
-        public EntryFilteringCursor search(SearchOperationContext 
searchContext) throws LdapException {
-            cursor = new EntryFilteringCursorImpl(new ListCursor<>(entries), 
searchContext, schemaManager);
-            return cursor;
-        }
-    }
 }
\ No newline at end of file
diff --git 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/LDAPRolesLookupInterceptorTest.java
 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/LDAPRolesLookupInterceptorTest.java
index 637e1fc0f..52b37d99c 100644
--- 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/LDAPRolesLookupInterceptorTest.java
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/ldap/interceptor/LDAPRolesLookupInterceptorTest.java
@@ -20,20 +20,40 @@ package org.apache.knox.gateway.services.ldap.interceptor;
 import org.apache.directory.api.ldap.model.entry.Attribute;
 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.schema.SchemaManager;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
+import 
org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
+import org.apache.knox.gateway.security.ldap.SimpleDirectoryService;
 import org.apache.knox.gateway.services.ldap.LDAPRolesLookupService;
+import org.apache.knox.gateway.services.ldap.SchemaManagerFactory;
+import org.apache.knox.gateway.services.ldap.control.RolesLookupBypassControl;
+import 
org.apache.knox.gateway.services.ldap.control.RolesLookupBypassControlImpl;
 import org.easymock.EasyMock;
+import org.junit.Before;
 import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 
+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;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 public class LDAPRolesLookupInterceptorTest {
+    private SchemaManager schemaManager;
+
+    @Before
+    public void setUp() throws Exception {
+        schemaManager = SchemaManagerFactory.createSchemaManager();
+    }
 
     @Test
     public void testModifyEntryWithRoles() throws Exception {
@@ -68,14 +88,89 @@ public class LDAPRolesLookupInterceptorTest {
         assertNull(modifiedEntry.get("memberOf"));
     }
 
-    private LDAPRolesLookupInterceptor createInterceptor() {
+    @Test
+    public void testRolesLookupNoBypass() throws Exception {
         final LDAPRolesLookupService mockRolesService = 
EasyMock.createMock(LDAPRolesLookupService.class);
+
+        final Collection<String> roles = Arrays.asList("roleA", "roleG");
+        expect(mockRolesService.lookupRoles(anyString(), anyObject()))
+                .andReturn(roles)
+                .atLeastOnce();
         replay(mockRolesService);
-        return new LDAPRolesLookupInterceptor(mockRolesService);
+
+        TestContext testContext = createTestContext(false, mockRolesService);
+
+        // Set up test to with group and role mapping
+        final Entry userEntry = createUserEntry("alice", 
"cn=group1,ou=groups,dc=hadoop,dc=apache,dc=org");
+        testContext.nextInterceptor.setEntries(List.of(userEntry));
+
+        final EntryFilteringCursor entries = 
testContext.interceptor.search(testContext.ctx);
+
+        assertTrue(entries.next());
+        Entry modifiedEntry = entries.get();
+        assertMemberOf(modifiedEntry,
+                "cn=roleA,ou=groups,dc=hadoop,dc=apache,dc=org",
+                "cn=roleG,ou=groups,dc=hadoop,dc=apache,dc=org");
+        assertFalse(entries.next());
+    }
+
+    @Test
+    public void testRolesLookupWithBypass() throws Exception {
+        final LDAPRolesLookupService mockRolesService = 
EasyMock.createMock(LDAPRolesLookupService.class);
+
+        TestContext testContext = createTestContext(true, mockRolesService);
+
+        // Set up test to with group and role mapping
+        final Entry userEntry = createUserEntry("alice", 
"cn=group1,ou=groups,dc=hadoop,dc=apache,dc=org");
+        testContext.nextInterceptor.setEntries(List.of(userEntry));
+
+        final EntryFilteringCursor entries = 
testContext.interceptor.search(testContext.ctx);
+
+        assertTrue(entries.next());
+        Entry modifiedEntry = entries.get();
+        assertMemberOf(modifiedEntry, 
"cn=group1,ou=groups,dc=hadoop,dc=apache,dc=org");
+        assertFalse(entries.next());
+    }
+
+    private TestContext createTestContext(boolean bypass, 
LDAPRolesLookupService rolesService) throws Exception {
+        DirectoryService directoryService = new SimpleDirectoryService();
+        directoryService.setShutdownHookEnabled(false);
+        
directoryService.setSchemaManager(SchemaManagerFactory.createSchemaManager());
+
+        LDAPRolesLookupInterceptor interceptor =
+                new LDAPRolesLookupInterceptor(rolesService);
+        interceptor.init(directoryService);
+        directoryService.addLast(interceptor);
+
+        ConfigurableEntriesTestInterceptor nextInterceptor =
+                new ConfigurableEntriesTestInterceptor("NEXT");
+        nextInterceptor.init(directoryService);
+        directoryService.addLast(nextInterceptor);
+
+        SearchOperationContext ctx =
+                new SearchOperationContext(directoryService.getSession());
+        ctx.setInterceptors(List.of(interceptor.getName(), "NEXT"));
+
+        RolesLookupBypassControl control =
+                new RolesLookupBypassControlImpl();
+        control.setBypassRolesLookup(bypass);
+        ctx.addRequestControl(control);
+
+        return new TestContext(interceptor, nextInterceptor, ctx);
+    }
+
+    private LDAPRolesLookupService createMockRolesService() throws Exception {
+        final LDAPRolesLookupService mockRolesService = 
EasyMock.createMock(LDAPRolesLookupService.class);
+        replay(mockRolesService);
+        return mockRolesService;
+    }
+
+    private LDAPRolesLookupInterceptor createInterceptor() throws Exception {
+        return new LDAPRolesLookupInterceptor(createMockRolesService());
     }
 
     private Entry createUserEntry(final String username, final String... 
memberOfDns) throws Exception {
-        final Entry entry = new DefaultEntry();
+        final Entry entry = new DefaultEntry(schemaManager);
         entry.add("uid", username);
         for (final String dn : memberOfDns) {
             entry.add("memberOf", dn);
@@ -90,4 +185,10 @@ public class LDAPRolesLookupInterceptorTest {
             assertTrue("Missing expected role DN: " + expected, 
memberOf.contains(expected));
         }
     }
+
+    private record TestContext(
+            LDAPRolesLookupInterceptor interceptor,
+            ConfigurableEntriesTestInterceptor nextInterceptor,
+            SearchOperationContext ctx) {
+    }
 }
diff --git 
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/ldap/model/constants/SchemaConstants.java
 
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/ldap/model/constants/SchemaConstants.java
new file mode 100644
index 000000000..ef34744d7
--- /dev/null
+++ 
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/ldap/model/constants/SchemaConstants.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.services.ldap.model.constants;
+
+/**
+ * A utility class where we declare the schema objects being used by the Knox 
LDAP Server.
+ * Apache Knox OID Base = 1.3.6.1.4.1.18060.18
+ */
+public final class SchemaConstants {
+
+    // Apache Knox LDAP Controls 1.3.6.1.4.1.18060.18.0
+    public static final String ROLES_LOOKUP_BYPASS_CONTROL_OID = 
"1.3.6.1.4.1.18060.18.0.1";
+
+}
diff --git a/knox-site/docs/service_ldap_server.md 
b/knox-site/docs/service_ldap_server.md
index 6e0d1a56b..c6e6e9128 100644
--- a/knox-site/docs/service_ldap_server.md
+++ b/knox-site/docs/service_ldap_server.md
@@ -60,6 +60,24 @@ The duplicate user filter interceptor ensures that each 
`Entry` has a unique `ui
 
 The user search interceptor is created if the `interceptorType` configuration 
is set to `backend`. This interceptor forwards search queries to its configured 
backend.
 
+#### Roles Lookup Interceptor (`rolesLookup`)
+
+The rolesLookup interceptor is created if the `interceptorType` configuration 
is set to `rolesLookup`. This interceptor transforms the response entities 
based on the mappings provided by the Role Lookup Service. For each entity, a 
request will be made to lookup roles based on the user's name and group 
membership. These roles will replace the values in the `memberOf` attribute.
+
+The interceptor will skip role mapping for a search request if the 
RolesLookupBypassControl is set to true. The control is specified using it's 
OID, `1.3.6.1.4.1.18060.18.0.1`. The value is a 3 byte array. This value must 
be base64 encoded for `ldapsearch`.
+
+| Byte | Value | Description |
+| :--- | :--- | :--- |
+| Tag | 0x01 | The Boolean Tag value |
+| Length | 0x03 | The length of the value in bytes |
+| Bypass | 0x00 or Oxff | 0x00 corresponds to `false` and 0xff corresponds to 
`true |
+
+
+For example, the control can be added to the `ldapsearch` cli using the `-e` 
option.
+```shell script
+ldapsearch -v -x -H ldap://localhost:3890 -b 'ou=people,DC=proxy,DC=com' -e 
"1.3.6.1.4.1.18060.18.0.1=AQH/" '(uid=sam*)' '*'
+```
+
 ### Backend Types
 
 #### Common Backend Properties
@@ -259,13 +277,18 @@ Alternative: Use host and port instead of URL
 </property>
 -->
 
-
 <!-- Duplicate Filter Interceptor -->
 <property>
     <name>gateway.ldap.interceptor.duplicatefilter.interceptorType</name>
     <value>duplicateuserfilter</value>
 </property>
 
+<!-- Roles Lookup Interceptor -->
+<property>
+    <name>gateway.ldap.interceptor.rolesLookup.interceptorType</name>
+    <value>rolesLookup</value>
+</property>
+
 <!-- End LDAP Proxy Service Configuration -->
 ```
 
diff --git a/pom.xml b/pom.xml
index 70e6480b6..9bb9a2abc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2245,6 +2245,16 @@
                 <artifactId>api-util</artifactId>
                 <version>${apacheds.directory.api.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.directory.api</groupId>
+                <artifactId>api-ldap-codec-core</artifactId>
+                <version>${apacheds.directory.api.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.directory.api</groupId>
+                <artifactId>api-asn1-api</artifactId>
+                <version>${apacheds.directory.api.version}</version>
+            </dependency>
 
             <dependency>
                 <groupId>org.apache.mina</groupId>


Reply via email to