From 2fa41b4bc38b2477da9f13a1db4968c170ab0def Mon Sep 17 00:00:00 2001 From: John Melati Date: Sat, 19 Oct 2024 03:09:56 +0200 Subject: [PATCH] fix: verify function --- .../sphereon/oid/fed/client/crypto/Crypto.kt | 20 +++-- .../sphereon/oid/fed/client/fetch/Fetch.kt | 11 +-- .../oid/fed/client/trustchain/TrustChain.kt | 60 +++++++++++++-- .../fed/client/trustchain/TrustChainTest.kt | 6 +- .../oid/fed/client/crypto/Crypto.js.kt | 77 +++++++++---------- .../crypto/CryptoPlatformTestCallback.js.kt | 13 +--- .../oid/fed/client/crypto/CryptoTest.js.kt | 64 +++++++-------- .../oid/fed/client/crypto/Crypto.jvm.kt | 6 ++ 8 files changed, 156 insertions(+), 101 deletions(-) diff --git a/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.kt b/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.kt index dfe80784..e1b0c259 100644 --- a/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.kt +++ b/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.kt @@ -1,29 +1,31 @@ package com.sphereon.oid.fed.client.crypto import com.sphereon.oid.fed.client.types.ICallbackService - +import com.sphereon.oid.fed.openapi.models.Jwk interface ICryptoService { suspend fun verify( jwt: String, + key: Jwk, ): Boolean } interface ICryptoCallbackService : ICallbackService, ICryptoService -expect fun cryptoService(): ICryptoCallbackService - class DefaultPlatformCallback : ICryptoService { - override suspend fun verify(jwt: String): Boolean { - return verify(jwt) + override suspend fun verify(jwt: String, key: Jwk): Boolean { + return verifyImpl(jwt, key) } } object CryptoServiceObject : ICryptoCallbackService { private lateinit var platformCallback: ICryptoService - override suspend fun verify(jwt: String): Boolean { - return this.platformCallback.verify(jwt) + override suspend fun verify(jwt: String, key: Jwk): Boolean { + if (!::platformCallback.isInitialized) { + throw IllegalStateException("CryptoServiceObject not initialized") + } + return platformCallback.verify(jwt, key) } override fun register(platformCallback: ICryptoService?): ICryptoCallbackService { @@ -31,3 +33,7 @@ object CryptoServiceObject : ICryptoCallbackService { return this } } + +expect fun cryptoService(): ICryptoCallbackService + +expect suspend fun verifyImpl(jwt: String, key: Jwk): Boolean diff --git a/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/fetch/Fetch.kt b/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/fetch/Fetch.kt index f2957fc1..a93fc4e0 100644 --- a/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/fetch/Fetch.kt +++ b/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/fetch/Fetch.kt @@ -24,11 +24,12 @@ object FetchServiceObject : IFetchCallbackService { private lateinit var httpClient: HttpClient override suspend fun fetchStatement(endpoint: String): String { - return httpClient.get(endpoint) { - headers { - append(HttpHeaders.Accept, "application/entity-statement+jwt") - } - }.body() + return httpClient + .get(endpoint) { + headers { + append(HttpHeaders.Accept, "application/entity-statement+jwt") + } + }.body() } override fun getHttpClient(): HttpClient { diff --git a/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/trustchain/TrustChain.kt b/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/trustchain/TrustChain.kt index 4bb89da0..b43709e3 100644 --- a/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/trustchain/TrustChain.kt +++ b/modules/openid-federation-client/src/commonMain/kotlin/com/sphereon/oid/fed/client/trustchain/TrustChain.kt @@ -9,7 +9,12 @@ import com.sphereon.oid.fed.client.mapper.mapEntityStatement import com.sphereon.oid.fed.openapi.models.EntityConfigurationStatement import com.sphereon.oid.fed.openapi.models.Jwk import com.sphereon.oid.fed.openapi.models.SubordinateStatement +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import kotlin.collections.set class SimpleCache { @@ -28,7 +33,20 @@ class TrustChain(private val fetchService: IFetchCallbackService, private val cr ): MutableList? { val cache = SimpleCache() val chain: MutableList = arrayListOf() - return buildTrustChainRecursive(entityIdentifier, trustAnchors, chain, cache) + return try { + buildTrustChainRecursive(entityIdentifier, trustAnchors, chain, cache) + } catch (_: Exception) { + // Log error + null + } + } + + private fun findKeyInJwks(keys: JsonArray, kid: String): Jwk? { + val key = keys.firstOrNull { it.jsonObject["kid"]?.jsonPrimitive?.content?.trim() == kid.trim() } + + if (key == null) return null + + return Json.decodeFromJsonElement(Jwk.serializer(), key) } private suspend fun buildTrustChainRecursive( @@ -37,12 +55,17 @@ class TrustChain(private val fetchService: IFetchCallbackService, private val cr chain: MutableList, cache: SimpleCache ): MutableList? { - val entityConfigurationJwt = this.fetchService.fetchStatement(getEntityConfigurationEndpoint(entityIdentifier)) - val decodedEntityConfiguration = decodeJWTComponents(entityConfigurationJwt) - if (!cryptoService.verify(entityConfigurationJwt)) { + val key = findKeyInJwks( + decodedEntityConfiguration.payload["jwks"]?.jsonObject?.get("keys")?.jsonArray ?: return null, + decodedEntityConfiguration.header.kid + ) + + if (key == null) return null + + if (!cryptoService.verify(entityConfigurationJwt, key)) { return null } @@ -64,6 +87,7 @@ class TrustChain(private val fetchService: IFetchCallbackService, private val cr decodedEntityConfiguration.header.kid, cache ) + if (result != null) { return result } @@ -90,7 +114,21 @@ class TrustChain(private val fetchService: IFetchCallbackService, private val cr val authorityEntityConfigurationJwt = fetchService.fetchStatement(authorityConfigurationEndpoint) cache.put(authorityConfigurationEndpoint, authorityEntityConfigurationJwt) - if (!cryptoService.verify(authorityEntityConfigurationJwt)) { + val decodedJwt = decodeJWTComponents(authorityEntityConfigurationJwt) + val kid = decodedJwt.header.kid + + val key = findKeyInJwks( + decodedJwt.payload["jwks"]?.jsonObject?.get("keys")?.jsonArray ?: return null, + kid + ) + + if (key == null) return null + + if (!cryptoService.verify( + authorityEntityConfigurationJwt, + key + ) + ) { return null } @@ -109,7 +147,17 @@ class TrustChain(private val fetchService: IFetchCallbackService, private val cr val subordinateStatementJwt = fetchService.fetchStatement(subordinateStatementEndpoint) - if (!cryptoService.verify(subordinateStatementJwt)) { + val decodedSubordinateStatement = decodeJWTComponents(subordinateStatementJwt) + + val subordinateStatementKey = findKeyInJwks( + decodedJwt.payload["jwks"]?.jsonObject?.get("keys")?.jsonArray + ?: return null, + decodedSubordinateStatement.header.kid.trim() + ) + + if (subordinateStatementKey == null) return null + + if (!cryptoService.verify(subordinateStatementJwt, subordinateStatementKey)) { return null } diff --git a/modules/openid-federation-client/src/commonTest/kotlin/com/sphereon/oid/fed/client/trustchain/TrustChainTest.kt b/modules/openid-federation-client/src/commonTest/kotlin/com/sphereon/oid/fed/client/trustchain/TrustChainTest.kt index 4021e254..a5c43d0a 100644 --- a/modules/openid-federation-client/src/commonTest/kotlin/com/sphereon/oid/fed/client/trustchain/TrustChainTest.kt +++ b/modules/openid-federation-client/src/commonTest/kotlin/com/sphereon/oid/fed/client/trustchain/TrustChainTest.kt @@ -3,6 +3,7 @@ package com.sphereon.oid.fed.client.trustchain import com.sphereon.oid.fed.client.FederationClient import com.sphereon.oid.fed.client.crypto.ICryptoService import com.sphereon.oid.fed.client.fetch.IFetchService +import com.sphereon.oid.fed.openapi.models.Jwk import io.ktor.client.* import io.ktor.client.engine.mock.* import io.ktor.http.* @@ -27,7 +28,7 @@ class PlatformCallback : IFetchService { } class CryptoServiceCallback : ICryptoService { - override suspend fun verify(jwt: String): Boolean { + override suspend fun verify(jwt: String, jwk: Jwk): Boolean { return true } } @@ -44,7 +45,8 @@ class TrustChainTest() { ) assertNotNull(trustChain) - assertEquals(trustChain.size, 4) + + assertEquals(4, trustChain.size) assertEquals( trustChain[0], diff --git a/modules/openid-federation-client/src/jsMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.js.kt b/modules/openid-federation-client/src/jsMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.js.kt index 12a001a8..1f017988 100644 --- a/modules/openid-federation-client/src/jsMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.js.kt +++ b/modules/openid-federation-client/src/jsMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.js.kt @@ -3,14 +3,21 @@ package com.sphereon.oid.fed.client.crypto import com.sphereon.oid.fed.client.mapper.decodeJWTComponents import com.sphereon.oid.fed.client.types.ICallbackService import com.sphereon.oid.fed.openapi.models.Jwk +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.await +import kotlinx.coroutines.promise import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import kotlinx.serialization.json.jsonArray -import kotlinx.serialization.json.jsonObject -import kotlinx.serialization.json.jsonPrimitive import kotlin.js.Promise +@JsModule("jose") +@JsNonModule +external object Jose { + fun importJWK(jwk: Jwk, alg: String, options: dynamic = definedExternally): Promise + fun jwtVerify(jwt: String, key: Any, options: dynamic = definedExternally): Promise +} + @JsExport @JsName("ICallbackCryptoService") external interface ICallbackCryptoServiceJS { @@ -23,46 +30,22 @@ external interface ICallbackCryptoServiceJS { fun register(platformCallback: PlatformCallbackType?): ICallbackCryptoServiceJS } -@JsExport external interface ICryptoServiceCallbackJS { - @JsName("verify") fun verify( jwt: String, + key: Jwk ): Promise } class DefaultPlatformCallbackJS : ICryptoServiceCallbackJS { - override fun verify(jwt: String): Promise { - return try { - val decodedJwt = decodeJWTComponents(jwt) - val kid = decodedJwt.header.kid - - val jwk = decodedJwt.payload["jwks"]?.jsonObject?.get("keys")?.jsonArray - ?.firstOrNull { it.jsonObject["kid"]?.jsonPrimitive?.content == kid } - ?: throw Exception("JWK not found") - - Jose.importJWK( - JSON.parse(Json.encodeToString(jwk)), alg = decodedJwt.header.alg ?: "RS256" - ).then { publicKey: dynamic -> - Jose.jwtVerify(jwt, publicKey).then { verification: dynamic -> - println("Verification result: $verification") - verification != undefined - }.catch { error -> - println("Error during JWT verification: $error") - false - } - }.catch { error -> - println("Error importing JWK: $error") - false - } - } catch (e: Throwable) { - println("Error: $e") - Promise.resolve(false) - } + @OptIn(DelicateCoroutinesApi::class) + override fun verify(jwt: String, key: Jwk): Promise { + return GlobalScope.promise { verifyImpl(jwt, key) } } } @JsExport +@JsName("CryptoService") object CryptoServiceJS : ICallbackCryptoServiceJS, ICryptoServiceCallbackJS { private lateinit var platformCallback: ICryptoServiceCallbackJS @@ -71,8 +54,12 @@ object CryptoServiceJS : ICallbackCryptoServiceJS, ICr return this } - override fun verify(jwt: String): Promise { - return platformCallback.verify(jwt) + override fun verify(jwt: String, key: Jwk): Promise { + if (!::platformCallback.isInitialized) { + throw IllegalStateException("CryptoServiceJS not initialized") + } + + return platformCallback.verify(jwt, key) } } @@ -82,8 +69,8 @@ open class CryptoServiceJSAdapter(private val cryptoServiceCallbackJS: CryptoSer throw Error("Register function should not be used on the adapter. It depends on the Javascript CryptoService object") } - override suspend fun verify(jwt: String): Boolean { - return cryptoServiceCallbackJS.verify(jwt).await() + override suspend fun verify(jwt: String, key: Jwk): Boolean { + return cryptoServiceCallbackJS.verify(jwt, key).await() } } @@ -91,9 +78,17 @@ object CryptoServiceJSAdapterObject : CryptoServiceJSAdapter(CryptoServiceJS) actual fun cryptoService(): ICryptoCallbackService = CryptoServiceJSAdapterObject -@JsModule("jose") -@JsNonModule -external object Jose { - fun importJWK(jwk: Jwk, alg: String, options: dynamic = definedExternally): Promise - fun jwtVerify(jwt: String, key: Any, options: dynamic = definedExternally): Promise +actual suspend fun verifyImpl(jwt: String, key: Jwk): Boolean { + try { + val decodedJwt = decodeJWTComponents(jwt) + + val publicKey = Jose.importJWK( + JSON.parse(Json.encodeToString(key)), alg = decodedJwt.header.alg ?: "RS256" + ).await() + + val verification = Jose.jwtVerify(jwt, publicKey).await() + return verification != undefined + } catch (e: Throwable) { + return false + } } diff --git a/modules/openid-federation-client/src/jsTest/kotlin/com/sphereon/oid/fed/client/crypto/CryptoPlatformTestCallback.js.kt b/modules/openid-federation-client/src/jsTest/kotlin/com/sphereon/oid/fed/client/crypto/CryptoPlatformTestCallback.js.kt index 5f3a66b8..b09e4d7c 100644 --- a/modules/openid-federation-client/src/jsTest/kotlin/com/sphereon/oid/fed/client/crypto/CryptoPlatformTestCallback.js.kt +++ b/modules/openid-federation-client/src/jsTest/kotlin/com/sphereon/oid/fed/client/crypto/CryptoPlatformTestCallback.js.kt @@ -1,25 +1,18 @@ package com.sphereon.oid.fed.client.crypto import com.sphereon.oid.fed.client.mapper.decodeJWTComponents +import com.sphereon.oid.fed.openapi.models.Jwk import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import kotlinx.serialization.json.jsonArray -import kotlinx.serialization.json.jsonObject -import kotlinx.serialization.json.jsonPrimitive import kotlin.js.Promise class CryptoPlatformCallback : ICryptoServiceCallbackJS { - override fun verify(jwt: String): Promise { + override fun verify(jwt: String, key: Jwk): Promise { return try { val decodedJwt = decodeJWTComponents(jwt) - val kid = decodedJwt.header.kid - - val jwk = decodedJwt.payload["jwks"]?.jsonObject?.get("keys")?.jsonArray - ?.firstOrNull { it.jsonObject["kid"]?.jsonPrimitive?.content == kid } - ?: throw Exception("JWK not found") Jose.importJWK( - JSON.parse(Json.encodeToString(jwk)), alg = decodedJwt.header.alg ?: "RS256" + JSON.parse(Json.encodeToString(key)), alg = decodedJwt.header.alg ?: "RS256" ).then { publicKey: dynamic -> val options: dynamic = js("({})") options["currentDate"] = js("new Date(Date.parse(\"Oct 14, 2024 01:00:00\"))") diff --git a/modules/openid-federation-client/src/jsTest/kotlin/com/sphereon/oid/fed/client/crypto/CryptoTest.js.kt b/modules/openid-federation-client/src/jsTest/kotlin/com/sphereon/oid/fed/client/crypto/CryptoTest.js.kt index 7e663306..b6507531 100644 --- a/modules/openid-federation-client/src/jsTest/kotlin/com/sphereon/oid/fed/client/crypto/CryptoTest.js.kt +++ b/modules/openid-federation-client/src/jsTest/kotlin/com/sphereon/oid/fed/client/crypto/CryptoTest.js.kt @@ -1,9 +1,14 @@ package com.sphereon.oid.fed.client.crypto +import com.sphereon.oid.fed.client.mapper.decodeJWTComponents import com.sphereon.oid.fed.openapi.models.Jwk -import kotlinx.coroutines.async import kotlinx.coroutines.await import kotlinx.coroutines.test.runTest +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import kotlin.js.Promise import kotlin.test.Test import kotlin.test.assertEquals @@ -18,53 +23,52 @@ external object Jose { class CryptoTest { private val cryptoService = CryptoServiceJS.register(CryptoPlatformCallback()) - @Test - fun testVerifyValidJwt() = runTest { - val jwt = - "eyJraWQiOiJkZWZhdWx0UlNBU2lnbiIsInR5cCI6ImVudGl0eS1zdGF0ZW1lbnQrand0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCIsIm1ldGFkYXRhIjp7ImZlZGVyYXRpb25fZW50aXR5Ijp7ImZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9mZXRjaCIsImZlZGVyYXRpb25fcmVzb2x2ZV9lbmRwb2ludCI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0L3Jlc29sdmUiLCJmZWRlcmF0aW9uX3RydXN0X21hcmtfc3RhdHVzX2VuZHBvaW50IjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvdHJ1c3RfbWFya19zdGF0dXMiLCJmZWRlcmF0aW9uX2xpc3RfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9saXN0In19LCJqd2tzIjp7ImtleXMiOlt7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoiZGVmYXVsdFJTQVNpZ24iLCJuIjoicVJUSkhRZ2IyZjhjbG45ZEpiLVdnaWs0cUVMNUdHX19zUHpsQVU0aTY5UzZ5SHhlTWczMllnTGZVenBOQnhfOGtYMm5kellYTV9SS21vM2poalF4dXhDSzFJSFNRY01rZzFoR2lpLXhSdzh4NDV0OFNHbFdjU0hpN182UmFBWTFTeUZjRUVsTkFxSGk1b2VCYUIzRkd2ZnJWLUVQLWNOa1V2R0VWYnlzX0NieHlHRFE5UU0wTkVyc2lsVmxNQVJERXJFTlpjclkwck5LdDUyV29aZ3kzcHNWY2Q4VTVEMExxZkM3N2JQakczNVBhVmh3WUFubFAwZXowSGY2dHV5V0pIZUE1MmRDZGUtbmEzV2ptUGFya2NscEZyLUtqWGVJQzhCd2ZqRXBBWGJLY3A4Tm11UUZqOWZEOUtuUjZ2Q2RPOTFSeUJJYkRsdUw1TEg4czBxRENRIn0seyJrdHkiOiJFQyIsInVzZSI6InNpZyIsImNydiI6IlAtMjU2Iiwia2lkIjoiZGVmYXVsdEVDU2lnbiIsIngiOiJ4TWtXSWExRVp5amdtazNKUUx0SERBOXAwVHBQOXdNU2JKSzBvQWl0Z2NrIiwieSI6IkNWTEZzdE93S3d0UXJ1dF92b0hqWU82SnoxSzBOWFJ1OE9MQ1RtS29zTGcifSx7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoiZW5jIiwia2lkIjoiZGVmYXVsdFJTQUVuYyIsIm4iOiJ3ZXcyMnhjcGZBU2tRUXA3U09vX0dzNmNLajJYeTd4VlpLX3RnWnh6QXlReExTeG01c1U0WkdzNm1kSUFIZEV2UTkxU25FSFR0anBlQVM5d0N2TlhWbVZ4TklqRkFQSnpDWXBzZkZ4R3pXMVBSM1NDQmVLUFl6VWpTeUJTZWw1LW1Td1U4MHlZQXFPbFoxUVJaTlFJNUVTVXZOUG9lUEZqR0NvZnhuRlJzbXF5X21Bd1p5bmQyTnJyc1QyQXlwMEw2UFF3ei1Fa09oakVCcHpzeXEwcE11am5aRWZ2UHk5UC1YdjJTVUZMZUpQcm1jRHllNjRaMlk5V1BoMmpwa25oT3hESzhSTUwtMllUdmI0dVNPalowWFpPVzltVm9nTkpSSm0yemVQVGVlTFBxR2x1TGNEenBsYnkwbkxiTGpkWDdLM29MYnFoRGFld2o3VnJhS2Vtc1EifV19LCJ0cnVzdF9tYXJrX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX0sImlzcyI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiZXhwIjoxNzI5MTAzMjQxLCJpYXQiOjE3MjkwMTY4NDEsImNvbnN0cmFpbnRzIjp7Im1heF9wYXRoX2xlbmd0aCI6MX0sInRydXN0X21hcmtzX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX19.j9bmJRlLokkmWTpPkrphtB5dyVrKQPwY7U9jtl_PXlgVODmDXla0vbQszR_b0aUfk7j-Sh5v_UwtHRF6P5vPcaTvUiaPcbtFEIVq0xW9xcyjgPmYEkfHyB9CWxfq-AC6OOoRunGyTOO5G9xdup6QSLFxLQBlMZh5sE_X8wzkG02dZOfl8RTzuoquzNMl-yWpyb0Rxk_iY-ZhGa1yDPHm16tFmXMY3sf0QOBQAAGxBaRhcjekRnXPEijrPIaV381_VnQdd4xtbikI_XNRiGeyuoMii40K4l6qiznZ-_mz8GaRdS21Dc5XL5cjwMc4EDGxSNnW9NgBr7R4HDURyiixcA" + private fun findKeyInJwks(keys: JsonArray, kid: String): Jwk? { + val key = keys.firstOrNull { it.jsonObject["kid"]?.jsonPrimitive?.content?.trim() == kid.trim() } + + if (key == null) return null + + return Json.decodeFromJsonElement(Jwk.serializer(), key) + } + + private fun getKeyFromJwt(jwt: String): Jwk { + val decodedJwt = decodeJWTComponents(jwt) - val deferred = async { - val result = cryptoService.verify(jwt).await() - assertEquals(true, result) - } + val key = findKeyInJwks( + decodedJwt.payload["jwks"]?.jsonObject?.get("keys")?.jsonArray ?: JsonArray(emptyList()), + decodedJwt.header.kid + ) ?: throw IllegalStateException("Key not found") - deferred.await() + return key } @Test - fun testVerifyValidJwtExpired() = runTest { + fun testVerifyValidJwt() = runTest { val jwt = - "eyJraWQiOiJkZWZhdWx0UlNBU2lnbiIsInR5cCI6ImVudGl0eS1zdGF0ZW1lbnQrand0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCIsIm1ldGFkYXRhIjp7ImZlZGVyYXRpb25fZW50aXR5Ijp7ImZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9mZXRjaCIsImZlZGVyYXRpb25fcmVzb2x2ZV9lbmRwb2ludCI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0L3Jlc29sdmUiLCJmZWRlcmF0aW9uX3RydXN0X21hcmtfc3RhdHVzX2VuZHBvaW50IjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvdHJ1c3RfbWFya19zdGF0dXMiLCJmZWRlcmF0aW9uX2xpc3RfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9saXN0In19LCJqd2tzIjp7ImtleXMiOlt7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoiZGVmYXVsdFJTQVNpZ24iLCJuIjoicVJUSkhRZ2IyZjhjbG45ZEpiLVdnaWs0cUVMNUdHX19zUHpsQVU0aTY5UzZ5SHhlTWczMllnTGZVenBOQnhfOGtYMm5kellYTV9SS21vM2poalF4dXhDSzFJSFNRY01rZzFoR2lpLXhSdzh4NDV0OFNHbFdjU0hpN182UmFBWTFTeUZjRUVsTkFxSGk1b2VCYUIzRkd2ZnJWLUVQLWNOa1V2R0VWYnlzX0NieHlHRFE5UU0wTkVyc2lsVmxNQVJERXJFTlpjclkwck5LdDUyV29aZ3kzcHNWY2Q4VTVEMExxZkM3N2JQakczNVBhVmh3WUFubFAwZXowSGY2dHV5V0pIZUE1MmRDZGUtbmEzV2ptUGFya2NscEZyLUtqWGVJQzhCd2ZqRXBBWGJLY3A4Tm11UUZqOWZEOUtuUjZ2Q2RPOTFSeUJJYkRsdUw1TEg4czBxRENRIn0seyJrdHkiOiJFQyIsInVzZSI6InNpZyIsImNydiI6IlAtMjU2Iiwia2lkIjoiZGVmYXVsdEVDU2lnbiIsIngiOiJ4TWtXSWExRVp5amdtazNKUUx0SERBOXAwVHBQOXdNU2JKSzBvQWl0Z2NrIiwieSI6IkNWTEZzdE93S3d0UXJ1dF92b0hqWU82SnoxSzBOWFJ1OE9MQ1RtS29zTGcifSx7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoiZW5jIiwia2lkIjoiZGVmYXVsdFJTQUVuYyIsIm4iOiJ3ZXcyMnhjcGZBU2tRUXA3U09vX0dzNmNLajJYeTd4VlpLX3RnWnh6QXlReExTeG01c1U0WkdzNm1kSUFIZEV2UTkxU25FSFR0anBlQVM5d0N2TlhWbVZ4TklqRkFQSnpDWXBzZkZ4R3pXMVBSM1NDQmVLUFl6VWpTeUJTZWw1LW1Td1U4MHlZQXFPbFoxUVJaTlFJNUVTVXZOUG9lUEZqR0NvZnhuRlJzbXF5X21Bd1p5bmQyTnJyc1QyQXlwMEw2UFF3ei1Fa09oakVCcHpzeXEwcE11am5aRWZ2UHk5UC1YdjJTVUZMZUpQcm1jRHllNjRaMlk5V1BoMmpwa25oT3hESzhSTUwtMllUdmI0dVNPalowWFpPVzltVm9nTkpSSm0yemVQVGVlTFBxR2x1TGNEenBsYnkwbkxiTGpkWDdLM29MYnFoRGFld2o3VnJhS2Vtc1EifV19LCJ0cnVzdF9tYXJrX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX0sImlzcyI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiZXhwIjoxNzI4NDI4MDI1LCJpYXQiOjE3MjgzNDE2MjUsImNvbnN0cmFpbnRzIjp7Im1heF9wYXRoX2xlbmd0aCI6MX0sInRydXN0X21hcmtzX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX19.QVndoAzYG4-r-f1mq2szTurjN4IWG5GN6aUBeIm6k5EXOdjEa2oOmP8iANBjCFWF6eNPNN2t342pBpb6-46o9kJv9MxyWASIaBkOv_X8RJGEgv2ghDLLnfOLv4R6J9XH9IIsQPzjlezgWJYk61ukfYN7kWA_aIT5Hf42zEU14V5kLbl50r8wjgJVRwmSBsDLKsWbOnbzfkiKv4druFhfhDZjiyBeCjYajh9MFYdAR1awYihNM-JVib89Z7XgOqxq4qGogPt_XU-YMuf917lw4kpphPRoUe1QIoj1KXfgbpJUdgiLMlXQoBl57Ej3b1mVWgEkC6oKjNyNvZR57Kx8AQ" + "eyJraWQiOiJkZWZhdWx0UlNBU2lnbiIsInR5cCI6ImVudGl0eS1zdGF0ZW1lbnQrand0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCIsIm1ldGFkYXRhIjp7ImZlZGVyYXRpb25fZW50aXR5Ijp7ImZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9mZXRjaCIsImZlZGVyYXRpb25fcmVzb2x2ZV9lbmRwb2ludCI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0L3Jlc29sdmUiLCJmZWRlcmF0aW9uX3RydXN0X21hcmtfc3RhdHVzX2VuZHBvaW50IjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvdHJ1c3RfbWFya19zdGF0dXMiLCJmZWRlcmF0aW9uX2xpc3RfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9saXN0In19LCJqd2tzIjp7ImtleXMiOlt7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoiZGVmYXVsdFJTQVNpZ24iLCJuIjoicVJUSkhRZ2IyZjhjbG45ZEpiLVdnaWs0cUVMNUdHX19zUHpsQVU0aTY5UzZ5SHhlTWczMllnTGZVenBOQnhfOGtYMm5kellYTV9SS21vM2poalF4dXhDSzFJSFNRY01rZzFoR2lpLXhSdzh4NDV0OFNHbFdjU0hpN182UmFBWTFTeUZjRUVsTkFxSGk1b2VCYUIzRkd2ZnJWLUVQLWNOa1V2R0VWYnlzX0NieHlHRFE5UU0wTkVyc2lsVmxNQVJERXJFTlpjclkwck5LdDUyV29aZ3kzcHNWY2Q4VTVEMExxZkM3N2JQakczNVBhVmh3WUFubFAwZXowSGY2dHV5V0pIZUE1MmRDZGUtbmEzV2ptUGFya2NscEZyLUtqWGVJQzhCd2ZqRXBBWGJLY3A4Tm11UUZqOWZEOUtuUjZ2Q2RPOTFSeUJJYkRsdUw1TEg4czBxRENRIn0seyJrdHkiOiJFQyIsInVzZSI6InNpZyIsImNydiI6IlAtMjU2Iiwia2lkIjoiZGVmYXVsdEVDU2lnbiIsIngiOiJ4TWtXSWExRVp5amdtazNKUUx0SERBOXAwVHBQOXdNU2JKSzBvQWl0Z2NrIiwieSI6IkNWTEZzdE93S3d0UXJ1dF92b0hqWU82SnoxSzBOWFJ1OE9MQ1RtS29zTGcifSx7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoiZW5jIiwia2lkIjoiZGVmYXVsdFJTQUVuYyIsIm4iOiJ3ZXcyMnhjcGZBU2tRUXA3U09vX0dzNmNLajJYeTd4VlpLX3RnWnh6QXlReExTeG01c1U0WkdzNm1kSUFIZEV2UTkxU25FSFR0anBlQVM5d0N2TlhWbVZ4TklqRkFQSnpDWXBzZkZ4R3pXMVBSM1NDQmVLUFl6VWpTeUJTZWw1LW1Td1U4MHlZQXFPbFoxUVJaTlFJNUVTVXZOUG9lUEZqR0NvZnhuRlJzbXF5X21Bd1p5bmQyTnJyc1QyQXlwMEw2UFF3ei1Fa09oakVCcHpzeXEwcE11am5aRWZ2UHk5UC1YdjJTVUZMZUpQcm1jRHllNjRaMlk5V1BoMmpwa25oT3hESzhSTUwtMllUdmI0dVNPalowWFpPVzltVm9nTkpSSm0yemVQVGVlTFBxR2x1TGNEenBsYnkwbkxiTGpkWDdLM29MYnFoRGFld2o3VnJhS2Vtc1EifV19LCJ0cnVzdF9tYXJrX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX0sImlzcyI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiZXhwIjoxNzI5MTAzMjQxLCJpYXQiOjE3MjkwMTY4NDEsImNvbnN0cmFpbnRzIjp7Im1heF9wYXRoX2xlbmd0aCI6MX0sInRydXN0X21hcmtzX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX19.j9bmJRlLokkmWTpPkrphtB5dyVrKQPwY7U9jtl_PXlgVODmDXla0vbQszR_b0aUfk7j-Sh5v_UwtHRF6P5vPcaTvUiaPcbtFEIVq0xW9xcyjgPmYEkfHyB9CWxfq-AC6OOoRunGyTOO5G9xdup6QSLFxLQBlMZh5sE_X8wzkG02dZOfl8RTzuoquzNMl-yWpyb0Rxk_iY-ZhGa1yDPHm16tFmXMY3sf0QOBQAAGxBaRhcjekRnXPEijrPIaV381_VnQdd4xtbikI_XNRiGeyuoMii40K4l6qiznZ-_mz8GaRdS21Dc5XL5cjwMc4EDGxSNnW9NgBr7R4HDURyiixcA" - val deferred = async { - val result = cryptoService.verify(jwt).await() - assertEquals(false, result) - } + val key = getKeyFromJwt(jwt) - deferred.await() + val result = cryptoService.verify(jwt, key).await() + assertEquals(true, result) } @Test - fun testVerifyJwtWithoutKeys() = runTest { + fun testVerifyValidJwtExpired() = runTest { val jwt = - "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTUxNjIzOTAyMn0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNb" - val deferred = async { - val result = cryptoService.verify(jwt).await() - assertEquals(false, result) - } + "eyJraWQiOiJkZWZhdWx0UlNBU2lnbiIsInR5cCI6ImVudGl0eS1zdGF0ZW1lbnQrand0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCIsIm1ldGFkYXRhIjp7ImZlZGVyYXRpb25fZW50aXR5Ijp7ImZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9mZXRjaCIsImZlZGVyYXRpb25fcmVzb2x2ZV9lbmRwb2ludCI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0L3Jlc29sdmUiLCJmZWRlcmF0aW9uX3RydXN0X21hcmtfc3RhdHVzX2VuZHBvaW50IjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvdHJ1c3RfbWFya19zdGF0dXMiLCJmZWRlcmF0aW9uX2xpc3RfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9saXN0In19LCJqd2tzIjp7ImtleXMiOlt7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoiZGVmYXVsdFJTQVNpZ24iLCJuIjoicVJUSkhRZ2IyZjhjbG45ZEpiLVdnaWs0cUVMNUdHX19zUHpsQVU0aTY5UzZ5SHhlTWczMllnTGZVenBOQnhfOGtYMm5kellYTV9SS21vM2poalF4dXhDSzFJSFNRY01rZzFoR2lpLXhSdzh4NDV0OFNHbFdjU0hpN182UmFBWTFTeUZjRUVsTkFxSGk1b2VCYUIzRkd2ZnJWLUVQLWNOa1V2R0VWYnlzX0NieHlHRFE5UU0wTkVyc2lsVmxNQVJERXJFTlpjclkwck5LdDUyV29aZ3kzcHNWY2Q4VTVEMExxZkM3N2JQakczNVBhVmh3WUFubFAwZXowSGY2dHV5V0pIZUE1MmRDZGUtbmEzV2ptUGFya2NscEZyLUtqWGVJQzhCd2ZqRXBBWGJLY3A4Tm11UUZqOWZEOUtuUjZ2Q2RPOTFSeUJJYkRsdUw1TEg4czBxRENRIn0seyJrdHkiOiJFQyIsInVzZSI6InNpZyIsImNydiI6IlAtMjU2Iiwia2lkIjoiZGVmYXVsdEVDU2lnbiIsIngiOiJ4TWtXSWExRVp5amdtazNKUUx0SERBOXAwVHBQOXdNU2JKSzBvQWl0Z2NrIiwieSI6IkNWTEZzdE93S3d0UXJ1dF92b0hqWU82SnoxSzBOWFJ1OE9MQ1RtS29zTGcifSx7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoiZW5jIiwia2lkIjoiZGVmYXVsdFJTQUVuYyIsIm4iOiJ3ZXcyMnhjcGZBU2tRUXA3U09vX0dzNmNLajJYeTd4VlpLX3RnWnh6QXlReExTeG01c1U0WkdzNm1kSUFIZEV2UTkxU25FSFR0anBlQVM5d0N2TlhWbVZ4TklqRkFQSnpDWXBzZkZ4R3pXMVBSM1NDQmVLUFl6VWpTeUJTZWw1LW1Td1U4MHlZQXFPbFoxUVJaTlFJNUVTVXZOUG9lUEZqR0NvZnhuRlJzbXF5X21Bd1p5bmQyTnJyc1QyQXlwMEw2UFF3ei1Fa09oakVCcHpzeXEwcE11am5aRWZ2UHk5UC1YdjJTVUZMZUpQcm1jRHllNjRaMlk5V1BoMmpwa25oT3hESzhSTUwtMllUdmI0dVNPalowWFpPVzltVm9nTkpSSm0yemVQVGVlTFBxR2x1TGNEenBsYnkwbkxiTGpkWDdLM29MYnFoRGFld2o3VnJhS2Vtc1EifV19LCJ0cnVzdF9tYXJrX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX0sImlzcyI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiZXhwIjoxNzI4NDI4MDI1LCJpYXQiOjE3MjgzNDE2MjUsImNvbnN0cmFpbnRzIjp7Im1heF9wYXRoX2xlbmd0aCI6MX0sInRydXN0X21hcmtzX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX19.QVndoAzYG4-r-f1mq2szTurjN4IWG5GN6aUBeIm6k5EXOdjEa2oOmP8iANBjCFWF6eNPNN2t342pBpb6-46o9kJv9MxyWASIaBkOv_X8RJGEgv2ghDLLnfOLv4R6J9XH9IIsQPzjlezgWJYk61ukfYN7kWA_aIT5Hf42zEU14V5kLbl50r8wjgJVRwmSBsDLKsWbOnbzfkiKv4druFhfhDZjiyBeCjYajh9MFYdAR1awYihNM-JVib89Z7XgOqxq4qGogPt_XU-YMuf917lw4kpphPRoUe1QIoj1KXfgbpJUdgiLMlXQoBl57Ej3b1mVWgEkC6oKjNyNvZR57Kx8AQ" - deferred.await() + val key = getKeyFromJwt(jwt) + val result = cryptoService.verify(jwt, key).await() + assertEquals(false, result) } @Test fun testVerifyInvalidSignature() = runTest { val jwt = "eyJraWQiOiJkZWZhdWx0UlNBU2lnbiIsInR5cCI6ImVudGl0eS1zdGF0ZW1lbnQrand0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCIsIm1ldGFkYXRhIjp7ImZlZGVyYXRpb25fZW50aXR5Ijp7ImZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9mZXRjaCIsImZlZGVyYXRpb25fcmVzb2x2ZV9lbmRwb2ludCI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0L3Jlc29sdmUiLCJmZWRlcmF0aW9uX3RydXN0X21hcmtfc3RhdHVzX2VuZHBvaW50IjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvdHJ1c3RfbWFya19zdGF0dXMiLCJmZWRlcmF0aW9uX2xpc3RfZW5kcG9pbnQiOiJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9saXN0In19LCJqd2tzIjp7ImtleXMiOlt7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoiZGVmYXVsdFJTQVNpZ24iLCJuIjoicVJUSkhRZ2IyZjhjbG45ZEpiLVdnaWs0cUVMNUdHX19zUHpsQVU0aTY5UzZ5SHhlTWczMllnTGZVenBOQnhfOGtYMm5kellYTV9SS21vM2poalF4dXhDSzFJSFNRY01rZzFoR2lpLXhSdzh4NDV0OFNHbFdjU0hpN182UmFBWTFTeUZjRUVsTkFxSGk1b2VCYUIzRkd2ZnJWLUVQLWNOa1V2R0VWYnlzX0NieHlHRFE5UU0wTkVyc2lsVmxNQVJERXJFTlpjclkwck5LdDUyV29aZ3kzcHNWY2Q4VTVEMExxZkM3N2JQakczNVBhVmh3WUFubFAwZXowSGY2dHV5V0pIZUE1MmRDZGUtbmEzV2ptUGFya2NscEZyLUtqWGVJQzhCd2ZqRXBBWGJLY3A4Tm11UUZqOWZEOUtuUjZ2Q2RPOTFSeUJJYkRsdUw1TEg4czBxRENRIn0seyJrdHkiOiJFQyIsInVzZSI6InNpZyIsImNydiI6IlAtMjU2Iiwia2lkIjoiZGVmYXVsdEVDU2lnbiIsIngiOiJ4TWtXSWExRVp5amdtazNKUUx0SERBOXAwVHBQOXdNU2JKSzBvQWl0Z2NrIiwieSI6IkNWTEZzdE93S3d0UXJ1dF92b0hqWU82SnoxSzBOWFJ1OE9MQ1RtS29zTGcifSx7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoiZW5jIiwia2lkIjoiZGVmYXVsdFJTQUVuYyIsIm4iOiJ3ZXcyMnhjcGZBU2tRUXA3U09vX0dzNmNLajJYeTd4VlpLX3RnWnh6QXlReExTeG01c1U0WkdzNm1kSUFIZEV2UTkxU25FSFR0anBlQVM5d0N2TlhWbVZ4TklqRkFQSnpDWXBzZkZ4R3pXMVBSM1NDQmVLUFl6VWpTeUJTZWw1LW1Td1U4MHlZQXFPbFoxUVJaTlFJNUVTVXZOUG9lUEZqR0NvZnhuRlJzbXF5X21Bd1p5bmQyTnJyc1QyQXlwMEw2UFF3ei1Fa09oakVCcHpzeXEwcE11am5aRWZ2UHk5UC1YdjJTVUZMZUpQcm1jRHllNjRaMlk5V1BoMmpwa25oT3hESzhSTUwtMllUdmI0dVNPalowWFpPVzltVm9nTkpSSm0yemVQVGVlTFBxR2x1TGNEenBsYnkwbkxiTGpkWDdLM29MYnFoRGFld2o3VnJhS2Vtc1EifV19LCJ0cnVzdF9tYXJrX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX0sImlzcyI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiZXhwIjoxNzI5MTAzMjQxLCJpYXQiOjE3MjkwMTY4NDEsImNvbnN0cmFpbnRzIjp7Im1heF9wYXRoX2xlbmd0aCI6MX0sInRydXN0X21hcmtzX2lzc3VlcnMiOnsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb2F1dGhfcmVzb3VyY2UvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcHJvdmlkZXIvcHJpdmF0ZSI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vYXV0aF9yZXNvdXJjZS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wdWJsaWMiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsImh0dHBzOi8vYXV0aC50b3NjYW5hLml0L2F1dGgvcmVhbG1zL2VudGkvZmVkZXJhdGlvbi1lbnRpdHkvcl90b3NjYW5fc2FfZW50aSIsImh0dHBzOi8vYXV0ZW50aWNhemlvbmUuY2xvdWQucHJvdmluY2lhLnRuLml0L2FnZ3JlZ2F0b3JlIiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3ByaXZhdGUiOlsiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiXSwiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvb3BlbmlkX3Byb3ZpZGVyL3B1YmxpYyI6WyJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdCJdLCJodHRwczovL29pZGMucmVnaXN0cnkuc2Vydml6aWNpZS5pbnRlcm5vLmdvdi5pdC9vcGVuaWRfcmVseWluZ19wYXJ0eS9wcml2YXRlIjpbImh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0IiwiaHR0cHM6Ly9vaWRjc2Eud2VibG9vbS5pdCIsImh0dHBzOi8vc3BpZC53YnNzLml0L1NwaWQvb2lkYy9zYSIsImh0dHBzOi8vc2VjdXJlLmVyZW1pbmQuaXQvaWRlbnRpdGEtZGlnaXRhbGUtb2lkYy9vaWRjLWZlZCIsImh0dHBzOi8vY2llLW9pZGMuY29tdW5lLW9ubGluZS5pdC9BdXRoU2VydmljZU9JREMvb2lkYy9zYSIsImh0dHBzOi8vcGhwLWNpZS5hbmR4b3IuaXQiLCJodHRwczovL2xvZ2luLmFzZndlYi5pdC8iLCJodHRwczovL29pZGMuc3R1ZGlvYW1pY2EuY29tIiwiaHR0cHM6Ly9pZHAuZW50cmFuZXh0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9jd29sc3NvLm51dm9sYXBhbGl0YWxzb2Z0Lml0L3NlcnZpY2VzL29pZGMvc2Evc3NvIiwiaHR0cHM6Ly9mZWRlcmEubGVwaWRhLml0L2d3L09pZGNTYUZ1bGwvIiwiaHR0cHM6Ly93d3cuZXVyb2NvbnRhYi5pdC9hcGkiXX19.j9bmJRlLokkmWTpPkrphtB5dyVrKQPwY7U9jtl_PXlgVODmDXla0vbQszR_b0aUfk7j-Sh5v_UwtHRF6P5vPcaTvUiaPcbtFEIVq0xW9xcyjgPmYEkfHyB9CWxfq-AC6OOoRunGyTOO5G9xdup6QSLFxLQBlMZh5sE_X8wzkG02dZOfl8RTzuoquzNMl-yWpyb0Rxk_iY-ZhGa1yDPHm16tFmXMY3sf0QOBQAAGxBaRhcjekRnXPEijrPIaV381_VnQdd4xtbikI_XNRiGeyuoMii40K4l6qiznZ-_mz8GaRdS21Dc5XL5cjwMc4EDGxSNnW9NgBr7R4HDURyii" - val deferred = async { - val result = cryptoService.verify(jwt).await() - assertEquals(false, result) - } - - deferred.await() + val key = getKeyFromJwt(jwt) + val result = cryptoService.verify(jwt, key).await() + assertEquals(false, result) } } diff --git a/modules/openid-federation-client/src/jvmMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.jvm.kt b/modules/openid-federation-client/src/jvmMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.jvm.kt index 5791f7fc..6beb26d5 100644 --- a/modules/openid-federation-client/src/jvmMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.jvm.kt +++ b/modules/openid-federation-client/src/jvmMain/kotlin/com/sphereon/oid/fed/client/crypto/Crypto.jvm.kt @@ -1,3 +1,9 @@ package com.sphereon.oid.fed.client.crypto +import com.sphereon.oid.fed.openapi.models.Jwk + actual fun cryptoService(): ICryptoCallbackService = CryptoServiceObject + +actual suspend fun verifyImpl(jwt: String, key: Jwk): Boolean { + TODO("Not yet implemented") +}