auth0 / jwks-rsa-java

MIT License
194 stars 73 forks source link

com.auth0.jwk.NetworkException: Cannot obtain jwks from url #163

Closed sivaraman-27 closed 1 year ago

sivaraman-27 commented 1 year ago

Hello, I'm encountering the issue "com.auth0.jwk.NetworkException: Cannot obtain jwks from url"

I'm trying to get the jwks from microsoft. But encountering the below issue

com.auth0.jwk.NetworkException: Cannot obtain jwks from url https://login.microsoftonline.com/common/discovery/v2.0/keys
        at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:139) ~[jwks-rsa-0.21.2.jar:0.21.2]
        at com.auth0.jwk.UrlJwkProvider.getAll(UrlJwkProvider.java:145) ~[jwks-rsa-0.21.2.jar:0.21.2]
        at com.auth0.jwk.UrlJwkProvider.get(UrlJwkProvider.java:163) ~[jwks-rsa-0.21.2.jar:0.21.2]

What was the expected behavior?

Successfully obtain jwks from the specified url

Reproduction

--

Environment

sivaraman-27 commented 1 year ago

Update 1:

I found the exception was thrown from 'UrlJwkProvider.java'. Below is the code

    private Map<String, Object> getJwks() throws SigningKeyNotFoundException {
        try {
            final URLConnection c = (proxy == null) ? this.url.openConnection() : this.url.openConnection(proxy);
            if (connectTimeout != null) {
                c.setConnectTimeout(connectTimeout);
            }
            if (readTimeout != null) {
                c.setReadTimeout(readTimeout);
            }

            for (Map.Entry<String, String> entry : headers.entrySet()) {
                c.setRequestProperty(entry.getKey(), entry.getValue());
            }

            try (InputStream inputStream = c.getInputStream()) {
                return reader.readValue(inputStream);
            }
        } catch (IOException e) {
            throw new NetworkException("Cannot obtain jwks from url " + url.toString(), e);
        }
    }

For new UrlJwkProvider, I'm only passing "Microsoft URL" alone, rest of them are null

    public UrlJwkProvider(URL url) {
        this(url, null, null, null, null);
    }
sivaraman-27 commented 1 year ago

Hi, @jimmyjames. Can you give any reasons for the above error?

axis80 commented 1 year ago

@sivaraman-27 Azure AD and some other IDPs use a different URL path structure for the JWKS endpoint. With those, you will have to specify the URL path explicitly. For my Azure AD IDP the URL is https://login.microsoftonline.com/<clientId>/discovery/v2.0/keys so I used this code:

provider = new UrlJwkProvider(new URL("https://login.microsoftonline.com/<clientId>/discovery/v2.0/keys"));

See https://github.com/auth0/jwks-rsa-java/issues/112 for more info.

shibukawa commented 1 year ago

I read source code of jwks-rsa-java and I noticed the same issue of this.

/.well-known/ paths are specified in internet standard and you can see on the following page.

https://www.iana.org/assignments/well-known-uris/well-known-uris.xhtml

/.well-known/openid-configuration is an internet standard based on OpenID Connect specs, but /.well-known/jwks.json is not allowed as a standard URL.

It requires extra internet access, but I beleave getting JWK's location form /.well-known/openid-configuration is the politest way to get JWKs.

shibukawa commented 1 year ago

@axis80 I tested on AzureAD and I got the following OpenID configuration path

And it returns the following path.

I couldn't access the path you mentioned.

jimmyjames commented 1 year ago

Thanks everyone for the help and ideas!

I'm trying to understand the issue at hand here, if I try the following it works as expected:

String url = "https://login.microsoftonline.com/common/discovery/v2.0/keys";

UrlJwkProvider provider = new UrlJwkProvider(new URI(url).normalize().toURL());
System.out.println(provider.get("{SOME-KID}"));

@axis80 is correct that we don't currently traverse the discovery URL as discussed in #112, but not sure if that's related to this specific issue or not.

If there's an example that reproduces an issue let us know, thanks!

jimmyjames commented 1 year ago

Potentially related, #165 may help in this case by at least throwing a more specific exception.

NeptuneG commented 1 year ago

While UrlJwkProvider works for me, I ran into a similar issue when using JwkProviderBuilder

public JwkProviderBuilder(String domain) 's doc says

It can be a url link 'https://samples.auth0.com' or just a domain 'samples.auth0.com'. If the protocol (http or https) is not provided then https is used by default. The default jwks path "/.well-known/jwks.json" is appended to the given string domain.

For example, when the domain is "samples.auth0.com" the jwks url that will be used is "https://samples.auth0.com/.well-known/jwks.json"

I agree with @shibukawa 's comment because I am using Keycloak and its default jwks_uri (which can be got from its ".well-known/openid-configuration") is like http://localhost:8080/auth/realms/master/protocol/openid-connect/certs which has nothing to do with "/.well-known/jwks.json".

Here is the backtrace of JwkProviderBuilder("http://0.0.0.0:18080/realms/real-world/protocol/openid-connect/certs")

2023-03-22 10:12:49.487 [eventLoopGroupProxy-4-3] TRACE io.ktor.server.auth.Authentication - Trying to authenticate /hello with keycloakJWT
2023-03-22 10:12:49.562 [eventLoopGroupProxy-4-3] TRACE io.ktor.auth.jwt - Failed to get JWK
com.auth0.jwk.SigningKeyNotFoundException: Failed to get key with kid l1YB4RV4wFs88KmbNOuXACmN40cgQcauRPhQ7rOyrkQ
        at com.auth0.jwk.GuavaCachedJwkProvider.get(GuavaCachedJwkProvider.java:70)
        at io.ktor.server.auth.jwt.JWTUtilsKt.getVerifier(JWTUtils.kt:55)
        at io.ktor.server.auth.jwt.JWTAuthenticationProvider$Config$verifier$4.invoke(JWTAuth.kt:250)
        at io.ktor.server.auth.jwt.JWTAuthenticationProvider$Config$verifier$4.invoke(JWTAuth.kt:250)
        at io.ktor.server.auth.jwt.JWTAuthenticationProvider.onAuthenticate(JWTAuth.kt:160)
        at io.ktor.server.auth.AuthenticationInterceptorsKt$AuthenticationInterceptors$2$1.invokeSuspend(AuthenticationInterceptors.kt:102)
        at io.ktor.server.auth.AuthenticationInterceptorsKt$AuthenticationInterceptors$2$1.invoke(AuthenticationInterceptors.kt)
        at io.ktor.server.auth.AuthenticationInterceptorsKt$AuthenticationInterceptors$2$1.invoke(AuthenticationInterceptors.kt)
        at io.ktor.server.auth.AuthenticationHook$install$1.invokeSuspend(AuthenticationInterceptors.kt:25)
        at io.ktor.server.auth.AuthenticationHook$install$1.invoke(AuthenticationInterceptors.kt)
        at io.ktor.server.auth.AuthenticationHook$install$1.invoke(AuthenticationInterceptors.kt)
        at io.ktor.server.application.ApplicationPluginKt$addAllInterceptors$1$1$1.invokeSuspend(ApplicationPlugin.kt:167)
        at io.ktor.server.application.ApplicationPluginKt$addAllInterceptors$1$1$1.invoke(ApplicationPlugin.kt)
        at io.ktor.server.application.ApplicationPluginKt$addAllInterceptors$1$1$1.invoke(ApplicationPlugin.kt)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
        at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
        at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invokeSuspend(Pipeline.kt:478)
        at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17)
        at io.ktor.server.routing.Routing.executeResult(Routing.kt:190)
        at io.ktor.server.routing.Routing.interceptor(Routing.kt:64)
        at io.ktor.server.routing.Routing$Plugin$install$1.invokeSuspend(Routing.kt:140)
        at io.ktor.server.routing.Routing$Plugin$install$1.invoke(Routing.kt)
        at io.ktor.server.routing.Routing$Plugin$install$1.invoke(Routing.kt)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
        at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invokeSuspend(BaseApplicationEngine.kt:123)
        at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invoke(BaseApplicationEngine.kt)
        at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invoke(BaseApplicationEngine.kt)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
        at io.ktor.server.application.hooks.CallFailed$install$1$1.invokeSuspend(CommonHooks.kt:43)
        at io.ktor.server.application.hooks.CallFailed$install$1$1.invoke(CommonHooks.kt)
        at io.ktor.server.application.hooks.CallFailed$install$1$1.invoke(CommonHooks.kt)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
        at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
        at io.ktor.server.application.hooks.CallFailed$install$1.invokeSuspend(CommonHooks.kt:42)
        at io.ktor.server.application.hooks.CallFailed$install$1.invoke(CommonHooks.kt)
        at io.ktor.server.application.hooks.CallFailed$install$1.invoke(CommonHooks.kt)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
        at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1$invokeSuspend$$inlined$execute$1.invokeSuspend(Pipeline.kt:478)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1.invokeSuspend(DefaultEnginePipeline.kt:118)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1.invoke(DefaultEnginePipeline.kt)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1.invoke(DefaultEnginePipeline.kt)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
        at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1$invokeSuspend$$inlined$execute$1.invokeSuspend(Pipeline.kt:478)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:119)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
        at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
        at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
        at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
        at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:37)
        at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:29)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
        at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
        at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:425)
        at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda$1$lambda$0(NettyApplicationEngine.kt:291)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.util.concurrent.ExecutionException: com.auth0.jwk.NetworkException: Cannot obtain jwks from url http://0.0.0.0:18080/realms/real-world/protocol/openid-connect/certs/.well-known/jwks.json
        at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:566)
        at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:527)
        at com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:104)
        at com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly(Uninterruptibles.java:240)
        at com.google.common.cache.LocalCache$Segment.getAndRecordStats(LocalCache.java:2313)
        at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2279)
        at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2155)
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2045)
        at com.google.common.cache.LocalCache.get(LocalCache.java:3951)
        at com.google.common.cache.LocalCache$LocalManualCache.get(LocalCache.java:4848)
        at com.auth0.jwk.GuavaCachedJwkProvider.get(GuavaCachedJwkProvider.java:63)
        ... 82 common frames omitted
Caused by: com.auth0.jwk.NetworkException: Cannot obtain jwks from url http://0.0.0.0:18080/realms/real-world/protocol/openid-connect/certs/.well-known/jwks.json
        at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:139)
        at com.auth0.jwk.UrlJwkProvider.getAll(UrlJwkProvider.java:145)
        at com.auth0.jwk.UrlJwkProvider.get(UrlJwkProvider.java:163)
        at com.auth0.jwk.RateLimitedJwkProvider.get(RateLimitedJwkProvider.java:28)
        at com.auth0.jwk.GuavaCachedJwkProvider$1.call(GuavaCachedJwkProvider.java:66)
        at com.auth0.jwk.GuavaCachedJwkProvider$1.call(GuavaCachedJwkProvider.java:63)
        at com.google.common.cache.LocalCache$LocalManualCache$1.load(LocalCache.java:4853)
        at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3529)
        at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2278)
        ... 87 common frames omitted
Caused by: java.io.FileNotFoundException: http://0.0.0.0:18080/realms/real-world/protocol/openid-connect/certs/.well-known/jwks.json
        at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1993)
        at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1589)
        at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:135)
        ... 95 common frames omitted