[GH-ISSUE #705] Keycloak : searching for users while LDAP User Federation is on doesn't work #251

Closed
opened 2026-02-27 08:16:09 +03:00 by kerem · 11 comments
Owner

Originally created by @sbordeyne on GitHub (Oct 14, 2023).
Original GitHub issue: https://github.com/lldap/lldap/issues/705

Setup :

  • Keycloak:latest (v22.0.3)
  • LLDAP: latest (nitnelave/lldap:latest)
  • Setup using kubernetes 1.28

I followed the documentation here https://github.com/lldap/lldap/blob/main/example_configs/keycloak.md, and have the same group mappings, same settings. When searching for a user in keycloak, it crashes, and this is the traceback in the logs :

2023-10-14 09:31:42,212 ERROR [org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager] (executor-thread-41) Could not query server using DN [ou=people,dc=dogeek,dc=me] and filter [(&(|(uid=s*)(mail=s*)(givenname=s*)(sn=s*))(objectclass=person))]: javax.naming.OperationNotSupportedException: [LDAP: error code 53 - Unsupported user attribute for substring filter: "givenname"]; remaining name 'ou=people,dc=dogeek,dc=me'
        at java.naming/com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3333)
        at java.naming/com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3206)
        at java.naming/com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2997)
        at java.naming/com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1875)
        at java.naming/com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1798)
        at java.naming/com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:392)
        at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:358)
        at java.naming/javax.naming.directory.InitialDirContext.search(InitialDirContext.java:305)
        at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager$3.execute(LDAPOperationManager.java:256)
        at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager$3.execute(LDAPOperationManager.java:253)
        at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:729)
        at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:709)
        at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:704)
        at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.search(LDAPOperationManager.java:253)
        at org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore.fetchQueryResults(LDAPIdentityStore.java:279)
        at org.keycloak.storage.ldap.idm.query.internal.LDAPQuery.getResultList(LDAPQuery.java:167)
        at org.keycloak.storage.ldap.LDAPStorageProvider.paginatedSearchLDAP(LDAPStorageProvider.java:959)
        at org.keycloak.storage.ldap.LDAPStorageProvider.searchLDAP(LDAPStorageProvider.java:487)
        at org.keycloak.storage.ldap.LDAPStorageProvider.searchForUserStream(LDAPStorageProvider.java:366)
        at org.keycloak.storage.UserStorageManager.lambda$searchForUserStream$25(UserStorageManager.java:475)
        at org.keycloak.storage.UserStorageManager.lambda$query$13(UserStorageManager.java:303)
        at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:273)
        at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
        at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
        at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:395)
        at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
        at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310)
        at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
        at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.forEachOrdered(ReferencePipeline.java:601)
        at com.fasterxml.jackson.datatype.jdk8.StreamSerializer.serialize(StreamSerializer.java:71)
        at com.fasterxml.jackson.datatype.jdk8.StreamSerializer.serialize(StreamSerializer.java:15)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:399)
        at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1568)
        at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1061)
        at org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider.writeTo(ResteasyJackson2Provider.java:332)
        at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.lambda$writeTo$1(ServerWriterInterceptorContext.java:74)
        at io.quarkus.resteasy.runtime.standalone.VertxHttpRequest$VertxExecutionContext.executeBlockingIo(VertxHttpRequest.java:251)
        at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:73)
        at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.syncProceed(AbstractWriterInterceptorContext.java:224)
        at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:207)
        at org.keycloak.quarkus.runtime.integration.jaxrs.TransactionalResponseInterceptor.aroundWriteTo(TransactionalResponseInterceptor.java:42)
        at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.syncProceed(AbstractWriterInterceptorContext.java:231)
        at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.getStarted(AbstractWriterInterceptorContext.java:161)
        at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.lambda$getStarted$0(ServerWriterInterceptorContext.java:68)
        at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.aroundWriteTo(ServerWriterInterceptorContext.java:87)
        at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.getStarted(ServerWriterInterceptorContext.java:68)
        at org.jboss.resteasy.core.ServerResponseWriter.lambda$writeNomapResponse$3(ServerResponseWriter.java:166)
        at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:365)
        at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:243)
        at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:100)
        at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:73)
        at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:518)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:458)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321)
        at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:157)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:229)
        at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:82)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:147)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:84)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:44)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:58)
        at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:36)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$0(QuarkusRequestFilter.java:82)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:833)

I've tried deleting the attribute mappers to only leave the username mapper which maps to the uid attribute.

Furthermore, is there an exhaustive list of LDAP attributes set by LLDAP ?

Originally created by @sbordeyne on GitHub (Oct 14, 2023). Original GitHub issue: https://github.com/lldap/lldap/issues/705 Setup : - Keycloak:latest (v22.0.3) - LLDAP: latest (nitnelave/lldap:latest) - Setup using kubernetes 1.28 I followed the documentation here https://github.com/lldap/lldap/blob/main/example_configs/keycloak.md, and have the same group mappings, same settings. When searching for a user in keycloak, it crashes, and this is the traceback in the logs : ``` 2023-10-14 09:31:42,212 ERROR [org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager] (executor-thread-41) Could not query server using DN [ou=people,dc=dogeek,dc=me] and filter [(&(|(uid=s*)(mail=s*)(givenname=s*)(sn=s*))(objectclass=person))]: javax.naming.OperationNotSupportedException: [LDAP: error code 53 - Unsupported user attribute for substring filter: "givenname"]; remaining name 'ou=people,dc=dogeek,dc=me' at java.naming/com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3333) at java.naming/com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3206) at java.naming/com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2997) at java.naming/com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1875) at java.naming/com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1798) at java.naming/com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:392) at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:358) at java.naming/javax.naming.directory.InitialDirContext.search(InitialDirContext.java:305) at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager$3.execute(LDAPOperationManager.java:256) at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager$3.execute(LDAPOperationManager.java:253) at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:729) at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:709) at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:704) at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.search(LDAPOperationManager.java:253) at org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore.fetchQueryResults(LDAPIdentityStore.java:279) at org.keycloak.storage.ldap.idm.query.internal.LDAPQuery.getResultList(LDAPQuery.java:167) at org.keycloak.storage.ldap.LDAPStorageProvider.paginatedSearchLDAP(LDAPStorageProvider.java:959) at org.keycloak.storage.ldap.LDAPStorageProvider.searchLDAP(LDAPStorageProvider.java:487) at org.keycloak.storage.ldap.LDAPStorageProvider.searchForUserStream(LDAPStorageProvider.java:366) at org.keycloak.storage.UserStorageManager.lambda$searchForUserStream$25(UserStorageManager.java:475) at org.keycloak.storage.UserStorageManager.lambda$query$13(UserStorageManager.java:303) at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:273) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:395) at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEachOrdered(ReferencePipeline.java:601) at com.fasterxml.jackson.datatype.jdk8.StreamSerializer.serialize(StreamSerializer.java:71) at com.fasterxml.jackson.datatype.jdk8.StreamSerializer.serialize(StreamSerializer.java:15) at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:399) at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1568) at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1061) at org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider.writeTo(ResteasyJackson2Provider.java:332) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.lambda$writeTo$1(ServerWriterInterceptorContext.java:74) at io.quarkus.resteasy.runtime.standalone.VertxHttpRequest$VertxExecutionContext.executeBlockingIo(VertxHttpRequest.java:251) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:73) at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.syncProceed(AbstractWriterInterceptorContext.java:224) at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:207) at org.keycloak.quarkus.runtime.integration.jaxrs.TransactionalResponseInterceptor.aroundWriteTo(TransactionalResponseInterceptor.java:42) at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.syncProceed(AbstractWriterInterceptorContext.java:231) at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.getStarted(AbstractWriterInterceptorContext.java:161) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.lambda$getStarted$0(ServerWriterInterceptorContext.java:68) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.aroundWriteTo(ServerWriterInterceptorContext.java:87) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.getStarted(ServerWriterInterceptorContext.java:68) at org.jboss.resteasy.core.ServerResponseWriter.lambda$writeNomapResponse$3(ServerResponseWriter.java:166) at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:365) at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:243) at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:100) at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:73) at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:518) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:458) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:157) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:229) at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:82) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:147) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:84) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:44) at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284) at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177) at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141) at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:58) at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:36) at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284) at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177) at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141) at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$0(QuarkusRequestFilter.java:82) at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576) at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:833) ``` I've tried deleting the attribute mappers to only leave the `username` mapper which maps to the `uid` attribute. Furthermore, is there an exhaustive list of LDAP attributes set by LLDAP ?
kerem closed this issue 2026-02-27 08:16:09 +03:00
Author
Owner

@nitnelave commented on GitHub (Oct 14, 2023):

Hi!
There's something weird with your filters (or is it intentional?): you're requesting for first names/last names and so on that start with the letter "s". You can see that in the error, the LDAP filter contains (givenname=s*).
LLDAP only supports substring search for UIDs.

The list of supported attributes is for now only uid, email, first/last/display name and jpegPhoto (plus memberOf for group membership).

But with issue #67, you'll be able to add any attribute you want, as well as see the schema (the frontend part is not implemented yet, but the backend is almost done)

<!-- gh-comment-id:1762781887 --> @nitnelave commented on GitHub (Oct 14, 2023): Hi! There's something weird with your filters (or is it intentional?): you're requesting for first names/last names and so on that start with the letter "s". You can see that in the error, the LDAP filter contains `(givenname=s*)`. LLDAP only supports substring search for UIDs. The list of supported attributes is for now only uid, email, first/last/display name and jpegPhoto (plus memberOf for group membership). But with issue #67, you'll be able to add any attribute you want, as well as see the schema (the frontend part is not implemented yet, but the backend is almost done)
Author
Owner

@roseap42 commented on GitHub (Oct 15, 2023):

Ran into this same scenario this morning. My kludgy fix was to import ldap users into keycloak, disable ldap full/periodic sync, and then change the firstname/lastname mappings to use uid. (Certainly not a long-term solution, or anything that would work for more than a self-hosted small family sized set of users).

Adding attributes (as you mention in issue #67) will be awesome! However, the problem here is that we can't substring search on firstname/lastame (which I can verify using ldapsearch). Or am I misunderstanding and 67 will add or solve that?

Lastly, this is such a great project, thank you. I was trying to implement 389ds previously, which is neither simple nor "lightweight".

<!-- gh-comment-id:1763443456 --> @roseap42 commented on GitHub (Oct 15, 2023): Ran into this same scenario this morning. My kludgy fix was to import ldap users into keycloak, disable ldap full/periodic sync, and then change the firstname/lastname mappings to use uid. (Certainly not a long-term solution, or anything that would work for more than a self-hosted small family sized set of users). Adding attributes (as you mention in issue #67) will be awesome! However, the problem here is that we can't substring search on firstname/lastame (which I can verify using ldapsearch). Or am I misunderstanding and 67 will add or solve that? Lastly, this is such a great project, thank you. I was trying to implement 389ds previously, which is neither simple nor "lightweight".
Author
Owner

@sbordeyne commented on GitHub (Oct 15, 2023):

Hi! There's something weird with your filters (or is it intentional?): you're requesting for first names/last names and so on that start with the letter "s". You can see that in the error, the LDAP filter contains (givenname=s*). LLDAP only supports substring search for UIDs.

The list of supported attributes is for now only uid, email, first/last/display name and jpegPhoto (plus memberOf for group membership).

But with issue #67, you'll be able to add any attribute you want, as well as see the schema (the frontend part is not implemented yet, but the backend is almost done)

This is a bug then, in LLDAP. Keycloak expects to substring search in attributes for firstName, lastName and userName. As per your message, LLDAP supports substring search for

  • uid
  • email
  • firstname
  • lastname
  • displayname
  • jpegPhoto

I just updated my attribute mappings to map keycloak's firstName to LLDAP's firstname (as per your message, the LLDAP documentation misses the exact names of supported attributes.

I found this in the code, which looks like the list of supported attributes in LLDAP github.com/lldap/lldap@9e88bfe6b4/server/src/domain/ldap/user.rs (L104C1-L114C3)

Using anything BUT uid results in the aforementionned error. It makes it pretty hard to sync LLDAP to keycloak. Maybe for Keycloak, a more heavy duty solution like openLDAP is preferrable.

I tested by mapping firstName to :

  • cn
  • sn
  • firstname
  • first_name
  • lastname
  • last_name
<!-- gh-comment-id:1763474119 --> @sbordeyne commented on GitHub (Oct 15, 2023): > Hi! There's something weird with your filters (or is it intentional?): you're requesting for first names/last names and so on that start with the letter "s". You can see that in the error, the LDAP filter contains `(givenname=s*)`. LLDAP only supports substring search for UIDs. > > The list of supported attributes is for now only uid, email, first/last/display name and jpegPhoto (plus memberOf for group membership). > > But with issue #67, you'll be able to add any attribute you want, as well as see the schema (the frontend part is not implemented yet, but the backend is almost done) This is a bug then, in LLDAP. Keycloak expects to substring search in attributes for firstName, lastName and userName. As per your message, LLDAP supports substring search for - uid - email - firstname - lastname - displayname - jpegPhoto I just updated my attribute mappings to map keycloak's firstName to LLDAP's firstname (as per your message, the LLDAP documentation misses the exact names of supported attributes. I found this in the code, which looks like the list of supported attributes in LLDAP https://github.com/lldap/lldap/blob/9e88bfe6b44bbb347bf220698138205abbc89af3/server/src/domain/ldap/user.rs#L104C1-L114C3 Using anything BUT `uid` results in the aforementionned error. It makes it pretty hard to sync LLDAP to keycloak. Maybe for Keycloak, a more heavy duty solution like openLDAP is preferrable. I tested by mapping firstName to : - cn - sn - firstname - first_name - lastname - last_name
Author
Owner

@nitnelave commented on GitHub (Oct 15, 2023):

Ah, no, to be clear: the list of attributes that I listed are the ones that
are supported in LLDAP at all!
Substring search is only implemented for UIDs, and I'm not sure how easy it
would be to adapt it to the more general case (the other attributes are
encoded differently so I can't just write a pattern in SQL). I could add
support for email without too much trouble, but for the rest of the
attributes it's going to be hard.

But I'm not sure I understand: why does KeyCloak need to do a substring
search?

On Sun, 15 Oct 2023, 20:52 Simon Bordeyne, @.***> wrote:

Hi! There's something weird with your filters (or is it intentional?):
you're requesting for first names/last names and so on that start with the
letter "s". You can see that in the error, the LDAP filter contains
(givenname=s*). LLDAP only supports substring search for UIDs.

The list of supported attributes is for now only uid, email,
first/last/display name and jpegPhoto (plus memberOf for group membership).

But with issue #67 https://github.com/lldap/lldap/issues/67, you'll be
able to add any attribute you want, as well as see the schema (the frontend
part is not implemented yet, but the backend is almost done)

This is a bug then, in LLDAP. Keycloak expects to substring search in
attributes for firstName, lastName and userName. As per your message, LLDAP
supports substring search for

  • uid
  • email
  • firstname
  • lastname
  • displayname
  • jpegPhoto

I just updated my attribute mappings to map keycloak's firstName to
LLDAP's firstname (as per your message, the LLDAP documentation misses the
exact names of supported attributes.

I found this in the code, which looks like the list of supported
attributes in LLDAP
github.com/lldap/lldap@9e88bfe6b4/server/src/domain/ldap/user.rs (L104C1-L114C3)

Using anything BUT uid results in the aforementionned error. It makes it
pretty hard to sync LLDAP to keycloak. Maybe for Keycloak, a more heavy
duty solution like openLDAP is preferrable.

I tested by mapping firstName to :

  • cn
  • sn
  • firstname
  • first_name
  • lastname
  • last_name


Reply to this email directly, view it on GitHub
https://github.com/lldap/lldap/issues/705#issuecomment-1763474119, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/AAGCPWMT7QLBW3G6NRUCXATX7QWFDANCNFSM6AAAAAA6AEJD2E
.
You are receiving this because you commented.Message ID:
@.***>

<!-- gh-comment-id:1763478556 --> @nitnelave commented on GitHub (Oct 15, 2023): Ah, no, to be clear: the list of attributes that I listed are the ones that are supported in LLDAP *at all*! Substring search is only implemented for UIDs, and I'm not sure how easy it would be to adapt it to the more general case (the other attributes are encoded differently so I can't just write a pattern in SQL). I could add support for email without too much trouble, but for the rest of the attributes it's going to be hard. But I'm not sure I understand: why does KeyCloak need to do a substring search? On Sun, 15 Oct 2023, 20:52 Simon Bordeyne, ***@***.***> wrote: > Hi! There's something weird with your filters (or is it intentional?): > you're requesting for first names/last names and so on that start with the > letter "s". You can see that in the error, the LDAP filter contains > (givenname=s*). LLDAP only supports substring search for UIDs. > > The list of supported attributes is for now only uid, email, > first/last/display name and jpegPhoto (plus memberOf for group membership). > > But with issue #67 <https://github.com/lldap/lldap/issues/67>, you'll be > able to add any attribute you want, as well as see the schema (the frontend > part is not implemented yet, but the backend is almost done) > > This is a bug then, in LLDAP. Keycloak expects to substring search in > attributes for firstName, lastName and userName. As per your message, LLDAP > supports substring search for > > - uid > - email > - firstname > - lastname > - displayname > - jpegPhoto > > I just updated my attribute mappings to map keycloak's firstName to > LLDAP's firstname (as per your message, the LLDAP documentation misses the > exact names of supported attributes. > > I found this in the code, which looks like the list of supported > attributes in LLDAP > https://github.com/lldap/lldap/blob/9e88bfe6b44bbb347bf220698138205abbc89af3/server/src/domain/ldap/user.rs#L104C1-L114C3 > > Using anything BUT uid results in the aforementionned error. It makes it > pretty hard to sync LLDAP to keycloak. Maybe for Keycloak, a more heavy > duty solution like openLDAP is preferrable. > > I tested by mapping firstName to : > > - cn > - sn > - firstname > - first_name > - lastname > - last_name > > — > Reply to this email directly, view it on GitHub > <https://github.com/lldap/lldap/issues/705#issuecomment-1763474119>, or > unsubscribe > <https://github.com/notifications/unsubscribe-auth/AAGCPWMT7QLBW3G6NRUCXATX7QWFDANCNFSM6AAAAAA6AEJD2E> > . > You are receiving this because you commented.Message ID: > ***@***.***> >
Author
Owner

@roseap42 commented on GitHub (Oct 15, 2023):

Got it. And totally understand the balancing act of keeping this light and simple vs more and more features. This is exposed in keycloak in their user search function... keycloak imports users from ldap, so I imagine they're hitting their own list of users and ldap to help someone find a user whether they were imported or not? And to @sbordeyne 's point, keycloak may need a more fully featured ldap provider behind it. Thanks again.

<!-- gh-comment-id:1763491532 --> @roseap42 commented on GitHub (Oct 15, 2023): Got it. And totally understand the balancing act of keeping this light and simple vs more and more features. This is exposed in keycloak in their user search function... keycloak imports users from ldap, so I imagine they're hitting their own list of users and ldap to help someone find a user whether they were imported or not? And to @sbordeyne 's point, keycloak may need a more fully featured ldap provider behind it. Thanks again.
Author
Owner

@sbordeyne commented on GitHub (Oct 15, 2023):

But I'm not sure I understand: why does KeyCloak need to do a substring
search?

Without any other configuration, Keycloak on its own tries to search by last name, first name and username. When you set up federated identities, that means doing fuzzy searches in the federated backends.

I feel like LLDAP is so close to being the perfect backend for Keycloak, but just that makes it a bit of a dealbreaker (not being able to add users to groups because the search breaks is kind of a dealbreaker, though mapping everything to uid is a working workaround if you don't mind your users being named $uid $uid 😄

<!-- gh-comment-id:1763502029 --> @sbordeyne commented on GitHub (Oct 15, 2023): > But I'm not sure I understand: why does KeyCloak need to do a substring search? Without any other configuration, Keycloak on its own tries to search by last name, first name and username. When you set up federated identities, that means doing fuzzy searches in the federated backends. I feel like LLDAP is so close to being the perfect backend for Keycloak, but just that makes it a bit of a dealbreaker (not being able to add users to groups because the search breaks is kind of a dealbreaker, though mapping everything to uid is a working workaround if you don't mind your users being named `$uid $uid` 😄
Author
Owner

@nitnelave commented on GitHub (Oct 15, 2023):

Wouldn't it be possible to configure KeyCloak to only search by uid? That
seems like it'd give the most bang for the buck, especially with LLDAP

On Sun, 15 Oct 2023, 22:57 Simon Bordeyne, @.***> wrote:

But I'm not sure I understand: why does KeyCloak need to do a substring
search?

Without any other configuration, Keycloak on its own tries to search by
last name, first name and username. When you set up federated identities,
that means doing fuzzy searches in the federated backends.

I feel like LLDAP is so close to being the perfect backend for Keycloak,
but just that makes it a bit of a dealbreaker (not being able to add users
to groups because the search breaks is kind of a dealbreaker, though
mapping everything to uid is a working workaround if you don't mind your
users being named $uid $uid 😄


Reply to this email directly, view it on GitHub
https://github.com/lldap/lldap/issues/705#issuecomment-1763502029, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/AAGCPWPELBANGWAUKTRQB4DX7RE2HANCNFSM6AAAAAA6AEJD2E
.
You are receiving this because you commented.Message ID:
@.***>

<!-- gh-comment-id:1763502453 --> @nitnelave commented on GitHub (Oct 15, 2023): Wouldn't it be possible to configure KeyCloak to only search by uid? That seems like it'd give the most bang for the buck, especially with LLDAP On Sun, 15 Oct 2023, 22:57 Simon Bordeyne, ***@***.***> wrote: > But I'm not sure I understand: why does KeyCloak need to do a substring > search? > > Without any other configuration, Keycloak on its own tries to search by > last name, first name and username. When you set up federated identities, > that means doing fuzzy searches in the federated backends. > > I feel like LLDAP is so close to being the perfect backend for Keycloak, > but just that makes it a bit of a dealbreaker (not being able to add users > to groups because the search breaks is kind of a dealbreaker, though > mapping everything to uid is a working workaround if you don't mind your > users being named $uid $uid 😄 > > — > Reply to this email directly, view it on GitHub > <https://github.com/lldap/lldap/issues/705#issuecomment-1763502029>, or > unsubscribe > <https://github.com/notifications/unsubscribe-auth/AAGCPWPELBANGWAUKTRQB4DX7RE2HANCNFSM6AAAAAA6AEJD2E> > . > You are receiving this because you commented.Message ID: > ***@***.***> >
Author
Owner

@sbordeyne commented on GitHub (Oct 16, 2023):

Unfortunately, I haven't found a way to customize the default search in Keycloak. I feel like I'll move over to OpenLDAP since I'll want to handle everything in Keycloak anyways (password resets, identity management, user federation...). Thanks for your time.

<!-- gh-comment-id:1763928538 --> @sbordeyne commented on GitHub (Oct 16, 2023): Unfortunately, I haven't found a way to customize the default search in Keycloak. I feel like I'll move over to OpenLDAP since I'll want to handle everything in Keycloak anyways (password resets, identity management, user federation...). Thanks for your time.
Author
Owner

@nitnelave commented on GitHub (Oct 16, 2023):

Alright, sorry it couldn't work for you. Make sure to check out kanidm too as a fully-featured LDAP server (AFAIK) that's much more modern and lighter than OpenLDAP (and might even replace KeyCloak for your use case?) The dev is a friend and very knowledgeable in all things LDAP.

<!-- gh-comment-id:1764077505 --> @nitnelave commented on GitHub (Oct 16, 2023): Alright, sorry it couldn't work for you. Make sure to check out kanidm too as a fully-featured LDAP server (AFAIK) that's much more modern and lighter than OpenLDAP (and might even replace KeyCloak for your use case?) The dev is a friend and _very_ knowledgeable in all things LDAP.
Author
Owner

@sbordeyne commented on GitHub (Oct 16, 2023):

Thanks for the recommendation, though I'll stick with keycloak for other reasons, namely that it's used in enterprise grade software as well for identity management, and I want to become more proficient at it to be able to add strings to my bow so to speak.

Furthermore, I've already set up Keycloak (with great trouble), so I don't feel like uprooting my whole IDP again right now

<!-- gh-comment-id:1764452802 --> @sbordeyne commented on GitHub (Oct 16, 2023): Thanks for the recommendation, though I'll stick with keycloak for other reasons, namely that it's used in enterprise grade software as well for identity management, and I want to become more proficient at it to be able to add strings to my bow so to speak. Furthermore, I've already set up Keycloak (with great trouble), so I don't feel like uprooting my whole IDP again right now
Author
Owner

@nbently commented on GitHub (Jan 12, 2024):

Figured out a workaround in case anyone is interested. I wasn't able to find a way to modify Keycloak's default LDAP search filter, however if you search for the uid in quotes, (e.g. "jdoe") in Keycloak's user search box, it seems to work. I suspect enclosing a value in quotes forces it to search only on uid.

<!-- gh-comment-id:1888291008 --> @nbently commented on GitHub (Jan 12, 2024): Figured out a workaround in case anyone is interested. I wasn't able to find a way to modify Keycloak's default LDAP search filter, however if you search for the uid in quotes, (e.g. "jdoe") in Keycloak's user search box, it seems to work. I suspect enclosing a value in quotes forces it to search only on uid.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/lldap-lldap#251
No description provided.