Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

quarkus-keycloak-admin-client throws UnrecognizedPropertyException using Keycloak 20.0.0 and native image while getting ServerInfo #29035

Closed
SailReal opened this issue Nov 3, 2022 · 22 comments · Fixed by #29076
Labels
Milestone

Comments

@SailReal
Copy link

SailReal commented Nov 3, 2022

Describe the bug

Using quarkus-keycloak-admin-client a Keycloak.getInstance(url, realm, username, password, clientId).serverInfo().getInfo().getSystemInfo().getVersion(); fails using Quarkus version 2.13.3.Final and Keycloak 20.0.0 using a native image due to a UnrecognizedPropertyException of field cryptoInfo.

Expected behavior

quarkus-keycloak-admin-client can be used together with Keycloak 20.0.0 and a native image to retrieve the system info as it works with a normal image.

Actual behavior

Exception handling request b741ed7e-5e13-4805-86ff-cec77c00cdc3-1 to /api/version: org.jboss.resteasy.spi.UnhandledException: javax.ws.rs.client.ResponseProcessingException: javax.ws.rs.ProcessingException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "cryptoInfo" (class org.keycloak.representations.info.ServerInfoRepresentation), not marked as ignorable (14 known properties: "protocolMapperTypes", "providers", "identityProviders", "themes", "passwordPolicies", "clientInstallations", "memoryInfo", "enums", "socialProviders", "clientImporters", "profileInfo", "componentTypes", "systemInfo", "builtinProtocolMappers"])
  at [Source: (org.jboss.resteasy.specimpl.AbstractBuiltResponse$InputStreamWrapper); line: 1, column: 1242] (through reference chain: org.keycloak.representations.info.ServerInfoRepresentation["cryptoInfo"])
 	at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:105)
 	at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:359)
 	at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218)
 	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
 	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 org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249)
 	at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:60)
 	at io.quarkus.resteasy.runtime.ResteasyServlet.service(ResteasyServlet.java:19)
 	at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55)
 	at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
 	at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
 	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:63)
 	at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
 	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
 	at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:67)
 	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:133)
 	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
 	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
 	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
 	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65)
 	at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
 	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
 	at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
 	at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
 	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
 	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
 	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:247)
 	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:56)
 	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:111)
 	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:108)
 	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
 	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
 	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$9$1.call(UndertowDeploymentRecorder.java:595)
 	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227)
 	at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:152)
 	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$1.handleRequest(UndertowDeploymentRecorder.java:120)
 	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:284)
 	at io.undertow.server.DefaultExchangeHandler.handle(DefaultExchangeHandler.java:18)
 	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$5$1.run(UndertowDeploymentRecorder.java:417)
 	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
 	at java.util.concurrent.FutureTask.run(FutureTask.java:264)
 	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:564)
 	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
 	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
 	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.lang.Thread.run(Thread.java:833)
 	at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:705)
 	at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202)
 Caused by: javax.ws.rs.client.ResponseProcessingException: javax.ws.rs.ProcessingException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "cryptoInfo" (class org.keycloak.representations.info.ServerInfoRepresentation), not marked as ignorable (14 known properties: "protocolMapperTypes", "providers", "identityProviders", "themes", "passwordPolicies", "clientInstallations", "memoryInfo", "enums", "socialProviders", "clientImporters", "profileInfo", "componentTypes", "systemInfo", "builtinProtocolMappers"])
  at [Source: (org.jboss.resteasy.specimpl.AbstractBuiltResponse$InputStreamWrapper); line: 1, column: 1242] (through reference chain: org.keycloak.representations.info.ServerInfoRepresentation["cryptoInfo"])
 	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:203)
 	at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:64)
 	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:154)
 	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:115)
 	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76)
 	at jdk.proxy4.$Proxy150.getInfo(Unknown Source)
 	at org.cryptomator.hub.api.VersionResource.getVersion(VersionResource.java:31)
 	at java.lang.reflect.Method.invoke(Method.java:568)
 	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.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:408)
 	at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:69)
 	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
 	... 50 more
 Caused by: javax.ws.rs.ProcessingException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "cryptoInfo" (class org.keycloak.representations.info.ServerInfoRepresentation), not marked as ignorable (14 known properties: "protocolMapperTypes", "providers", "identityProviders", "themes", "passwordPolicies", "clientInstallations", "memoryInfo", "enums", "socialProviders", "clientImporters", "profileInfo", "componentTypes", "systemInfo", "builtinProtocolMappers"])
  at [Source: (org.jboss.resteasy.specimpl.AbstractBuiltResponse$InputStreamWrapper); line: 1, column: 1242] (through reference chain: org.keycloak.representations.info.ServerInfoRepresentation["cryptoInfo"])
 	at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:254)
 	at org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:90)
 	at org.jboss.resteasy.specimpl.AbstractBuiltResponse.readEntity(AbstractBuiltResponse.java:256)
 	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:167)
 	... 68 more
 Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "cryptoInfo" (class org.keycloak.representations.info.ServerInfoRepresentation), not marked as ignorable (14 known properties: "protocolMapperTypes", "providers", "identityProviders", "themes", "passwordPolicies", "clientInstallations", "memoryInfo", "enums", "socialProviders", "clientImporters", "profileInfo", "componentTypes", "systemInfo", "builtinProtocolMappers"])
  at [Source: (org.jboss.resteasy.specimpl.AbstractBuiltResponse$InputStreamWrapper); line: 1, column: 1242] (through reference chain: org.keycloak.representations.info.ServerInfoRepresentation["cryptoInfo"])
 	at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:1127)
 	at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:2036)
 	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1700)
 	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1678)
 	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:320)
 	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
 	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323)
 	at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:2025)
 	at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1175)
 	at org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider.readFrom(ResteasyJackson2Provider.java:193)
 	at org.jboss.resteasy.core.interception.jaxrs.AbstractReaderInterceptorContext.readFrom(AbstractReaderInterceptorContext.java:101)
 	at org.jboss.resteasy.core.interception.jaxrs.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:80)
 	at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:217)
 	... 71 more

How to Reproduce?

Output of uname -a or ver

No response

Output of java -version

No response

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.13.0.Final and 2.13.3.Final

Build tool (ie. output of mvnw --version or gradlew --version)

mvn clean package -Pnative -Dquarkus.container-image.build=true -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel:22.2-java17 -Dquarkus.container-image.tag=1.0.0-amd64

Additional information

While debugging, we found out that

"cryptoInfo":{"cryptoProvider":"DefaultCryptoProvider","supportedKeystoreTypes":["JKS","PKCS12","BCFKS"]}

is now in the response from Keycloak 20.0.0 but wasn't in 19.x . In the normal image quarkus-keycloak-admin-client doesn't have a problem that this property was added but the native image does.

Here is the full response of the SystemInfoResponse.json using Keycloak 20.0.0. And here is the repsonse of the SystemInfoResponse_KC_19_0_3.txt using Keycloak 19.0.3 without this cryptoInfo which works as expected.

@SailReal SailReal added the kind/bug Something isn't working label Nov 3, 2022
@quarkus-bot
Copy link

quarkus-bot bot commented Nov 3, 2022

/cc @Karm, @galderz, @pedroigor, @sberyozkin, @zakkak

@SailReal SailReal changed the title quarkus-keycloak-admin-client throws UnrecognizedPropertyException using Keycloak 20.0.0 and native image while getting ServerInfo quarkus-keycloak-admin-client throws UnrecognizedPropertyException using Keycloak 20.0.0 and native image while getting ServerInfo Nov 3, 2022
@sberyozkin
Copy link
Member

sberyozkin commented Nov 3, 2022

We haven't worked on upgrading to KC 20.0.0 yet, so it is not really a bug, KC 19.0.3 clients are not expected to be forward compatible with higher versions of Keycloak

@sberyozkin
Copy link
Member

Ignore my message please, it is a response from KC 20 which causes the problem

In the normal image quarkus-keycloak-admin-client doesn't have a problem that this property was added but the native image does.

@sberyozkin
Copy link
Member

@michalvavrik Hi Michal, do you recall why we have both of

<dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-rest-client-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-rest-client-jaxb</artifactId>
        </dependency>

@SailReal Can you please try quarkus-keycloak-admin-client-reactive ?

@michalvavrik
Copy link
Member

@sberyozkin AFAICT @gsmet added it.

@michalvavrik
Copy link
Member

btw @sberyozkin I can have a look, but I bet you're already on it.

@sberyozkin
Copy link
Member

Thanks, I guess the jaxb one is not relevant in this case though...

I see #25984 as possibly being related as it only does not work in native image, CC @zakkak just in case

@sberyozkin
Copy link
Member

@michalvavrik I'm not really on it yet, as I have a few PRs to look at. I think it is a general Jackson native issue at this point

@michalvavrik
Copy link
Member

Okay, let me check.

@zakkak
Copy link
Contributor

zakkak commented Nov 3, 2022

I see #25984 as possibly being related as it only does not work in native image, CC @zakkak just in case

Yes, it looks like a reflection registration issue. @michalvavrik Please let me know if you need any help.

@SailReal
Copy link
Author

SailReal commented Nov 3, 2022

@SailReal Can you please try quarkus-keycloak-admin-client-reactive ?

@sberyozkin Yes, I'll check it and report back, takes some seconds to build 😅

@SailReal
Copy link
Author

SailReal commented Nov 3, 2022

@sberyozkin Yes, I'll check it and report back, takes some seconds to build 😅

quarkus-keycloak-admin-client-reactive doesn't show this problem using the native image.

@sberyozkin
Copy link
Member

Thanks @SailReal, looks like quarkus-rest-client-jackson does not have a fix which is available in quarkus-rest-client-jackson-reactive which is what quarkus-keycloak-admin-client-reactive depends upon...

@michalvavrik
Copy link
Member

I don't agree with @sberyozkin, IMHO nothing to fix. Our Keycloak admin client is using org.keycloak... with version 19.0.3 and these are classes to which response from 20.0.0 is mapped. Only reason why it works for quarkus-keycloak-admin-client-reactive is different Jackson setup in here io.quarkus.keycloak.admin.client.reactive.runtime.ResteasyReactiveClientProvider#registerJacksonProviders, while quarkus-keycloak-admin-client is using default Keycloak client provider. If you want to relax Jackson setup, you can always set org.keycloak.admin.client.Keycloak#setClientProvider. I bet you can do it in couple minutes (use @Observer StartupEvent....).

If you change BOM Keycloak version to 20.0.0 and build quarkus-keycloak-admin-client, everything works as expected - our set up is correct.

One else thing, just because quarkus-keycloak-admin-client-reactive doesn't throw exceptions, it doesn't mean it works correctly. In fact, you are mapping responses to different DTOs and only someone who actually did changes in code between 19.0.3 and 20.0.0 can tell you if there has been changes that will affect your use case. I'd suggest not to use reactive client as fix!

@sberyozkin
Copy link
Member

sberyozkin commented Nov 3, 2022

@michalvavrik Why would we want users mess with setting up Jackson just so that a JSON response containing a few unknown properties can be accepted ? This is just a basic interop concept, don't fail if some unknown properties in the response are available...

Only reason why it works for quarkus-keycloak-admin-client-reactive is different Jackson setup in here io.quarkus.keycloak.admin.client.reactive.runtime.ResteasyReactiveClientProvider#registerJacksonProviders, while quarkus-keycloak-admin-client is using default Keycloak client provider. If you want to relax Jackson setup, you can always set org.keycloak.admin.client.Keycloak#setClientProvider. I bet you can do it in couple minutes (use @observer StartupEvent....).

Why can't we have the right provider set for the non-reactive version as well ?

One else thing, just because quarkus-keycloak-admin-client-reactive doesn't throw exceptions, it doesn't mean it works correctly.

Does it not work correctly in the user reproducer ?

@sberyozkin
Copy link
Member

sberyozkin commented Nov 3, 2022

Michal, IMHO we should move https://github.com/quarkusio/quarkus/blob/main/extensions/keycloak-admin-client-reactive/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java into the existing common module (and I guess replacing Reactive with Jackson) and just use the same provider, that would offer a consistent and better user experience, do you agree with it ?

thanks

@sberyozkin
Copy link
Member

Or at least most of it as the abstract class as I see io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyWriter; there

@michalvavrik
Copy link
Member

Michal, IMHO we should move https://github.com/quarkusio/quarkus/blob/main/extensions/keycloak-admin-client-reactive/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java into the existing common module (and I guess replacing Reactive with Jackson) and just use the same provider, that would offer a consistent and better user experience, do you agree with it ?

I agree it's inconsistent, but apart of com.fasterxml.jackson.databind.ObjectMapper, the code can't be re-used

import org.jboss.resteasy.reactive.client.impl.ClientBuilderImpl;
import org.jboss.resteasy.reactive.client.impl.WebTargetImpl;
import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader;
import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyWriter;

Keycloak default version is using org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider and that should pick up ObjectMapper from io.quarkus.resteasy.common.runtime.jackson.QuarkusObjectMapperContextResolver and thus behavior should be same as in reactive according to this https://quarkus.io/guides/resteasy#jackson (missing properties ignored) as by default quarkus.jackson.fail-on-unknown-properties is set to false.

That said, I created my reproducer as I don't know cryptomator/hub and I'm not comfortable to run so much code and scripts I didn't properly inspect. Now I understand why my reproducer failed (KeycloakLifecycleManager don't run inside Quarkus app). It's worth exploring why it doesn't work for @SailReal , but having standalone reproducer would make things easier. I'm busy in next few days.

@michalvavrik
Copy link
Member

michalvavrik commented Nov 4, 2022

Just to check, @SailReal do you use quarkus-keycloak-admin-client together with quarkus-resteasy-jackson? that shouldn't be necessary, sorry.

@michalvavrik
Copy link
Member

Okay, now I reproduced it inside Quarkus app with my reproducer, I'll check next week why we don't use provided mapper.

@SailReal
Copy link
Author

SailReal commented Nov 4, 2022

If I can do something to help please let me know.

@sberyozkin
Copy link
Member

Thanks Michal @michalvavrik, looks like an interesting problem to explore but not urgent IMHO; we do recommend users to use reactive equivalents which works in this case. But it can be useful to see how to control Jackson better in the legacy scenarios as well, thanks.

@gsmet gsmet modified the milestones: 2.15 - main, 2.14.1.Final Nov 10, 2022
gsmet pushed a commit to gsmet/quarkus that referenced this issue Nov 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
5 participants