Brandon Chapman
06/20/2024, 2:38 AM2024-06-20 02:36:52.013 [main] INFO ktor.application - Application started in 3.795 seconds.
2024-06-20 02:36:52.477 [DefaultDispatcher-worker-1] INFO ktor.application - Responding at <http://0.0.0.0:8080>
2024-06-20 02:36:58.192 [eventLoopGroupProxy-4-1] TRACE io.ktor.routing.Routing - Trace for [login]
/, segment:0 -> SUCCESS @ /
/(RateLimit login), segment:0 -> SUCCESS @ /(RateLimit login)
/(RateLimit login)/login, segment:1 -> SUCCESS @ /(RateLimit login)/login
/(RateLimit login)/login/(method:POST), segment:1 -> SUCCESS @ /(RateLimit login)/login/(method:POST)
/(RateLimit signup), segment:0 -> SUCCESS @ /(RateLimit signup)
/(RateLimit signup)/signup, segment:0 -> FAILURE "Selector didn't match" @ /(RateLimit signup)/signup
/(authenticate auth-jwt), segment:0 -> SUCCESS @ /(authenticate auth-jwt)
/(authenticate auth-jwt)/(RateLimit KTOR_NO_NAME_RATE_LIMITER), segment:0 -> SUCCESS @ /(authenticate auth-jwt)/(RateLimit KTOR_NO_NAME_RATE_LIMITER)
/(authenticate auth-jwt)/(RateLimit KTOR_NO_NAME_RATE_LIMITER)/dashboard, segment:0 -> FAILURE "Selector didn't match" @ /(authenticate auth-jwt)/(RateLimit KTOR_NO_NAME_RATE_LIMITER)/dashboard
/.well-known, segment:0 -> FAILURE "Selector didn't match" @ /.well-known
Matched routes:
"" -> "(RateLimit login)" -> "login" -> "(method:POST)"
Route resolve result:
SUCCESS @ /(RateLimit login)/login/(method:POST)
2024-06-20 02:36:58.201 [eventLoopGroupProxy-4-1] TRACE i.k.s.plugins.ratelimit.RateLimit - Using rate limit RateLimitName(name=login) for /login
2024-06-20 02:36:58.203 [eventLoopGroupProxy-4-1] TRACE i.k.s.plugins.ratelimit.RateLimit - Using key=kotlin.Unit and weight=1 for /login
2024-06-20 02:36:58.216 [eventLoopGroupProxy-4-1] TRACE i.k.s.plugins.ratelimit.RateLimit - Allowing /login
2024-06-20 02:36:58.315 [eventLoopGroupProxy-4-1] TRACE i.k.server.engine.DefaultTransform - No Default Transformations found for class io.ktor.utils.io.ByteBufferChannel and expected type TypeInfo(type=class com.XXXXXXXXXXX.models.Auth, reifiedType=class com.XXXXXXXXXXX.models.Auth, kotlinType=com.XXXXXXXXXXX.models.Auth) for call /login
^C2024-06-20 02:37:04.047 [eventLoopGroupProxy-4-1] TRACE i.k.s.p.statuspages.StatusPages - Call /login failed with cause com.auth0.jwk.NetworkException: Cannot obtain jwks from url <http://XXX.XX.XX.XXX:8080/.well-known/jwks.json>
2024-06-20 02:37:04.048 [eventLoopGroupProxy-4-1] TRACE i.k.s.p.statuspages.StatusPages - No handler found for exception: com.auth0.jwk.NetworkException: Cannot obtain jwks from url <http://XXX.XX.XX.XXX:8080/.well-known/jwks.json> for call /login
2024-06-20 02:37:04.051 [eventLoopGroupProxy-4-1] ERROR ktor.application - Unhandled: POST - /login
com.auth0.jwk.NetworkException: Cannot obtain jwks from url <http://XXX.XX.XX.XXX:8080/.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.lambda$get$0(GuavaCachedJwkProvider.java:62)
at com.google.common.cache.LocalCache$LocalManualCache$1.load(LocalCache.java:4925)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3571)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2313)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2190)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2080)
at com.google.common.cache.LocalCache.get(LocalCache.java:4012)
at com.google.common.cache.LocalCache$LocalManualCache.get(LocalCache.java:4920)
at com.auth0.jwk.GuavaCachedJwkProvider.get(GuavaCachedJwkProvider.java:62)
at com.XXXXXXXXXXX.routes.LoginKt$login$1.invokeSuspend(Login.kt:39)
at com.XXXXXXXXXXX.routes.LoginKt$login$1.invoke(Login.kt)
at com.XXXXXXXXXXX.routes.LoginKt$login$1.invoke(Login.kt)
at io.ktor.server.routing.Route$buildPipeline$1$1.invokeSuspend(Route.kt:116)
at io.ktor.server.routing.Route$buildPipeline$1$1.invoke(Route.kt)
at io.ktor.server.routing.Route$buildPipeline$1$1.invoke(Route.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:131)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:89)
at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:109)
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:131)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:89)
at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invokeSuspend(BaseApplicationEngine.kt:124)
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:131)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:89)
at io.ktor.server.application.hooks.CallFailed$install$1$1.invokeSuspend(CommonHooks.kt:45)
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:78)
at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
at io.ktor.server.application.hooks.CallFailed$install$1.invokeSuspend(CommonHooks.kt:44)
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:131)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:89)
at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:109)
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:123)
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:131)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:89)
at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:109)
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:140)
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:44)
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:41)
at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:33)
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:173)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166)
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:296)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Net.java:579)
at java.base/sun.nio.ch.Net.connect(Net.java:568)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:593)
at java.base/java.net.Socket.connect(Socket.java:633)
at java.base/java.net.Socket.connect(Socket.java:583)
at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:183)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:533)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:638)
at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:947)
at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:761)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1710)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1611)
at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:135)
... 87 common frames omitted
Brandon Chapman
06/20/2024, 2:43 AMjwks.json
file inside a certs folder to just a file in the root directory. That doesn't work. I've explicitly chown the directory and files. No change. I'm not sure why this works locally and adding the local.properties
file to the same directory as the jar loads that information, but jwks.json
won't seem to load. Java versions are identical.Brandon Chapman
06/20/2024, 2:45 AMjwt_issuer=<http://localhost:8080/>
jwt_audience=<http://localhost:8080/hello>
in local.properties
and in production I changed this to the IP addressBrandon Chapman
06/20/2024, 3:08 AMBrandon Chapman
06/20/2024, 3:08 AMfun Route.login(usersQueries: UserQueries, jwkProvider: JwkProvider, privateKeyString: String,
audience: String, issuer: String) {
post("/login") {
val auth = call.receive<Auth>()
// Check email exists and return hashed password
var pwHash = usersQueries.findByEmail(auth.email).executeAsList().toString()
if(pwHash == "[]") {
call.respond(HttpStatusCode.Unauthorized, "Email not found")
}
// remove leading and trailing brackets from pwHash
pwHash = pwHash.dropLast(1)
pwHash = pwHash.drop(1)
// check password against hash in database
val validPw = BCrypt.checkpw(auth.password, pwHash)
// we have found email and verified password
if (validPw) {
val publicKey = jwkProvider.get("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAusmK9bSA4sQDJR5LpR5wL9oEoSke7xfi9MRT7OvzSakOzHm/PvB0vWBW17K7l/wMX/JTHZtjtDARmNq3bNi0JMk+on9ryWyYtaAnOFcQF7xuwS5knO0wpoBraWTFGPH5Iunr+t9nG0J4IdUD+NSl ep6C12JJN5cTe5hlPDe2dKS6RAVo0HsBpw4bmIX+sLBR6kxq70OayI0x0CDN0vfC++yIW+FLUcBU4wjL7R7aGrLiugzNKZX73M7ZplCSG1E9XsMKeAcnXTq+U/eWsdJqKUpEGwkqQoFl9yuhnYtr/E16l18srFxab7RZP5tUuYXLQl22hJEbXnuGKK03e9XFqQIDAQAB").publicKey
val keySpecPKCS8 = PKCS8EncodedKeySpec(getDecoder().decode(privateKeyString))
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpecPKCS8)
val token = JWT.create()
.withAudience(audience)
.withIssuer(issuer)
.withClaim("email", auth.email)
.withExpiresAt(Date(System.currentTimeMillis() + 57600000)) // 16 hours
.sign(Algorithm.RSA256(publicKey as RSAPublicKey, privateKey as RSAPrivateKey))
call.respond(hashMapOf("token" to token))
} else {
call.respond(HttpStatusCode.Unauthorized, "Password is invalid")
}
}
Brandon Chapman
06/20/2024, 12:49 PMAndrew O'Hara
06/20/2024, 12:52 PMcom.auth0.jwk.NetworkException: Cannot obtain jwks from url <http://XXX.XX.XX.XXX:8080/.well-known/jwks.json>
Brandon Chapman
06/20/2024, 12:56 PMAndrew O'Hara
06/20/2024, 12:56 PMBrandon Chapman
06/20/2024, 12:57 PMAndrew O'Hara
06/20/2024, 1:00 PM$ curl -v <http://xxx.xx.xx.xxx:8080/.well-known/jwks.json>
Andrew O'Hara
06/20/2024, 1:01 PMBrandon Chapman
06/20/2024, 1:13 PMBrandon Chapman
06/20/2024, 1:13 PMBrandon Chapman
06/20/2024, 1:14 PMAndrew O'Hara
06/20/2024, 1:15 PMBrandon Chapman
06/20/2024, 5:59 PMprintln()
statements. The route hangs at jwkProvider.get
this is bizarre. I can curl the jwks.json
file from the ec2 instance terminal and from my local terminal.
That's two different compute providers giving the same issue. Digitalocean and Amazon. Not sure how to debug this in productionBrandon Chapman
06/20/2024, 6:01 PMBrandon Chapman
06/20/2024, 7:10 PMjwks.json
file location for my local rig and it'll pull the file locally to build the jwkProvider. This is a really strange bug. I increased read timeout on the builder to 10s. Just stalls until it hits the read timeout and gives the same error that it can't find the file at the location. Why can it be found every which way except inside the program?Brandon Chapman
06/20/2024, 7:30 PMBrandon Chapman
06/20/2024, 8:34 PMBrandon Chapman
06/20/2024, 9:46 PMapplication.conf
hoping that would somehow change things. I'm out of ideas 🤷♂️ the error doesn't appear to match what's going on. In every which way except outside of the application, I can access and use the jwks.json file at the server location. Just not by the application at a remote compute instance.Brandon Chapman
06/20/2024, 11:35 PMEugene Wainaina
11/03/2024, 8:07 PM