Skip to content

Smallrye JWT isn't compatible with native image #3496

@aesteve

Description

@aesteve

Describe the bug
Securing APIs through the smallrye-jwt extension works fine in dev mode (and I'm guessing jar mode is OK too) but fails with an exception when used in a native image.

Expected behavior
It should work the same way in native mode than in dev mode, and not fail with an exception

Actual behavior

2019-08-13 07:47:06,443 ERROR [io.und.req.io] (executor-thread-1) Exception handling request 73085ca2-c294-444a-b71d-e616a31e0e73-1 to <<<endpoint>>>>: java.lang.UnsatisfiedLinkError: sun.security.ec.ECKeyPairGenerator.isCurveSupported([B)Z [symbol: Java_sun_security_ec_ECKeyPairGenerator_isCurveSupported or Java_sun_security_ec_ECKeyPairGenerator_isCurveSupported___3B]
	at com.oracle.svm.jni.access.JNINativeLinkage.getOrFindEntryPoint(JNINativeLinkage.java:145)
	at com.oracle.svm.jni.JNIGeneratedMethodSupport.nativeCallAddress(JNIGeneratedMethodSupport.java:57)
	at sun.security.ec.ECKeyPairGenerator.isCurveSupported(ECKeyPairGenerator.java)
	at sun.security.ec.ECKeyPairGenerator.ensureCurveIsSupported(ECKeyPairGenerator.java:135)
	at sun.security.ec.ECKeyPairGenerator.initialize(ECKeyPairGenerator.java:114)
	at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:674)
	at sun.security.ssl.ECDHCrypt.<init>(ECDHCrypt.java:77)
	at sun.security.ssl.ClientHandshaker.serverKeyExchange(ClientHandshaker.java:783)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:302)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
	at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1564)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
	at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:347)
	at org.jose4j.http.Get.get(Get.java:80)
	at org.jose4j.jwk.HttpsJwks.refresh(HttpsJwks.java:204)
	at org.jose4j.jwk.HttpsJwks.getJsonWebKeys(HttpsJwks.java:161)
	at io.smallrye.jwt.auth.principal.KeyLocationResolver.tryAsJWK(KeyLocationResolver.java:116)
	at io.smallrye.jwt.auth.principal.KeyLocationResolver.resolveKey(KeyLocationResolver.java:80)
	at org.jose4j.jwt.consumer.JwtConsumer.processContext(JwtConsumer.java:213)
	at org.jose4j.jwt.consumer.JwtConsumer.process(JwtConsumer.java:433)
	at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parse(DefaultJWTTokenParser.java:87)
	at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator.validateClaimsSet(MpJwtValidator.java:41)
	at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator.validate(MpJwtValidator.java:35)
	at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator_ClientProxy.validate(MpJwtValidator_ClientProxy.zig:164)
	at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.validateToken(TokenSecurityRealm.java:207)
	at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.getClaims(TokenSecurityRealm.java:195)
	at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.exists(TokenSecurityRealm.java:157)
	at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.getEvidenceVerifySupport(TokenSecurityRealm.java:186)
	at org.wildfly.security.auth.server.ServerAuthenticationContext$UnassignedState.verifyEvidence(ServerAuthenticationContext.java:1659)
	at org.wildfly.security.auth.server.ServerAuthenticationContext$InactiveState.verifyEvidence(ServerAuthenticationContext.java:1391)
	at org.wildfly.security.auth.server.ServerAuthenticationContext.verifyEvidence(ServerAuthenticationContext.java:759)
	at org.wildfly.security.auth.server.SecurityDomain.authenticate(SecurityDomain.java:309)
	at org.wildfly.security.auth.server.SecurityDomain.authenticate(SecurityDomain.java:270)
	at io.quarkus.smallrye.jwt.runtime.auth.JwtIdentityManager.verify(JwtIdentityManager.java:36)
	at io.quarkus.smallrye.jwt.runtime.auth.JWTAuthMechanism.authenticate(JWTAuthMechanism.java:53)
	at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:245)
	at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:268)
	at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.access$100(SecurityContextImpl.java:231)
	at io.undertow.security.impl.SecurityContextImpl.attemptAuthentication(SecurityContextImpl.java:125)
	at io.undertow.security.impl.SecurityContextImpl.authTransition(SecurityContextImpl.java:99)
	at io.undertow.security.impl.SecurityContextImpl.authenticate(SecurityContextImpl.java:92)
	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:55)
	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:64)
	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.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:292)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
	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$8$1$1.call(UndertowDeploymentRecorder.java:489)
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:364)
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
	at java.lang.Thread.run(Thread.java:748)
	at org.jboss.threads.JBossThread.run(JBossThread.java:479)
	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)

To Reproduce
Steps to reproduce the behavior:
Follow the tutorial and build a native image.
Then execute it and try to access any secured endpoint. You'll get the stacktrace above.

Configuration

# HTTP Server config
quarkus.http.port=9090
# DataSource
# Hibernate
quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL95Dialect
#quarkus.hibernate-orm.log.sql=true
# OpenAPI / Swagger
quarkus.smallrye-openapi.path=/swagger
quarkus.swagger-ui.always-include=true
quarkus.swagger-ui.path=/swagger-ui
# JWT / Security
## Issuer
%dev.mp.jwt.verify.issuer=#hidden
%preproduction.mp.jwt.verify.issuer=#hidden
%production.mp.jwt.verify.issuer=#hidden
## Public Key
%dev.mp.jwt.verify.publickey.location=https://com.company/JWKS
%preproduction.mp.jwt.verify.publickey.location=https://com.company/JWKS
%production.mp.jwt.verify.publickey.location=https://com.company/JWKS

Basically the same as in the tutorial, but adapted to a real-life use-case I'm not able to share.

Environment (please complete the following information):

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions