Getting error for custom JPA provider

Hi team , I’m getting following error for custom JPA provider when trying to hit through custom rest endpoints on Keycloak 18.0.0 quarkus . ‘IDPConfigs’ is the custom entity I created
An exception occurred java.lang.IllegalArgumentException: Unknown entity: org.keycloak.persistence.identityManagerJPA.jpa.IDPConfigs

Can anyone help me resolve this. This is kind of blocker for us migrating to Quarkus

Thanks

Without more information on your setup, it will be impossible to help you debug. A few questions:

Can you show us your implementation of JpaEntityProviderFactory and JpaEntityProvider so we can see how you are loading your IDPConfigs entity?

Do your Quarkus startup logs show that the factory is getting loaded, and that your Liquibase changelog is getting run?

Do you see the provider ID in your server-info page of the Admin UI?

Are you using a persistence.xml file with the Quarkus version? I had some similar problems when upgrading from Wildfly to Quarkus, and found that the persistence.xml was the problem and could be removed.

Anyway, the more information you provide, the more likely we’ll be able to help.

Hello @xgp, thanks for your reply. Yes I can see Provider ID in server-info page and liquibase also ran which created the new tables in DB. I dont have any persistent.xml file.

The custom entity itself is not getting recognised when I call create entity from custom rest enpoints. following is full stack trace

2022-04-29 11:45:57,304 ERROR [org.keycloak.services] (executor-thread-3) An exception occurred java.lang.IllegalArgumentException: Unknown entity: org.keycloak.persistence.identityManagerJPA.jpa.IDPConfigs
keycloak | 2022-04-29 11:45:57,316 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-3) Uncaught server error: java.lang.IllegalArgumentException: RESTEASY003715: path was null
keycloak | at org.jboss.resteasy.specimpl.ResteasyUriBuilderImpl.path(ResteasyUriBuilderImpl.java:382)
keycloak | at org.keycloak.persistence.identityManagerJPA.rest.IDPConfigsResource.createIDPConfigs(IDPConfigsResource.java:52)
keycloak | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
keycloak | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
keycloak | at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
keycloak | at java.base/java.lang.reflect.Method.invoke(Method.java:566)
keycloak | at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
keycloak | at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
keycloak | at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
keycloak | at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
keycloak | at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
keycloak | at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
keycloak | at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
keycloak | at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
keycloak | at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
keycloak | at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)
keycloak | at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)
keycloak | at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
keycloak | at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
keycloak | at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
keycloak | at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
keycloak | at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
keycloak | at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
keycloak | at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
keycloak | at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
keycloak | at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
keycloak | at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
keycloak | at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
keycloak | at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
keycloak | at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak | at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak | at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak | at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
keycloak | at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
keycloak | at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak | at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak | at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak | at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
keycloak | at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
keycloak | at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak | at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak | at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak | at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:71)
keycloak | at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
keycloak | at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
keycloak | at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
keycloak | at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
keycloak | at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
keycloak | at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
keycloak | at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
keycloak | at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
keycloak | at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
keycloak | at java.base/java.lang.Thread.run(Thread.java:829)

This error I’m getting even for domain-extension provider.

@xgp @prachi.pachankar Did you find any resolution for this problem? I am getting below error for my custom JPA provider.

java.lang.IllegalArgumentException: No query defined for that name [findByTenantId].

Everything was working fine in wildfly but since I migrated to Quarkus my custom provider stopped working with above error.

I don’t have another idea, but I’ve got an example up of a project with a custom JPA entity provider that works with Keycloak v18.0.0:

The JpaEntityProviderFactory: keycloak-orgs/OrganizationEntityProviderFactory.java at main · p2-inc/keycloak-orgs · GitHub

The JpaEntityProvider: keycloak-orgs/OrganizationEntityProvider.java at main · p2-inc/keycloak-orgs · GitHub

The Dependencies entry in the jar manifest: keycloak-orgs/pom.xml at main · p2-inc/keycloak-orgs · GitHub

The Liquibase changelogs: keycloak-orgs/src/main/resources/META-INF at main · p2-inc/keycloak-orgs · GitHub

@xgp Thanks for the quick reply. In the class keycloak-orgs/OrganizationEntityProvider.java at main · p2-inc/keycloak-orgs · GitHub you have comment where you mentioned to also add entity classes in persistence.xml file. But I didn’t find this file in your source code. Is it not needed anymore?

Yes @saguntumkar I was getting the same error and just to unblock and test further I changed my named queries native queries which worked. But the problem here is the custom entity itself is not getting recognised due to which named queries are not getting identified. It’s even failing for HQL queries.
@xgp Can you let me know how did you integrate your custom JPA jar in keycloak. As mentioned in doc, it’s just copying the jar in providers folder right in keycloak 18? or any extra configurations need to be done. Also, you mentioned about not having persistence.xml file right?

That comment is specific to the legacy/Wildfly version, and I found that it is not needed anymore after the Quarkus change.

@prachi.pachankar would you be able to share the code example for native query? Thanks in advance.

@xgp I have added exact same code as yours. There are only few differences in pom.xml file but that should not result in the error I am getting (Not able to load the entity). Do you think anything I might be missing?

@prachi.pachankar Thanks for the suggestion on using native query. It’s a pain though to change the entire code to use native queries :slightly_frowning_face:. I also posted this error on keycloak-dev email group but no one answered. I am really surprised how come no one asked this question. Is there something we are doing wrong in our setup? I was just hoping it should work how it was working in old setup.

What are the differences?

Hi @saguntumkar, Yes its painful to change all the named queries to native one … i just changed few to unblock myself and test other functionalities with the migration. Even I wonder the why no body posted the question and wanted to know if I’m missing any extra configurations to be done for custom SPI in quarkus as everything worked smoothly in wildfly/legacy versions. I could see provider Id in the server info list… new tables got created in the DB then what’s wrong with custom entity not getting recognized. Can someone please help in this. In keycloak example as well, I could see the documentation has the old references or setup guide :frowning:

I have not added org.codehaus.mojo, com.fizzed, com.spotify.fmt plugins and also the scm tag

<scm>
<url>GitHub - p2-inc/keycloak-orgs: Single realm, multi-tenancy for SaaS apps</url>
<connection>scm:git:git@github.com:p2-inc/keycloak-orgs.git</connection>
</scm>

Same with my setup. All changelogs ran fine and DB table got created successfully. I will keep you posted if I find any solution. Please let me also know if you find any.

Hi @saguntumkar , did you find any solution for the issue?

@prachi.pachankar Not really. I ended up doing it using native queries approach. I got one example here keycloak-quickstarts/user-storage-jpa at main · keycloak/keycloak-quickstarts · GitHub where keycloak dev team member implemented user storage jpa. But somehow I was not able to get it working. In this example, he created separate user store (new data source) and wrote this provider to connect to that store. In my case I wanted to use same default data source as keycloak. Please let me know if you get this working.

I am also using the same keycloak data source

Same issue here. Apparently this is a known Keycloak issue with Quarkus.

Is this problem reported and plannned to be fixed in next Keycloak version? I only found this: Update custom provider examples in source to KC 17.x · Issue #10293 · keycloak/keycloak · GitHub

@xgp Hi team, I’m new to Keycloak and I want to extend the Keycloak to create custom rest endpoint to get user credentials ( TOTPsecret data) so I can retrieve credentials at any time. Do you have any suggestion how to implement that , what spi do I need to implement or interfaces I need to use. From the api documentaton of Keycloak, there are some possible interface such as CredentialModel which then I can use method getValue or TOTPCredentialModel which I can get value secret data. But how the things works? I mean do you have a flow which one instance that keycloak will create for us once and when it is created? I see somethingProviderFactory will create only once then somethingProvider will created on demand