anarsultanov / keycloak-multi-tenancy Goto Github PK
View Code? Open in Web Editor NEWKeycloak extension for creating multi-tenant IAM for B2B SaaS applications.
License: Apache License 2.0
Keycloak extension for creating multi-tenant IAM for B2B SaaS applications.
License: Apache License 2.0
I get "Internal Server Error" when using the DELETE /tenants/${tenantId}/memberships/${memberId} endpoint on a fresh member.
Keycloak version 22.0.1
Keycloak-multi-tenancy version 22.0.0
Steps to reproduce:
The keycloak logs shows error log:
Detail: Key (id)=(df2c5d55-5361-4b6a-85c7-42d624acc4c1) is still referenced from table "user_role_mapping".] [delete from USER_ENTITY where ID=?]
2023-08-30T09:35:26.906617491+02:00 at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:95)
2023-08-30T09:35:26.906633630+02:00 at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:56)
2023-08-30T09:35:26.906647820+02:00 at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108)
2023-08-30T09:35:26.906659930+02:00 at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:278)
2023-08-30T09:35:26.906672940+02:00 at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:108)
2023-08-30T09:35:26.906686583+02:00 at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:40)
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:53)
2023-08-30T09:35:26.906714353+02:00 at org.hibernate.persister.entity.mutation.DeleteCoordinator.doStaticDelete(DeleteCoordinator.java:300)
at org.hibernate.persister.entity.mutation.DeleteCoordinator.coordinateDelete(DeleteCoordinator.java:87)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2867)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:131)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:606)
2023-08-30T09:35:26.906801047+02:00 at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
2023-08-30T09:35:26.906807420+02:00 at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:358)
2023-08-30T09:35:26.906813900+02:00 at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
2023-08-30T09:35:26.906820329+02:00 at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
2023-08-30T09:35:26.906832786+02:00 at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1412)
2023-08-30T09:35:26.906839187+02:00 at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:485)
2023-08-30T09:35:26.906845574+02:00 at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2301)
2023-08-30T09:35:26.906851874+02:00 at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:1966)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:439)
2023-08-30T09:35:26.906864606+02:00 at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.beforeCompletion(JtaTransactionCoordinatorImpl.java:336)
at org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47)
2023-08-30T09:35:26.906877791+02:00 at org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)
2023-08-30T09:35:26.906884098+02:00 at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.java:76)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:360)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:91)
at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162)
at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1295)
2023-08-30T09:35:26.906921505+02:00 at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:128)
2023-08-30T09:35:26.906929133+02:00 at io.quarkus.narayana.jta.runtime.NotifyingTransactionManager.commit(NotifyingTransactionManager.java:70)
2023-08-30T09:35:26.907007242+02:00 at org.keycloak.transaction.JtaTransactionWrapper.commit(JtaTransactionWrapper.java:90)
at org.keycloak.services.DefaultKeycloakTransactionManager.commit(DefaultKeycloakTransactionManager.java:136)
2023-08-30T09:35:26.907046884+02:00 at org.keycloak.services.DefaultKeycloakSession.closeTransactionManager(DefaultKeycloakSession.java:407)
2023-08-30T09:35:26.907061449+02:00 at org.keycloak.services.DefaultKeycloakSession.close(DefaultKeycloakSession.java:372)
2023-08-30T09:35:26.907081949+02:00 at org.keycloak.quarkus.runtime.transaction.TransactionalSessionHandler.close(TransactionalSessionHandler.java:56)
at org.keycloak.quarkus.runtime.integration.jaxrs.TransactionalResponseFilter.filter(TransactionalResponseFilter.java:48)
2023-08-30T09:35:26.907144683+02:00 at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:329)
2023-08-30T09:35:26.907155941+02:00 at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:243)
at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:100)
2023-08-30T09:35:26.907172239+02:00 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)
2023-08-30T09:35:26.907223528+02:00 at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154)
2023-08-30T09:35:26.907237010+02:00 at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321)
2023-08-30T09:35:26.907246066+02:00 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)
2023-08-30T09:35:26.907265424+02:00 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)
2023-08-30T09:35:26.907288254+02:00 at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
2023-08-30T09:35:26.907302823+02:00 at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
2023-08-30T09:35:26.907316462+02:00 at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:200)
at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:58)
2023-08-30T09:35:26.907347717+02:00 at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:36)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
2023-08-30T09:35:26.907362099+02:00 at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
2023-08-30T09:35:26.907368520+02:00 at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:200)
2023-08-30T09:35:26.907375185+02:00 at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$0(QuarkusRequestFilter.java:82)
2023-08-30T09:35:26.907381602+02:00 at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
2023-08-30T09:35:26.907390737+02:00 at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
2023-08-30T09:35:26.907410302+02:00 at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
2023-08-30T09:35:26.907424069+02:00 at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
2023-08-30T09:35:26.907454306+02:00 at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
2023-08-30T09:35:26.907468905+02:00 at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
2023-08-30T09:35:26.907484513+02:00 Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "user_entity" violates foreign key constraint "fk_c4fqv34p1mbylloxang7b1q3l" on table "user_role_mapping"
2023-08-30T09:35:26.907490814+02:00 Detail: Key (id)=(df2c5d55-5361-4b6a-85c7-42d624acc4c1) is still referenced from table "user_role_mapping".
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2713)
2023-08-30T09:35:26.907503696+02:00 at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2401)
2023-08-30T09:35:26.907545680+02:00 at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:368)
2023-08-30T09:35:26.907564595+02:00 at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:498)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:415)
2023-08-30T09:35:26.907590673+02:00 at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:190)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:152)
at jdk.internal.reflect.GeneratedMethodAccessor127.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.postgresql.ds.PGPooledConnection$StatementHandler.invoke(PGPooledConnection.java:441)
2023-08-30T09:35:26.907647045+02:00 at jdk.proxy2/jdk.proxy2.$Proxy93.executeUpdate(Unknown Source)
at io.agroal.pool.wrapper.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:88)
2023-08-30T09:35:26.907673292+02:00 at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:275)
... 64 more
2023-08-30T09:35:26.907686485+02:00
2023-08-30T09:35:26.908045499+02:00 2023-08-30 07:35:26,907 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-127) Uncaught server error: org.keycloak.models.ModelException: org.postgresql.util.PSQLException: ERROR: update or delete on table "user_entity" violates foreign key constraint "fk_c4fqv34p1mbylloxang7b1q3l" on table "user_role_mapping"
Detail: Key (id)=(df2c5d55-5361-4b6a-85c7-42d624acc4c1) is still referenced from table "user_role_mapping".
at org.keycloak.connections.jpa.PersistenceExceptionConverter.convert(PersistenceExceptionConverter.java:99)
at org.keycloak.connections.jpa.JpaExceptionConverter.convert(JpaExceptionConverter.java:33)
2023-08-30T09:35:26.908088993+02:00 at org.keycloak.transaction.JtaTransactionWrapper.lambda$handleException$0(JtaTransactionWrapper.java:65)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1779)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
2023-08-30T09:35:26.908135216+02:00 at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
2023-08-30T09:35:26.908142729+02:00 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.forEach(ReferencePipeline.java:596)
at org.keycloak.transaction.JtaTransactionWrapper.handleException(JtaTransactionWrapper.java:67)
at org.keycloak.transaction.JtaTransactionWrapper.commit(JtaTransactionWrapper.java:92)
2023-08-30T09:35:26.908180667+02:00 at org.keycloak.services.DefaultKeycloakTransactionManager.commit(DefaultKeycloakTransactionManager.java:136)
at org.keycloak.services.DefaultKeycloakSession.closeTransactionManager(DefaultKeycloakSession.java:407)
at org.keycloak.services.DefaultKeycloakSession.close(DefaultKeycloakSession.java:372)
at org.keycloak.quarkus.runtime.transaction.TransactionalSessionHandler.close(TransactionalSessionHandler.java:56)
at org.keycloak.quarkus.runtime.integration.jaxrs.TransactionalResponseFilter.filter(TransactionalResponseFilter.java:48)
2023-08-30T09:35:26.908212169+02:00 at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:329)
2023-08-30T09:35:26.908218676+02:00 at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:243)
2023-08-30T09:35:26.908224840+02:00 at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:100)
2023-08-30T09:35:26.908231177+02:00 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)
2023-08-30T09:35:26.908249803+02:00 at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240)
2023-08-30T09:35:26.908256127+02:00 at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154)
2023-08-30T09:35:26.908262423+02:00 at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321)
2023-08-30T09:35:26.908292255+02:00 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)
2023-08-30T09:35:26.908311775+02:00 at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:147)
2023-08-30T09:35:26.908318071+02:00 at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:84)
2023-08-30T09:35:26.908324394+02:00 at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:44)
2023-08-30T09:35:26.908331087+02:00 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.RoutingContextWrapper.next(RoutingContextWrapper.java:200)
at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:58)
2023-08-30T09:35:26.908396442+02:00 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)
2023-08-30T09:35:26.908422719+02:00 at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:200)
2023-08-30T09:35:26.908429966+02:00 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)
2023-08-30T09:35:26.908443252+02:00 at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
2023-08-30T09:35:26.908449809+02:00 at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
2023-08-30T09:35:26.908456034+02:00 at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
2023-08-30T09:35:26.908462350+02:00 at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
2023-08-30T09:35:26.908468669+02:00 at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
2023-08-30T09:35:26.908475370+02:00 at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "user_entity" violates foreign key constraint "fk_c4fqv34p1mbylloxang7b1q3l" on table "user_role_mapping"
2023-08-30T09:35:26.908488516+02:00 Detail: Key (id)=(df2c5d55-5361-4b6a-85c7-42d624acc4c1) is still referenced from table "user_role_mapping".
2023-08-30T09:35:26.908494729+02:00 at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2713)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2401)
2023-08-30T09:35:26.908511510+02:00 at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:368)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:498)
2023-08-30T09:35:26.908525196+02:00 at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:415)
2023-08-30T09:35:26.908531506+02:00 at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:190)
2023-08-30T09:35:26.908537825+02:00 at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:152)
2023-08-30T09:35:26.908544101+02:00 at jdk.internal.reflect.GeneratedMethodAccessor127.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2023-08-30T09:35:26.908557113+02:00 at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.postgresql.ds.PGPooledConnection$StatementHandler.invoke(PGPooledConnection.java:441)
2023-08-30T09:35:26.908569895+02:00 at jdk.proxy2/jdk.proxy2.$Proxy93.executeUpdate(Unknown Source)
at io.agroal.pool.wrapper.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:88)
2023-08-30T09:35:26.908582587+02:00 at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:275)
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:108)
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:40)
2023-08-30T09:35:26.908614467+02:00 at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:53)
2023-08-30T09:35:26.908620777+02:00 at org.hibernate.persister.entity.mutation.DeleteCoordinator.doStaticDelete(DeleteCoordinator.java:300)
2023-08-30T09:35:26.908627084+02:00 at org.hibernate.persister.entity.mutation.DeleteCoordinator.coordinateDelete(DeleteCoordinator.java:87)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2867)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:131)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:606)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:358)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
2023-08-30T09:35:26.908677110+02:00 at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1412)
2023-08-30T09:35:26.908683432+02:00 at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:485)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2301)
2023-08-30T09:35:26.908719397+02:00 at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:1966)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:439)
2023-08-30T09:35:26.908740284+02:00 at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.beforeCompletion(JtaTransactionCoordinatorImpl.java:336)
2023-08-30T09:35:26.908747329+02:00 at org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47)
2023-08-30T09:35:26.908753716+02:00 at org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)
2023-08-30T09:35:26.908759948+02:00 at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.java:76)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:360)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:91)
2023-08-30T09:35:26.908778714+02:00 at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162)
2023-08-30T09:35:26.908784937+02:00 at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1295)
2023-08-30T09:35:26.908791171+02:00 at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:128)
at io.quarkus.narayana.jta.runtime.NotifyingTransactionManager.commit(NotifyingTransactionManager.java:70)
2023-08-30T09:35:26.908831433+02:00 at org.keycloak.transaction.JtaTransactionWrapper.commit(JtaTransactionWrapper.java:90)
Hi @anarsultanov, I am having problems when I try to delete a created tenant. The error seems to be caused by the existing relationships between the tables, and when trying to delete a tenant it tells me that there are relationships with other tables on the record that I am trying to delete due to the foreign key constraint.
I attach an image where you can see the error it is giving me.
Do you know if I'm doing something wrong?
Thank you very much in advance
When calling /tenants/{tenant_id}/[memberships?search=email%40example.com keycloak returns HTTP 400 'unknown_error'
Without the search query the endpoints returns the values correctly.
Keycloak version : 23.0.6 - with MySQL
keycloak-multi-tenancy version : 23.1.0
This is more of a feature request. Is it possible to rename a tenant? Ideally this would be a PUT
endpoint on the API. This would be useful for users who did not know what the purpose of entering the tenant name and may want to change it in the future as they start adding other members.
Hello,
We are examining how your logic works.
I'd like to ask you a question.
There are two users:
If I try to obtain an access token on behalf of alice from the /token endpoint using Resource Owner Password Grant, it works as expected.
But when I try to obtain an access token on behalf of bob, it returns an error as shown below:
It works well when I try to log in using Authorization Code Grant.
Could you please let me know how I can obtain an access token for bob?
First off, thank you have having a swagger doc. It really helps with auto-generating client code to work with it. That being said. I have noticed some inconsistencies.
user
object in the response is not defined as a schema.There are others as well. I guess the ask is a review of the request payloads, response models, and status codes to ensure the API docs match the actual results.
When creating new resources through the API the response only contains http status 201 (Created)
I would like to suggest to add the new resource's ID to the response. When using the API in a chained process there is an extra call to Keycloak needed that in my opinion should not be necessary
Imagine the following scenario: (javascript)
const newTenantId = await kcClient.createTenant({ "name": "new Tenant" })
await someNewResourceCreationThatDependsOnTenantId({ tenantId: newTenantId })
This would be the preferred way to use the API but because the new Tenant ID is not present in the response we have to do an additional call to Keycloak to chain code that depends on the new tenantId
await kcClient.createTenant({ "name": "new Tenant" })
const tenantArray = await kcClient.getTenants({ first: 0, max: 10, string: "new Tenant" })
await someNewResourceCreationThatDependsOnTenantId({ tenantId: tenantArray[0].id })
When including the id in the response the calls to Keycloak gets reduces by 50%
When attempting to enable the creation of tenants in the authentication section of my Keycloak instance, I'm encountering an unknown error. This error prevents me from successfully configuring multi-tenancy for my application.
Steps followed to enable Create tenant:
I expect to be able to enable the creation of tenants without encountering any errors. This would allow me to configure multi-tenancy for my application as needed. However, an unknown error is displayed when attempting to enable the creation of tenants. This prevents me from proceeding with the multi-tenancy configuration.
I am using keycloak version 22.0.1
I would greatly appreciate any assistance in resolving this issue. If there's any further information required from my side, please let me know.
Thank you for your help!
Hello, on https://github.com/anarsultanov/keycloak-multi-tenancy/blob/main/src/main/resources/META-INF/keycloak-multi-tenancy-changelog-20221217-2113.xml the ids REALM_ID, USER_ID, TENANT_ID are varchar(255) on line 14, 26 and 29. They should be 36. Indeed, when start on sql server it break everything and the entiry keycloack doesn't start. I fixed in my pc, i cannot push a branch or a suggestion on your repo so i write here. Also the plugin you deployed are broken with sql server. i suggest to fix.
Kind Regards
Paolo
Hello,
I have CORS issue when trying to call the APIs from my local frontend app
while it is perfectly working with kcadm commands or directly with postman using the same user/brearer. I can't understand why it is not working directly inside my angular app (simple http get query with the bearer header)
I suspected something wrong with the "Web origins" config inside my client, because when I remove the host header in postman I got the same error
I tried multiple value in the "Web origins" config without success.
I even tried with the realm "multi-tenant" json on the test resources but got the same error.
Sorry, I may have missed something but can't figure out why I can't reach your endpoints. Have you any idea ?
Currently, the POST endpoint for creating a tenant doesn't have specific restrictions. This setup could potentially allow any user with API access to create new tenants.
Suggested Enhancement:
I propose implementing a role-based access control for the tenant creation endpoint. This would align with how Keycloak handles API management in general. In my current setup, I issue API tokens to my customers by creating a Keycloak client with a service account, using a predefined Keycloak client (named api-cli). This client is not allowed to interact with the Keycloak API unless I assign a service account role of realm-management - manage-clients
.
Proposed Implementation:
For the tenancy API, I suggest a similar approach where a service account role (e.g., realm-management - manage-tenants
) is required to manage tenant creation. This role would only be assigned to my predefined api-cli client. By doing so, it ensures that API tokens held by my customers cannot create tenants unless I explicitly add this role to their service account, which I intend not to do. In my application, creating a new tenant is a paid feature, and this change would add an extra layer of control and security.
Additional Consideration:
This suggestion needs some careful thought, especially in relation to the feature where users are forced to create a tenant if not a member of one. I have this feature disabled in my application, but the proposed enhancement should ideally be compatible with both scenarios.
Thank you for considering this enhancement. I believe it would be a valuable addition to the API.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
org.apache.maven.plugins:maven-shade-plugin
, org.apache.maven.plugins:maven-compiler-plugin
, com.github.dasniko:testcontainers-keycloak
, org.testcontainers:junit-jupiter
, com.microsoft.playwright:playwright
, org.projectlombok:lombok
, org.keycloak:keycloak-admin-client
, org.keycloak:keycloak-model-jpa
, org.keycloak:keycloak-services
, org.keycloak:keycloak-server-spi-private
, org.keycloak:keycloak-server-spi
).github/workflows/codeql.yml
actions/setup-java v4
actions/checkout v4
github/codeql-action v3
github/codeql-action v3
github/codeql-action v3
.github/workflows/release.yml
actions/checkout v4
actions/setup-java v4
codacy/git-version 2.8.0
mikepenz/release-changelog-builder-action v4
actions/upload-artifact v4
stefanzweifel/git-auto-commit-action v5
softprops/action-gh-release v1
.github/workflows/stale.yml
actions/stale v9
pom.xml
org.keycloak:keycloak-server-spi 24.0.1
org.keycloak:keycloak-server-spi-private 24.0.1
org.keycloak:keycloak-services 24.0.1
org.keycloak:keycloak-model-jpa 24.0.1
org.keycloak:keycloak-admin-client 24.0.1
org.projectlombok:lombok 1.18.30
io.smallrye:smallrye-open-api-jaxrs 3.10.0
com.microsoft.playwright:playwright 1.41.2
org.junit.jupiter:junit-jupiter 5.10.2
org.assertj:assertj-core 3.25.3
org.testcontainers:junit-jupiter 1.19.6
com.github.dasniko:testcontainers-keycloak 3.2.0
com.github.javafaker:javafaker 1.0.2
org.apache.maven.plugins:maven-compiler-plugin 3.12.1
org.apache.maven.plugins:maven-shade-plugin 3.5.2
org.apache.maven.plugins:maven-surefire-plugin 3.2.5
me.fabriciorby:maven-surefire-junit5-tree-reporter 1.2.1
org.apache.maven.plugins:maven-failsafe-plugin 3.2.5
me.fabriciorby:maven-surefire-junit5-tree-reporter 1.2.1
io.smallrye:smallrye-open-api-maven-plugin 3.10.0
org.codehaus.mojo:versions-maven-plugin 2.16.2
Hello, I am planning to implement Keycloak in a project and I would like to have different password policies defined for each tenant, does this extension allow me to do it?
Thank you so much for your attention.
Encountered a ModelDuplicateException when issuing a tenant invitation due to non-unique email addresses because the setting "Duplicate Emails" is enabled. Error message received:
Caused by: org.keycloak.models.ModelDuplicateException: Multiple users with email '[email protected]' exist in Keycloak.
Replace the reliance on unique email addresses for user identification with subject identifiers (sub token claim). This would resolve issues arising from shared email addresses and align better with OIDC standards. Additionally, suggest incorporating actionTokens to enable invite distribution through various transports, including SMS.
Reliability: Subject identifiers provide a more reliable and unique method for user identification.
Flexibility: Accommodates scenarios where multiple users share the same email address and account linking disabled/enabled.
Transport Flexibility: ActionTokens enable sending invites via alternative methods, such as SMS, broadening the scope of user outreach.
OIDC Alignment: Better conforms to OIDC practices by utilizing standard token claims for identification.
I appreciate your feedback on this suggestion, particularly regarding the feasibility and implications of integrating actionTokens in this context. This should allow OIDC logins where email is not registered
I just want to verify the right setup of the sub-flows when using IdpTenantMembershipsCreatingAuthenticator
. Should it be added as 1st flow in first broker login
or I should create a new one that only using the authenticator? My usecase is to bypass the Review profile flow but I also have to customize the username that will be created in Keycloak without using from the IDP token. Thank you.
Based on your readme file,
"To configure an IDP as tenant-specific, tenants' IDs should be added to the multi-tenancy.tenants configuration attribute of the IDP as a comma-separated list. This can be achieved using the standard Keycloak REST API."
I'm trying to figure out how to link tenant to IDP.
I successfully created 2 tenants by consuming {{keycloakUrl}}/auth/realms/{{realmName}}/tenants endpoint.
Then, I create new user, use the user email to for invitation for on of the client. From what I can see, the user will able to view the invitation when they login to Keycloak. Is there any way the user can view the invitation? like received an email?
I also created a Microsoftt IDP.
I'm strugling to to link created tenant to an IDP based on the description above. Can you please specify which endpoint from the Keycloak Rest API to use for this purpose and example of the payload?
Hi, first of all thank you for the extension.
I've been trying to use the API but it always returns 401 Unauthorized no matter what I try.
I'm sure it's a mistake on my side, here's the request I do on Postman:
GET http://{keycloak_host}/realms/{realm}/tenants
Authorization: Basic user:pass
or with body
GET http://{keycloak_host}/realms/{realm}/tenants
x-www-form-encoded
username=user
password=pass
I've been utilizing Keycloak for managing multi-tenancy in my platform, and while it has been an excellent tool, I've noticed a usability issue regarding the default terminology used for tenant management. Specifically, the term "Tenant" might not align with the language and context of all user bases.
Many platforms, including mine, use alternative terminology such as "Organization" to refer to what Keycloak terms as "Tenant." This inconsistency in language can lead to confusion among users, particularly during account creation or when selecting which "Tenant" to log into.
To enhance user experience and streamline the integration of Keycloak into various platforms, I propose the addition of an environment variable that allows developers to customize the term used for multi-tenancy. This would enable us to align Keycloak's language with the terminology utilized within our respective platforms.
I envision this feature as a simple configuration option, perhaps in the form of an environment variable like KEYCLOAK_MULTI_TENANCY_TERM, where developers can specify their preferred term (e.g., "Organization", "Workspace", etc.).
By providing this customization option, Keycloak can better accommodate diverse user bases and integrate seamlessly into a wider range of platforms. This enhancement would ultimately contribute to a more intuitive and user-friendly experience for all Keycloak users.
Thank you for considering my suggestion. I believe that implementing this feature would significantly improve the usability and flexibility of Keycloak in multi-tenant environments. I'm happy to provide further clarification or assistance as needed.
Hi. Great project! I would like to change the link sent to invited users. How is this done?
Right now it points to: ${keycloak_url}/auth/realms/${realm}/account
I need it to point to my application.
My app will redirect the user to login and/or show a message before login.
After login the invite confirmation is displayed to the user (if the user logged in with an account with the same email. I only use IDPs)
One additional feature request would be to use a action token instead of matching the email to validate if invite should be displayed to the user. Example:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.