Default Role mapping to AD stopping creation of new users

We have an LDAP User Federation setup in Keycloak 19.0.3, along with a role-ldap-mapper.

This Role LDAP Mapper is setup as below:

My issue arises when I create a new user, upon first new user creation a new ‘role/group’ is created in our AD domain at the top level ou=environment,dc=base,dc=domain that is called ‘default-roles-master’ where master is our realm name.

This creates the user and assigns them to this role. The next user I create I get the following error and it fails to create the user successfully.

2023-04-05 15:53:02,282 WARN  [org.keycloak.services.resources.admin.UsersResource] (executor-thread-1731) Could not create user: org.keycloak.models.ModelException: Error creating subcontext [cn=default-roles-master,OU=environment,DC=base,DC=domain]
    at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.createSubContext(LDAPOperationManager.java:656)
    at org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore.add(LDAPIdentityStore.java:102)
    at org.keycloak.storage.ldap.LDAPUtils.createLDAPGroup(LDAPUtils.java:169)
    at org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapper.createLDAPRole(RoleLDAPStorageMapper.java:253)
    at org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapper.addRoleMappingInLDAP(RoleLDAPStorageMapper.java:263)
    at org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapper$LDAPRoleMappingsUserDelegate.grantRole(RoleLDAPStorageMapper.java:382)
    at org.keycloak.models.utils.UserModelDelegate.grantRole(UserModelDelegate.java:180)
    at org.keycloak.models.utils.UserModelDelegate.grantRole(UserModelDelegate.java:180)
    at org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapper$LDAPRoleMappingsUserDelegate.grantRole(RoleLDAPStorageMapper.java:384)
    at org.keycloak.models.utils.UserModelDelegate.grantRole(UserModelDelegate.java:180)
    at org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapper$LDAPRoleMappingsUserDelegate.grantRole(RoleLDAPStorageMapper.java:384)
    at org.keycloak.models.utils.UserModelDelegate.grantRole(UserModelDelegate.java:180)
    at org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapper$LDAPRoleMappingsUserDelegate.grantRole(RoleLDAPStorageMapper.java:384)
    at org.keycloak.models.utils.UserModelDelegate.grantRole(UserModelDelegate.java:180)
    at org.keycloak.models.utils.UserModelDelegate.grantRole(UserModelDelegate.java:180)
    at org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapper$LDAPRoleMappingsUserDelegate.grantRole(RoleLDAPStorageMapper.java:384)
    at org.keycloak.storage.ldap.LDAPStorageProvider.addUser(LDAPStorageProvider.java:302)
    at org.keycloak.storage.UserStorageManager.lambda$addUser$13(UserStorageManager.java:277)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:400)
    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.copyIntoWithCancel(AbstractPipeline.java:503)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543)
    at org.keycloak.storage.UserStorageManager.addUser(UserStorageManager.java:279)
    at org.keycloak.models.cache.infinispan.UserCacheSession.addUser(UserCacheSession.java:794)
    at org.keycloak.userprofile.AbstractUserProfileProvider$1.apply(AbstractUserProfileProvider.java:273)
    at org.keycloak.userprofile.AbstractUserProfileProvider$1.apply(AbstractUserProfileProvider.java:260)
    at org.keycloak.userprofile.DefaultUserProfile.create(DefaultUserProfile.java:87)
    at org.keycloak.services.resources.admin.UsersResource.createUser(UsersResource.java:157)
    at jdk.internal.reflect.GeneratedMethodAccessor802.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
    at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
    at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
    at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
    at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
    at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
    at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
    at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
    at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
    at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
    at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:90)
    at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
    at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
    at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
    at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:545)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
    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:829)
Caused by: javax.naming.NameAlreadyBoundException: [LDAP: error code 68 - 00002071: UpdErr: DSID-030503C4, problem 6005 (ENTRY_EXISTS), data 0
]; remaining name 'cn=default-roles-master,OU=environment,DC=base,DC=domain'
    at java.naming/com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3254)
    at java.naming/com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3205)
    at java.naming/com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2996)
    at java.naming/com.sun.jndi.ldap.LdapCtx.c_createSubcontext(LdapCtx.java:841)
    at java.naming/com.sun.jndi.toolkit.ctx.ComponentDirContext.p_createSubcontext(ComponentDirContext.java:341)
    at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.createSubcontext(PartialCompositeDirContext.java:268)
    at java.naming/javax.naming.directory.InitialDirContext.createSubcontext(InitialDirContext.java:202)
    at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager$7.execute(LDAPOperationManager.java:638)
    at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager$7.execute(LDAPOperationManager.java:635)
    at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:731)
    at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:711)
    at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:706)
    at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.createSubContext(LDAPOperationManager.java:635)
    ... 87 more

I have 2 issues, one is I don’t want it to create this default role inside my AD Domain, and second the above error when it does create the role/group and then I attempt to create a second user.

Is there a way around this?? Preferably by not creating the default role, or if it is required, by getting around the error when I create the 2nd user.

Thanks

I have updated to Keycloak 21.0.2 and get the same issue.

I have also tried excluding the role name in the LDAP Filter for Role Mapping, but no luck.

OK I’m able to get past this error, but it feels kinda hacky… can I get peoples opinions on this?

I have created a role/group in AD in the specific OU I want, and called it My-Custom-Default-Role.
I have then synced with Keycloak, and it appears in my Realm Roles (I have then taken note of the role id)…

I have then gone into the database, and in the ‘realms’ table, I have set the default_role value for my realm to be the new role id I have just created.

This now adds that role to all users, which is fine, and it allows for the creation of more than 1 user.

Will this be fine as a long term solution? Or will something break in the future?