From da63278090712c2eccf5f86e24e4444e998f61ee Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Mon, 15 Jul 2024 20:51:01 +0530 Subject: [PATCH 01/25] feat: Added mapper for JWT --- .../oid/fed/common/mapper/JWTMapper.kt | 30 +++++++++++ .../oid/fed/common/model/JWTHeader.kt | 12 +++++ .../oid/fed/common/model/JWTSignature.kt | 4 ++ .../oid/fed/common/mapper/JWTMapperTest.kt | 50 +++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapper.kt create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTSignature.kt create mode 100644 modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapperTest.kt diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapper.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapper.kt new file mode 100644 index 00000000..cbd0ecb0 --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapper.kt @@ -0,0 +1,30 @@ +package com.sphereon.oid.fed.common.mapper + +import com.sphereon.oid.fed.common.model.JWTHeader +import com.sphereon.oid.fed.common.model.JWTSignature +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement + +import kotlin.io.encoding.Base64 +import kotlin.io.encoding.ExperimentalEncodingApi + + +@OptIn(ExperimentalEncodingApi::class) +fun decodeJWTComponents(jwtToken: String): Triple { + val parts = jwtToken.split(".") + if (parts.size != 3) { + return Triple(null, null, null) + } + + val headerJson = Base64.decode(parts[0]).decodeToString() + val payloadJson = Base64.decode(parts[1]).decodeToString() + + return try { + Triple( + Json.decodeFromString(headerJson), Json.parseToJsonElement(payloadJson), JWTSignature(parts[2]) + ) + } catch (e: Exception) { + println(e.printStackTrace()) + Triple(null, null, null) + } +} diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt new file mode 100644 index 00000000..1cdd0f26 --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt @@ -0,0 +1,12 @@ +package com.sphereon.oid.fed.common.model + +import kotlinx.serialization.Serializable + +import kotlinx.serialization.SerialName + +@Serializable +data class JWTHeader( + @SerialName("alg") val alg: String, // RS256 + @SerialName("kid") val kid: String, // B6EB8488CC84C41017134BC77F4132A0467CCC0E + @SerialName("typ") val typ: String // entity-statement+jwt +) \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTSignature.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTSignature.kt new file mode 100644 index 00000000..f9cf7995 --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTSignature.kt @@ -0,0 +1,4 @@ +package com.sphereon.oid.fed.common.model + + +data class JWTSignature(val value: String) \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapperTest.kt b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapperTest.kt new file mode 100644 index 00000000..d616ffd0 --- /dev/null +++ b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapperTest.kt @@ -0,0 +1,50 @@ +package com.sphereon.oid.fed.common.mapper + +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.boolean +import kotlinx.serialization.json.jsonPrimitive +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class JWTMapperTest { + + @Test + fun testDecodeValidJWT() { + val jwt = + "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTUxNjIzOTAyMn0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc" + val (header, payload, signature) = decodeJWTComponents(jwt) + + assertEquals("RS256", header?.alg) + assertEquals("B6EB8488CC84C41017134BC77F4132A0467CCC0E", header?.kid) + assertEquals("entity-statement+jwt", header?.typ) + + payload as JsonObject + assertEquals("1234567890", payload["sub"]?.jsonPrimitive?.content) // Check payload + assertEquals("John Doe", payload["name"]?.jsonPrimitive?.content) + assertEquals(true, payload["admin"]?.jsonPrimitive?.boolean) + + assertEquals("NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc", signature?.value) // Check signature + } + + @Test + fun testDecodeJWTWithInvalidStructure() { + val invalidJWT = "header.payload.signature" // Missing dots + val (header, payload, signature) = decodeJWTComponents(invalidJWT) + + assertNull(header) + assertNull(payload) + assertNull(signature) + } + + @Test + fun testDecodeJWTWithInvalidJSON() { + val jwtWithInvalidJson = + "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJhZG1pbiI6dHJ1ZX0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc" // Missing quote in payload + val (header, payload, signature) = decodeJWTComponents(jwtWithInvalidJson) + + assertNull(header) + assertNull(payload) + assertNull(signature) + } +} \ No newline at end of file From efa24365bd5d4ea148d392ccbb7b8590e00ae745 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Mon, 22 Jul 2024 00:07:24 +0200 Subject: [PATCH 02/25] feat: Created the client to fetch entity statements --- .../openid-federation-common/build.gradle.kts | 22 +++++++++--- .../common/httpclient/OidFederationClient.kt | 34 +++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt diff --git a/modules/openid-federation-common/build.gradle.kts b/modules/openid-federation-common/build.gradle.kts index 62762b20..a609c502 100644 --- a/modules/openid-federation-common/build.gradle.kts +++ b/modules/openid-federation-common/build.gradle.kts @@ -49,7 +49,10 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation("io.ktor:ktor-client-core:$ktorVersion") + implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") + runtimeOnly("io.ktor:ktor-client-core:$ktorVersion") + runtimeOnly("io.ktor:ktor-client-logging:$ktorVersion") + runtimeOnly("io.ktor:ktor-client-cio:$ktorVersion") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") } @@ -63,6 +66,7 @@ kotlin { val jvmMain by getting { dependencies { implementation("io.ktor:ktor-client-core-jvm:$ktorVersion") + runtimeOnly("io.ktor:ktor-client-cio-jvm:$ktorVersion") } } val jvmTest by getting { @@ -74,6 +78,7 @@ kotlin { val androidMain by getting { dependencies { implementation("io.ktor:ktor-client-core-jvm:$ktorVersion") + implementation("io.ktor:ktor-client-cio-jvm:$ktorVersion") } } val androidUnitTest by getting { @@ -84,18 +89,27 @@ kotlin { val iosMain by creating { dependsOn(commonMain) - dependencies { - implementation("io.ktor:ktor-client-ios:$ktorVersion") - } } val iosX64Main by getting { dependsOn(iosMain) + dependencies { + implementation("io.ktor:ktor-client-core-iosx64:$ktorVersion") + implementation("io.ktor:ktor-client-cio-iosx64:$ktorVersion") + } } val iosArm64Main by getting { dependsOn(iosMain) + dependencies { + implementation("io.ktor:ktor-client-core-iosarm64:$ktorVersion") + implementation("io.ktor:ktor-client-cio-iosarm64:$ktorVersion") + } } val iosSimulatorArm64Main by getting { dependsOn(iosMain) + dependencies { + implementation("io.ktor:ktor-client-core-iossimulatorarm64:$ktorVersion") + implementation("io.ktor:ktor-client-cio-iossimulatorarm64:$ktorVersion") + } } val iosTest by creating { diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt new file mode 100644 index 00000000..c9faeba2 --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt @@ -0,0 +1,34 @@ +package nl.zoe.httpclient + +import com.sphereon.oid.fed.openapi.models.EntityStatement +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.request.forms.* +import io.ktor.http.* +import io.ktor.http.HttpMethod.Companion.Get +import io.ktor.http.HttpMethod.Companion.Post + +class OidFederationClient( + private val client: HttpClient +) { + suspend fun fetchEntityStatement(url: String, httpMethod: HttpMethod = Get, parameters: Parameters = Parameters.Empty): EntityStatement { + return when (httpMethod) { + Get -> getEntityStatement(url) + Post -> postEntityStatement(url, parameters) + else -> throw IllegalArgumentException("Unsupported HTTP method: $httpMethod") + } + } + + private suspend fun getEntityStatement(url: String): EntityStatement { + return client.use { it.get(url).body() } + } + + private suspend fun postEntityStatement(url: String, parameters: Parameters): EntityStatement { + return client.use { + it.post(url) { + setBody(FormDataContent(parameters)) + }.body() + } + } +} \ No newline at end of file From 205cadbf458e4783bb60e8cd00e58b9821c79915 Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Mon, 22 Jul 2024 11:54:12 +0530 Subject: [PATCH 03/25] feat: Added OpenAPI maven local and added mapper for entity statement --- .../openid-federation-common/build.gradle.kts | 8 ++++++-- .../oid/fed/common/mapper/JsonMapperForJWT.kt | 20 +++++++++++++++++++ settings.gradle.kts | 4 +++- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt diff --git a/modules/openid-federation-common/build.gradle.kts b/modules/openid-federation-common/build.gradle.kts index 62762b20..566199d5 100644 --- a/modules/openid-federation-common/build.gradle.kts +++ b/modules/openid-federation-common/build.gradle.kts @@ -50,8 +50,8 @@ kotlin { val commonMain by getting { dependencies { implementation("io.ktor:ktor-client-core:$ktorVersion") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") + api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.1") } } val commonTest by getting { @@ -121,6 +121,10 @@ kotlin { } } +dependencies { + implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") +} + tasks.register("printSdkLocation") { doLast { println("Android SDK Location: ${android.sdkDirectory}") diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt new file mode 100644 index 00000000..fe2780da --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt @@ -0,0 +1,20 @@ +package com.sphereon.oid.fed.common.mapper + +import com.sphereon.oid.fed.openapi.models.EntityStatement +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromJsonElement + +class JsonMapperForJWT { + + /* + * Used for mapping JWT token to EntityStatement object + */ + fun mapToEntityStatement(jwtToken: String): EntityStatement? { + val data = decodeJWTComponents(jwtToken) + return if (data.second != null) { + Json.decodeFromJsonElement(data.second!!) + } else { + null + } + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 3a09b2cc..637f6fc3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -11,6 +11,7 @@ pluginManagement { } } mavenCentral() + mavenLocal() gradlePluginPortal() } } @@ -24,10 +25,11 @@ dependencyResolutionManagement { includeGroupAndSubgroups("com.google") } } + mavenLocal() mavenCentral() } } include(":modules:openid-federation-common") include(":modules:admin-server") -include(":modules:openapi") +include(":modules:openapi") \ No newline at end of file From de2f3943ffa456bc99a80493a411cc33ce37e513 Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Mon, 22 Jul 2024 17:41:14 +0530 Subject: [PATCH 04/25] chores: changed from implementation to api --- modules/openid-federation-common/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/openid-federation-common/build.gradle.kts b/modules/openid-federation-common/build.gradle.kts index fe686891..f460daab 100644 --- a/modules/openid-federation-common/build.gradle.kts +++ b/modules/openid-federation-common/build.gradle.kts @@ -50,8 +50,8 @@ kotlin { val commonMain by getting { dependencies { implementation("io.ktor:ktor-client-core:$ktorVersion") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") + api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.1") implementation(libs.kermit.logging) } } From ac2a0dc8b740fa5ba7dcea7ff80c27c285613002 Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Tue, 23 Jul 2024 17:58:50 +0530 Subject: [PATCH 05/25] chores: code cleanup --- .../openid-federation-common/build.gradle.kts | 8 +++----- .../oid/fed/common/mapper/JsonMapperForJWT.kt | 18 +++++++++--------- settings.gradle.kts | 1 - 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/modules/openid-federation-common/build.gradle.kts b/modules/openid-federation-common/build.gradle.kts index f460daab..68e78864 100644 --- a/modules/openid-federation-common/build.gradle.kts +++ b/modules/openid-federation-common/build.gradle.kts @@ -49,7 +49,9 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation("io.ktor:ktor-client-core:$ktorVersion") + //implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") + + api("io.ktor:ktor-client-core:$ktorVersion") api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.1") implementation(libs.kermit.logging) @@ -122,10 +124,6 @@ kotlin { } } -dependencies { - implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") -} - tasks.register("printSdkLocation") { doLast { println("Android SDK Location: ${android.sdkDirectory}") diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt index fe2780da..9e024e06 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt @@ -1,6 +1,6 @@ package com.sphereon.oid.fed.common.mapper -import com.sphereon.oid.fed.openapi.models.EntityStatement +//import com.sphereon.oid.fed.openapi.models.EntityStatement import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromJsonElement @@ -9,12 +9,12 @@ class JsonMapperForJWT { /* * Used for mapping JWT token to EntityStatement object */ - fun mapToEntityStatement(jwtToken: String): EntityStatement? { - val data = decodeJWTComponents(jwtToken) - return if (data.second != null) { - Json.decodeFromJsonElement(data.second!!) - } else { - null - } - } +// fun mapToEntityStatement(jwtToken: String): EntityStatement? { +// val data = decodeJWTComponents(jwtToken) +// return if (data.second != null) { +// Json.decodeFromJsonElement(data.second!!) +// } else { +// null +// } +// } } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 637f6fc3..66dd228a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -11,7 +11,6 @@ pluginManagement { } } mavenCentral() - mavenLocal() gradlePluginPortal() } } From 92d1cfa1bb44d1b45ce44894c85d0c6193a80bcd Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Tue, 23 Jul 2024 14:37:08 +0200 Subject: [PATCH 06/25] refactor: Made openid a KMM library. --- modules/openapi/build.gradle.kts | 162 ++++++++++++------ modules/openapi/gradle.properties | 2 +- .../com/sphereon/oid/fed/openapi/openapi.yaml | 0 .../openid-federation-common/build.gradle.kts | 73 ++++---- settings.gradle.kts | 2 + 5 files changed, 151 insertions(+), 88 deletions(-) rename modules/openapi/src/{main => commonMain}/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml (100%) diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index d8e95628..64c3a4ab 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -1,5 +1,8 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon +import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile + plugins { - kotlin("jvm") version "2.0.0" + kotlin("multiplatform") version "2.0.0" id("org.openapi.generator") version "7.7.0" id("maven-publish") } @@ -17,66 +20,121 @@ repositories { mavenCentral() } -dependencies { - implementation("io.ktor:ktor-client-core:$ktorVersion") - implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") - implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") -} +kotlin { + tasks { + withType { + dependsOn("openApiGenerate") + } + named("sourcesJar") { + dependsOn("openApiGenerate") + } + } + jvm { + tasks { + openApiGenerate { + val openApiPackage: String by project + generatorName.set("kotlin") + packageName.set("com.sphereon.oid.fed.openapi") + apiPackage.set("$openApiPackage.api") + modelPackage.set("$openApiPackage.models") + inputSpec.set("$projectDir/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml") + library.set("multiplatform") + outputDir.set("$projectDir/build/generated") + configOptions.set( + mapOf( + "dateLibrary" to "string" + ) + ) -openApiGenerate { - val openApiPackage: String by project - generatorName.set("kotlin") - packageName.set("com.sphereon.oid.fed.openapi") - apiPackage.set("$openApiPackage.api") - modelPackage.set("$openApiPackage.models") - inputSpec.set("$projectDir/src/main/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml") - library.set("multiplatform") - outputDir.set("$projectDir/build/generated") -configOptions.set( - mapOf( - "dateLibrary" to "string" - ) - ) + if (isModelsOnlyProfile) { + globalProperties.set( + configOptions.get().plus( + mapOf( + "models" to "" + ) + ) + ) + } + } - if (isModelsOnlyProfile) { - globalProperties.set( - configOptions.get().plus( - mapOf( - "models" to "" - ) - ) - ) - } -} + named("compileKotlinJvm") { + dependsOn("openApiGenerate") + } + named("jvmSourcesJar") { + dependsOn("openApiGenerate") + } -publishing { - publications { - create("mavenKotlin") { - from(components["kotlin"]) + named("jvmJar") { + dependsOn("compileKotlinJvm") + archiveBaseName.set("openapi") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from(configurations.kotlinCompilerClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) + from("$projectDir/build/classes/kotlin/jvm/main") + } } } -} -tasks.compileKotlin { - dependsOn(tasks.openApiGenerate) -} + js { + tasks { + named("compileKotlinJs") { + dependsOn("openApiGenerate") + } + named("jsSourcesJar") { + dependsOn("openApiGenerate") + } + } + nodejs() + } + + iosX64 { + tasks { + named("compileKotlinIosX64") { + dependsOn("openApiGenerate") + } + named("iosX64SourcesJar") { + dependsOn("openApiGenerate") + } + } + } + iosArm64 { + tasks { + named("compileKotlinIosArm64") { + dependsOn("openApiGenerate") + } + named("iosArm64SourcesJar") { + dependsOn("openApiGenerate") + } + } + } + iosSimulatorArm64 { + tasks { + named("compileKotlinIosSimulatorArm64") { + dependsOn("openApiGenerate") + } + named("iosSimulatorArm64SourcesJar") { + dependsOn("openApiGenerate") + } + } + } -tasks.jar { - dependsOn(tasks.compileKotlin) - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - archiveBaseName.set(project.name) - from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) - from("$projectDir/build/classes/kotlin/main") + sourceSets { + val commonMain by getting { + kotlin.srcDir("build/generated/src/commonMain/kotlin") + dependencies { + implementation("io.ktor:ktor-client-core:$ktorVersion") + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") + } + } + } } -kotlin { - sourceSets.main { - kotlin.srcDirs( - "$projectDir/build/generated/src/commonMain/kotlin" - ) +publishing { + publications { + create("mavenKotlin") { + from(components["kotlin"]) + } } - jvmToolchain(21) } diff --git a/modules/openapi/gradle.properties b/modules/openapi/gradle.properties index 08d60d78..33cf166a 100644 --- a/modules/openapi/gradle.properties +++ b/modules/openapi/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style=official -#profiles=models-only +profiles=models-only diff --git a/modules/openapi/src/main/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml b/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml similarity index 100% rename from modules/openapi/src/main/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml rename to modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml diff --git a/modules/openid-federation-common/build.gradle.kts b/modules/openid-federation-common/build.gradle.kts index 0f402dfd..39241a06 100644 --- a/modules/openid-federation-common/build.gradle.kts +++ b/modules/openid-federation-common/build.gradle.kts @@ -40,9 +40,9 @@ kotlin { } } - iosX64() - iosArm64() - iosSimulatorArm64() +// iosX64() +// iosArm64() +// iosSimulatorArm64() jvm() @@ -50,7 +50,7 @@ kotlin { val commonMain by getting { dependencies { implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") - runtimeOnly("io.ktor:ktor-client-core:$ktorVersion") + implementation("io.ktor:ktor-client-core:$ktorVersion") runtimeOnly("io.ktor:ktor-client-logging:$ktorVersion") runtimeOnly("io.ktor:ktor-client-cio:$ktorVersion") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") @@ -88,37 +88,40 @@ kotlin { } } - val iosMain by creating { - dependsOn(commonMain) - } - val iosX64Main by getting { - dependsOn(iosMain) - dependencies { - implementation("io.ktor:ktor-client-core-iosx64:$ktorVersion") - implementation("io.ktor:ktor-client-cio-iosx64:$ktorVersion") - } - } - val iosArm64Main by getting { - dependsOn(iosMain) - dependencies { - implementation("io.ktor:ktor-client-core-iosarm64:$ktorVersion") - implementation("io.ktor:ktor-client-cio-iosarm64:$ktorVersion") - } - } - val iosSimulatorArm64Main by getting { - dependsOn(iosMain) - dependencies { - implementation("io.ktor:ktor-client-core-iossimulatorarm64:$ktorVersion") - implementation("io.ktor:ktor-client-cio-iossimulatorarm64:$ktorVersion") - } - } - - val iosTest by creating { - dependsOn(commonTest) - dependencies { - implementation(kotlin("test")) - } - } +// val iosMain by creating { +// dependsOn(commonMain) +// dependencies { +// +// } +// } +// val iosX64Main by getting { +// //dependsOn(iosMain) +// dependencies { +// implementation("io.ktor:ktor-client-core-iosx64:$ktorVersion") +// implementation("io.ktor:ktor-client-cio-iosx64:$ktorVersion") +// } +// } +// val iosArm64Main by getting { +// dependsOn(iosX64Main) +// dependencies { +// implementation("io.ktor:ktor-client-core-iosarm64:$ktorVersion") +// implementation("io.ktor:ktor-client-cio-iosarm64:$ktorVersion") +// } +// } +// val iosSimulatorArm64Main by getting { +// dependsOn(iosX64Main) +// dependencies { +// implementation("io.ktor:ktor-client-core-iossimulatorarm64:$ktorVersion") +// implementation("io.ktor:ktor-client-cio-iossimulatorarm64:$ktorVersion") +// } +// } +// +// val iosTest by creating { +// dependsOn(commonTest) +// dependencies { +// implementation(kotlin("test")) +// } +// } val jsMain by getting { dependencies { diff --git a/settings.gradle.kts b/settings.gradle.kts index 3a09b2cc..62604efb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,7 @@ pluginManagement { includeGroupAndSubgroups("com.google") } } + mavenLocal() mavenCentral() gradlePluginPortal() } @@ -24,6 +25,7 @@ dependencyResolutionManagement { includeGroupAndSubgroups("com.google") } } + mavenLocal() mavenCentral() } } From 7590c054cecd7a11872b3ceb7fb80b83a2b44f7c Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Tue, 23 Jul 2024 15:01:57 +0200 Subject: [PATCH 07/25] fix: Fixed ktor-client-cio issue --- .../openid-federation-common/build.gradle.kts | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/modules/openid-federation-common/build.gradle.kts b/modules/openid-federation-common/build.gradle.kts index 39241a06..028874bd 100644 --- a/modules/openid-federation-common/build.gradle.kts +++ b/modules/openid-federation-common/build.gradle.kts @@ -40,9 +40,9 @@ kotlin { } } -// iosX64() -// iosArm64() -// iosSimulatorArm64() + iosX64() + iosArm64() + iosSimulatorArm64() jvm() @@ -50,9 +50,8 @@ kotlin { val commonMain by getting { dependencies { implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") - implementation("io.ktor:ktor-client-core:$ktorVersion") + runtimeOnly("io.ktor:ktor-client-core:$ktorVersion") runtimeOnly("io.ktor:ktor-client-logging:$ktorVersion") - runtimeOnly("io.ktor:ktor-client-cio:$ktorVersion") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") implementation(libs.kermit.logging) @@ -88,44 +87,45 @@ kotlin { } } -// val iosMain by creating { -// dependsOn(commonMain) -// dependencies { -// -// } -// } -// val iosX64Main by getting { -// //dependsOn(iosMain) -// dependencies { -// implementation("io.ktor:ktor-client-core-iosx64:$ktorVersion") -// implementation("io.ktor:ktor-client-cio-iosx64:$ktorVersion") -// } -// } -// val iosArm64Main by getting { -// dependsOn(iosX64Main) -// dependencies { -// implementation("io.ktor:ktor-client-core-iosarm64:$ktorVersion") -// implementation("io.ktor:ktor-client-cio-iosarm64:$ktorVersion") -// } -// } -// val iosSimulatorArm64Main by getting { -// dependsOn(iosX64Main) -// dependencies { -// implementation("io.ktor:ktor-client-core-iossimulatorarm64:$ktorVersion") -// implementation("io.ktor:ktor-client-cio-iossimulatorarm64:$ktorVersion") -// } -// } -// -// val iosTest by creating { -// dependsOn(commonTest) -// dependencies { -// implementation(kotlin("test")) -// } -// } + val iosMain by creating { + dependsOn(commonMain) + dependencies { + + } + } + val iosX64Main by getting { + //dependsOn(iosMain) + dependencies { + implementation("io.ktor:ktor-client-core-iosx64:$ktorVersion") + implementation("io.ktor:ktor-client-cio-iosx64:$ktorVersion") + } + } + val iosArm64Main by getting { + dependsOn(iosX64Main) + dependencies { + implementation("io.ktor:ktor-client-core-iosarm64:$ktorVersion") + implementation("io.ktor:ktor-client-cio-iosarm64:$ktorVersion") + } + } + val iosSimulatorArm64Main by getting { + dependsOn(iosX64Main) + dependencies { + implementation("io.ktor:ktor-client-core-iossimulatorarm64:$ktorVersion") + implementation("io.ktor:ktor-client-cio-iossimulatorarm64:$ktorVersion") + } + } + + val iosTest by creating { + dependsOn(commonTest) + dependencies { + implementation(kotlin("test")) + } + } val jsMain by getting { dependencies { - implementation("io.ktor:ktor-client-js:$ktorVersion") + runtimeOnly("io.ktor:ktor-client-core-js:$ktorVersion") + runtimeOnly("io.ktor:ktor-client-js:$ktorVersion") } } From 3e8e7c408f6a3a4a03a0b9b69f5d49ca4fa2a7c5 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Tue, 23 Jul 2024 15:07:30 +0200 Subject: [PATCH 08/25] fix: Changed the models jvm target to 11 --- modules/openapi/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index 64c3a4ab..ce5f5fef 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -1,3 +1,4 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile @@ -59,6 +60,9 @@ kotlin { named("compileKotlinJvm") { dependsOn("openApiGenerate") + compilerOptions { + jvmTarget.set(JvmTarget.JVM_11) + } } named("jvmSourcesJar") { From 6dcd541852044dfa9d5beea4f95826f0041c73b8 Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Wed, 24 Jul 2024 12:25:30 +0530 Subject: [PATCH 09/25] bugfix: Fixed OpenAPI model import issue --- modules/openapi/build.gradle.kts | 166 ++++++++++++------ modules/openapi/gradle.properties | 2 +- .../com/sphereon/oid/fed/openapi/openapi.yaml | 0 .../openid-federation-common/build.gradle.kts | 10 +- .../oid/fed/common/mapper/JsonMapper.kt | 20 +++ .../oid/fed/common/mapper/JsonMapperForJWT.kt | 20 --- settings.gradle.kts | 1 + 7 files changed, 141 insertions(+), 78 deletions(-) rename modules/openapi/src/{main => commonMain}/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml (100%) create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt delete mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index d8e95628..ce5f5fef 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -1,5 +1,9 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon +import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile + plugins { - kotlin("jvm") version "2.0.0" + kotlin("multiplatform") version "2.0.0" id("org.openapi.generator") version "7.7.0" id("maven-publish") } @@ -17,66 +21,124 @@ repositories { mavenCentral() } -dependencies { - implementation("io.ktor:ktor-client-core:$ktorVersion") - implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") - implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") -} +kotlin { + tasks { + withType { + dependsOn("openApiGenerate") + } + named("sourcesJar") { + dependsOn("openApiGenerate") + } + } + jvm { + tasks { + openApiGenerate { + val openApiPackage: String by project + generatorName.set("kotlin") + packageName.set("com.sphereon.oid.fed.openapi") + apiPackage.set("$openApiPackage.api") + modelPackage.set("$openApiPackage.models") + inputSpec.set("$projectDir/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml") + library.set("multiplatform") + outputDir.set("$projectDir/build/generated") + configOptions.set( + mapOf( + "dateLibrary" to "string" + ) + ) -openApiGenerate { - val openApiPackage: String by project - generatorName.set("kotlin") - packageName.set("com.sphereon.oid.fed.openapi") - apiPackage.set("$openApiPackage.api") - modelPackage.set("$openApiPackage.models") - inputSpec.set("$projectDir/src/main/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml") - library.set("multiplatform") - outputDir.set("$projectDir/build/generated") -configOptions.set( - mapOf( - "dateLibrary" to "string" - ) - ) + if (isModelsOnlyProfile) { + globalProperties.set( + configOptions.get().plus( + mapOf( + "models" to "" + ) + ) + ) + } + } - if (isModelsOnlyProfile) { - globalProperties.set( - configOptions.get().plus( - mapOf( - "models" to "" - ) - ) - ) - } -} + named("compileKotlinJvm") { + dependsOn("openApiGenerate") + compilerOptions { + jvmTarget.set(JvmTarget.JVM_11) + } + } + named("jvmSourcesJar") { + dependsOn("openApiGenerate") + } -publishing { - publications { - create("mavenKotlin") { - from(components["kotlin"]) + named("jvmJar") { + dependsOn("compileKotlinJvm") + archiveBaseName.set("openapi") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from(configurations.kotlinCompilerClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) + from("$projectDir/build/classes/kotlin/jvm/main") + } } } -} -tasks.compileKotlin { - dependsOn(tasks.openApiGenerate) -} + js { + tasks { + named("compileKotlinJs") { + dependsOn("openApiGenerate") + } + named("jsSourcesJar") { + dependsOn("openApiGenerate") + } + } + nodejs() + } + + iosX64 { + tasks { + named("compileKotlinIosX64") { + dependsOn("openApiGenerate") + } + named("iosX64SourcesJar") { + dependsOn("openApiGenerate") + } + } + } + iosArm64 { + tasks { + named("compileKotlinIosArm64") { + dependsOn("openApiGenerate") + } + named("iosArm64SourcesJar") { + dependsOn("openApiGenerate") + } + } + } + iosSimulatorArm64 { + tasks { + named("compileKotlinIosSimulatorArm64") { + dependsOn("openApiGenerate") + } + named("iosSimulatorArm64SourcesJar") { + dependsOn("openApiGenerate") + } + } + } -tasks.jar { - dependsOn(tasks.compileKotlin) - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - archiveBaseName.set(project.name) - from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) - from("$projectDir/build/classes/kotlin/main") + sourceSets { + val commonMain by getting { + kotlin.srcDir("build/generated/src/commonMain/kotlin") + dependencies { + implementation("io.ktor:ktor-client-core:$ktorVersion") + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") + } + } + } } -kotlin { - sourceSets.main { - kotlin.srcDirs( - "$projectDir/build/generated/src/commonMain/kotlin" - ) +publishing { + publications { + create("mavenKotlin") { + from(components["kotlin"]) + } } - jvmToolchain(21) } diff --git a/modules/openapi/gradle.properties b/modules/openapi/gradle.properties index 08d60d78..33cf166a 100644 --- a/modules/openapi/gradle.properties +++ b/modules/openapi/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style=official -#profiles=models-only +profiles=models-only diff --git a/modules/openapi/src/main/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml b/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml similarity index 100% rename from modules/openapi/src/main/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml rename to modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml diff --git a/modules/openid-federation-common/build.gradle.kts b/modules/openid-federation-common/build.gradle.kts index 68e78864..2c1fee9a 100644 --- a/modules/openid-federation-common/build.gradle.kts +++ b/modules/openid-federation-common/build.gradle.kts @@ -49,11 +49,11 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - //implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") - - api("io.ktor:ktor-client-core:$ktorVersion") - api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") - api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.1") + implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") + implementation("io.ktor:ktor-client-core:$ktorVersion") + implementation("io.ktor:ktor-client-logging:$ktorVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") implementation(libs.kermit.logging) } } diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt new file mode 100644 index 00000000..192ae769 --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt @@ -0,0 +1,20 @@ +package com.sphereon.oid.fed.common.mapper + +import com.sphereon.oid.fed.openapi.models.EntityStatement +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromJsonElement + +class JsonMapper { + + /* + * Used for mapping JWT token to EntityStatement object + */ + fun mapEntityStatement(jwtToken: String): EntityStatement? { + val data = decodeJWTComponents(jwtToken) + return if (data.second != null) { + Json.decodeFromJsonElement(data.second!!) + } else { + null + } + } +} \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt deleted file mode 100644 index 9e024e06..00000000 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperForJWT.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.sphereon.oid.fed.common.mapper - -//import com.sphereon.oid.fed.openapi.models.EntityStatement -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromJsonElement - -class JsonMapperForJWT { - - /* - * Used for mapping JWT token to EntityStatement object - */ -// fun mapToEntityStatement(jwtToken: String): EntityStatement? { -// val data = decodeJWTComponents(jwtToken) -// return if (data.second != null) { -// Json.decodeFromJsonElement(data.second!!) -// } else { -// null -// } -// } -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 66dd228a..05458317 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,7 @@ pluginManagement { includeGroupAndSubgroups("com.google") } } + mavenLocal() mavenCentral() gradlePluginPortal() } From c5cb2c050dc7bfba0ae9071895a7d686c69e3e79 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Wed, 24 Jul 2024 15:49:45 +0200 Subject: [PATCH 10/25] fix: Fixed serialization issue and Open Api Generator bug --- modules/openapi/build.gradle.kts | 48 +++++++---- modules/openapi/gradle.properties | 2 +- .../openid-federation-common/build.gradle.kts | 82 ++++++++++--------- .../common/httpclient/OidFederationClient.kt | 40 ++++++++- .../httpclient/OidFederationClientTest.kt | 46 +++++++++++ 5 files changed, 161 insertions(+), 57 deletions(-) create mode 100644 modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index ce5f5fef..7d913327 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -4,6 +4,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { kotlin("multiplatform") version "2.0.0" + kotlin("plugin.serialization") version "2.0.0" id("org.openapi.generator") version "7.7.0" id("maven-publish") } @@ -23,11 +24,26 @@ repositories { kotlin { tasks { + // Temporary fix for this issue: https://github.com/OpenAPITools/openapi-generator/issues/17658 + register("fixOpenApiGeneratorIssue") { + from( + "$projectDir/build/generated/src/commonMain/kotlin/com/sphereon/oid/fed/openapi" + ) + into( + "$projectDir/build/copy/src/commonMain/kotlin/com/sphereon/oid/fed/openapi" + ) + filter { line: String -> + line.replace( + "kotlin.collections.Map", + "kotlinx.serialization.json.JsonObject") + } + } + withType { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("sourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } jvm { @@ -58,19 +74,23 @@ kotlin { } } - named("compileKotlinJvm") { + named("fixOpenApiGeneratorIssue") { dependsOn("openApiGenerate") + } + + named("compileKotlinJvm") { + dependsOn("fixOpenApiGeneratorIssue") compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } } named("jvmSourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("jvmJar") { - dependsOn("compileKotlinJvm") + dependsOn("fixOpenApiGeneratorIssue") archiveBaseName.set("openapi") duplicatesStrategy = DuplicatesStrategy.EXCLUDE from(configurations.kotlinCompilerClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) @@ -82,10 +102,10 @@ kotlin { js { tasks { named("compileKotlinJs") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("jsSourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } nodejs() @@ -94,37 +114,37 @@ kotlin { iosX64 { tasks { named("compileKotlinIosX64") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("iosX64SourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } } iosArm64 { tasks { named("compileKotlinIosArm64") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("iosArm64SourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } } iosSimulatorArm64 { tasks { named("compileKotlinIosSimulatorArm64") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("iosSimulatorArm64SourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } } sourceSets { val commonMain by getting { - kotlin.srcDir("build/generated/src/commonMain/kotlin") + kotlin.srcDir("build/copy/src/commonMain/kotlin") dependencies { implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") diff --git a/modules/openapi/gradle.properties b/modules/openapi/gradle.properties index 33cf166a..08d60d78 100644 --- a/modules/openapi/gradle.properties +++ b/modules/openapi/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style=official -profiles=models-only +#profiles=models-only diff --git a/modules/openid-federation-common/build.gradle.kts b/modules/openid-federation-common/build.gradle.kts index 028874bd..3e9d899b 100644 --- a/modules/openid-federation-common/build.gradle.kts +++ b/modules/openid-federation-common/build.gradle.kts @@ -40,9 +40,9 @@ kotlin { } } - iosX64() - iosArm64() - iosSimulatorArm64() +// iosX64() +// iosArm64() +// iosSimulatorArm64() jvm() @@ -50,8 +50,11 @@ kotlin { val commonMain by getting { dependencies { implementation("com.sphereon.oid.fed:openapi:0.1.0-SNAPSHOT") - runtimeOnly("io.ktor:ktor-client-core:$ktorVersion") - runtimeOnly("io.ktor:ktor-client-logging:$ktorVersion") + implementation("io.ktor:ktor-client-core:$ktorVersion") + implementation("io.ktor:ktor-client-logging:$ktorVersion") + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-client-auth:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") implementation(libs.kermit.logging) @@ -61,6 +64,7 @@ kotlin { dependencies { implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) + implementation("io.ktor:ktor-client-mock:$ktorVersion") } } val jvmMain by getting { @@ -87,40 +91,40 @@ kotlin { } } - val iosMain by creating { - dependsOn(commonMain) - dependencies { - - } - } - val iosX64Main by getting { - //dependsOn(iosMain) - dependencies { - implementation("io.ktor:ktor-client-core-iosx64:$ktorVersion") - implementation("io.ktor:ktor-client-cio-iosx64:$ktorVersion") - } - } - val iosArm64Main by getting { - dependsOn(iosX64Main) - dependencies { - implementation("io.ktor:ktor-client-core-iosarm64:$ktorVersion") - implementation("io.ktor:ktor-client-cio-iosarm64:$ktorVersion") - } - } - val iosSimulatorArm64Main by getting { - dependsOn(iosX64Main) - dependencies { - implementation("io.ktor:ktor-client-core-iossimulatorarm64:$ktorVersion") - implementation("io.ktor:ktor-client-cio-iossimulatorarm64:$ktorVersion") - } - } - - val iosTest by creating { - dependsOn(commonTest) - dependencies { - implementation(kotlin("test")) - } - } +// val iosMain by creating { +// dependsOn(commonMain) +// dependencies { +// implementation("io.ktor:ktor-client-core-ios:$ktorVersion") +// } +// } +// val iosX64Main by getting { +// dependsOn(iosMain) +// dependencies { +// implementation("io.ktor:ktor-client-core-iosx64:$ktorVersion") +// implementation("io.ktor:ktor-client-cio-iosx64:$ktorVersion") +// } +// } +// val iosArm64Main by getting { +// dependsOn(iosMain) +// dependencies { +// implementation("io.ktor:ktor-client-core-iosarm64:$ktorVersion") +// implementation("io.ktor:ktor-client-cio-iosarm64:$ktorVersion") +// } +// } +// val iosSimulatorArm64Main by getting { +// dependsOn(iosMain) +// dependencies { +// implementation("io.ktor:ktor-client-core-iossimulatorarm64:$ktorVersion") +// implementation("io.ktor:ktor-client-cio-iossimulatorarm64:$ktorVersion") +// } +// } + +// val iosTest by creating { +// dependsOn(commonTest) +// dependencies { +// implementation(kotlin("test")) +// } +// } val jsMain by getting { dependencies { diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt index c9faeba2..6fa78a6b 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt @@ -1,17 +1,51 @@ -package nl.zoe.httpclient +package com.sphereon.oid.fed.common.httpclient import com.sphereon.oid.fed.openapi.models.EntityStatement import io.ktor.client.* import io.ktor.client.call.* +import io.ktor.client.engine.* +import io.ktor.client.plugins.auth.* +import io.ktor.client.plugins.auth.providers.* +import io.ktor.client.plugins.cache.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.plugins.logging.* import io.ktor.client.request.* import io.ktor.client.request.forms.* import io.ktor.http.* import io.ktor.http.HttpMethod.Companion.Get import io.ktor.http.HttpMethod.Companion.Post +import io.ktor.serialization.kotlinx.json.* +import io.ktor.utils.io.core.* class OidFederationClient( - private val client: HttpClient + engine: HttpClientEngine, + isRequestAuthenticated: Boolean = false, + isRequestCached: Boolean = false ) { + private val client: HttpClient = HttpClient(engine) { + install(HttpCache) + install(ContentNegotiation) { + json() + } + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.INFO + } + if (isRequestAuthenticated) { + install(Auth) { + bearer { + loadTokens { + //TODO add correct implementation later + BearerTokens("accessToken", "refreshToken") + } + } + } + } + if (isRequestCached) { + install(HttpCache) + } + } + suspend fun fetchEntityStatement(url: String, httpMethod: HttpMethod = Get, parameters: Parameters = Parameters.Empty): EntityStatement { return when (httpMethod) { Get -> getEntityStatement(url) @@ -31,4 +65,4 @@ class OidFederationClient( }.body() } } -} \ No newline at end of file +} diff --git a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt new file mode 100644 index 00000000..19925cd4 --- /dev/null +++ b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt @@ -0,0 +1,46 @@ +package com.sphereon.oid.fed.common.httpclient + +import com.sphereon.oid.fed.openapi.models.EntityStatement +import com.sphereon.oid.fed.openapi.models.FederationEntityMetadata +import com.sphereon.oid.fed.openapi.models.Metadata +import io.ktor.client.engine.mock.* +import io.ktor.http.* +import io.ktor.utils.io.* +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import kotlin.test.Test + +class OidFederationClientTest { + + private val entityStatement = EntityStatement( + iss = "test_iss", + sub = "test_sub", + metadata = Metadata( + federationEntity = FederationEntityMetadata( + federationListEndpoint = "http://www.example.com/list", + federationResolveEndpoint = "http://www.example.com/resolve", + organizationName = "test organization", + homepageUri = "http://www.example.com", + federationFetchEndpoint = "http://www.example.com/fetch", + ) + ) + ) + + private val mockEngine = MockEngine { + respond( + content = ByteReadChannel(Json.encodeToString(entityStatement)), + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + @Test + fun testGetEntityStatement() { + runBlocking { + val client = OidFederationClient(mockEngine) + val response = client.fetchEntityStatement("test_iss", HttpMethod.Get) + assert(response == entityStatement) + } + } +} \ No newline at end of file From a3fef171eed722a308093b057085ce757ddbdca8 Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Thu, 25 Jul 2024 12:31:59 +0530 Subject: [PATCH 11/25] feat: Added mapping for trust chain and categorize entity statement --- modules/openapi/build.gradle.kts | 48 +++++++++++----- modules/openapi/gradle.properties | 2 +- .../oid/fed/common/logic/EntityLogic.kt | 33 +++++++++++ .../oid/fed/common/mapper/JsonMapper.kt | 13 ++++- .../oid/fed/common/model/JWTHeader.kt | 3 +- .../oid/fed/common/logic/EntityLogicTest.kt | 56 +++++++++++++++++++ 6 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt create mode 100644 modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/EntityLogicTest.kt diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index ce5f5fef..7d913327 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -4,6 +4,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { kotlin("multiplatform") version "2.0.0" + kotlin("plugin.serialization") version "2.0.0" id("org.openapi.generator") version "7.7.0" id("maven-publish") } @@ -23,11 +24,26 @@ repositories { kotlin { tasks { + // Temporary fix for this issue: https://github.com/OpenAPITools/openapi-generator/issues/17658 + register("fixOpenApiGeneratorIssue") { + from( + "$projectDir/build/generated/src/commonMain/kotlin/com/sphereon/oid/fed/openapi" + ) + into( + "$projectDir/build/copy/src/commonMain/kotlin/com/sphereon/oid/fed/openapi" + ) + filter { line: String -> + line.replace( + "kotlin.collections.Map", + "kotlinx.serialization.json.JsonObject") + } + } + withType { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("sourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } jvm { @@ -58,19 +74,23 @@ kotlin { } } - named("compileKotlinJvm") { + named("fixOpenApiGeneratorIssue") { dependsOn("openApiGenerate") + } + + named("compileKotlinJvm") { + dependsOn("fixOpenApiGeneratorIssue") compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } } named("jvmSourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("jvmJar") { - dependsOn("compileKotlinJvm") + dependsOn("fixOpenApiGeneratorIssue") archiveBaseName.set("openapi") duplicatesStrategy = DuplicatesStrategy.EXCLUDE from(configurations.kotlinCompilerClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) @@ -82,10 +102,10 @@ kotlin { js { tasks { named("compileKotlinJs") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("jsSourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } nodejs() @@ -94,37 +114,37 @@ kotlin { iosX64 { tasks { named("compileKotlinIosX64") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("iosX64SourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } } iosArm64 { tasks { named("compileKotlinIosArm64") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("iosArm64SourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } } iosSimulatorArm64 { tasks { named("compileKotlinIosSimulatorArm64") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } named("iosSimulatorArm64SourcesJar") { - dependsOn("openApiGenerate") + dependsOn("fixOpenApiGeneratorIssue") } } } sourceSets { val commonMain by getting { - kotlin.srcDir("build/generated/src/commonMain/kotlin") + kotlin.srcDir("build/copy/src/commonMain/kotlin") dependencies { implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") diff --git a/modules/openapi/gradle.properties b/modules/openapi/gradle.properties index 33cf166a..08d60d78 100644 --- a/modules/openapi/gradle.properties +++ b/modules/openapi/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style=official -profiles=models-only +#profiles=models-only diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt new file mode 100644 index 00000000..ac937fa1 --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt @@ -0,0 +1,33 @@ +package com.sphereon.oid.fed.common.logic + +import com.sphereon.oid.fed.openapi.models.EntityStatement + +class EntityLogic { + + fun getEntityType(entityStatement: EntityStatement): EntityType { + if (isFederationListEndpointPresent(entityStatement) == true && isAuthorityHintPresent(entityStatement) == false) { + return EntityType.TRUST_ANCHOR + } else if (isFederationListEndpointPresent(entityStatement) == true && isAuthorityHintPresent(entityStatement) == true) { + return EntityType.INTERMEDIATE + } else if (isFederationListEndpointPresent(entityStatement) == false && isAuthorityHintPresent(entityStatement) == true) { + return EntityType.LEAF + } else { + return EntityType.UNDEFINED + } + } + + private fun isAuthorityHintPresent(entityStatement: EntityStatement): Boolean { + return entityStatement.authorityHints?.isEmpty() == false + } + + private fun isFederationListEndpointPresent(entityStatement: EntityStatement): Boolean { + return entityStatement.metadata?.federationEntity?.federationListEndpoint?.isNotEmpty() == true + } +} + +enum class EntityType { + LEAF, + INTERMEDIATE, + TRUST_ANCHOR, + UNDEFINED +} \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt index 192ae769..bc504a52 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt @@ -7,7 +7,7 @@ import kotlinx.serialization.json.decodeFromJsonElement class JsonMapper { /* - * Used for mapping JWT token to EntityStatement object + * Used for mapping JWT token to EntityStatement object */ fun mapEntityStatement(jwtToken: String): EntityStatement? { val data = decodeJWTComponents(jwtToken) @@ -17,4 +17,15 @@ class JsonMapper { null } } + + /* + * Used for mapping trust chain + */ + fun mapTrustChain(jwtTokenList: List): List { + val list: MutableList = mutableListOf() + jwtTokenList.forEach { jwtToken -> + list.add(mapEntityStatement(jwtToken)) + } + return list + } } \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt index 1cdd0f26..b1937f06 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt @@ -8,5 +8,6 @@ import kotlinx.serialization.SerialName data class JWTHeader( @SerialName("alg") val alg: String, // RS256 @SerialName("kid") val kid: String, // B6EB8488CC84C41017134BC77F4132A0467CCC0E - @SerialName("typ") val typ: String // entity-statement+jwt + @SerialName("typ") val typ: String? = null, // entity-statement+jwt + @SerialName("trust_chain") val trustChain: List? = null // ["eyJhbGciOiJSUzI1NiIsImtpZCI6IlpXRlRRbWhmVFdaSVRuRlRZM0ZTV2pKdU5HMWZWV05hZWxkNmNtUjFRa0pEYlhaWlRYQm1hM1JWUVEiLCJ0eXAiOiJlbnRpdHktc3RhdGVtZW50K2p3dCJ9.eyJleHAiOjE2OTY1ODMzMzQsImlhdCI6MTY5NjI4MzMzNCwiaXNzIjoiaHR0cHM6Ly90cnVzdC1hbmNob3IuZXhhbXBsZS5vcmciLCJzdWIiOiJodHRwczovL2ludGVybWVkaWF0ZS5laWRhcy5leGFtcGxlLm9yZyIsImp3a3MiOnsia2V5cyI6W3sia3R5IjoiUlNBIiwia2lkIjoiWmxKd05tNDVUMmxVY1hsSFRHZzFaV2hsYmxkalVXbGxjbVF0U1VsUVdYcEhTMUpFUTA4eVRXVnZOQSIsImUiOiJBUUFCIiwibiI6ImtSQUlzLVRBblF6T29lc195RW9oaDNUeGlaWFlPRC1xekI2T25JalZCaVI0WFNGbkw4djhRQ0IxamJiSlZTQ1hBZmdObTlBZjdVRDNBX0E2T1pQOUtacldSUk00NEp0TVAzZmxVSU5CQ2xzNFBrdVd2RklmWEtaaWVUNGhBMzNYdUlTSndqT2NlNnRrbUZTUl9wQmI3S0JHbnB4d3dnRlJjeUM2RU1VQWtWUGdQRl9mbXM3NEEyTF83TGVaNzh2X053VUhsY2VxVHB1OUx6VTRuTTd1RTZQY0JPSmJweXI2SFFuUTR1VHN6WThsWHVmT3pHZ2IzVXNDNmRnQWVVVERIZlFROE4xYXV2bkJUNmR0SHNHNWMxS2NCT2QzLVp6ZTZ5WVE5c2JLUlUtWVoydDZKdUJIbS1xLTVOamxiRWVwNDAwbFgxSXlKdG9Tc3F0d3lCX1djdyJ9XX19.CvBvN0aG-r13UG4uITH72tC5CbAG0rT4qYQ5wwHOtGE021etZFQd40RFnQT5e-Gy_Y8Wiin-Zmc1hWW2rVyZ1RRInjYGUt26QI6ujR-5w9Y_LHVp-6RzYEF0lg9otpAyszQE4hf5qBZYAj8t39FvCYWTYVci6mtpovJQ380ha8I4QL__fZtEgDLQ-7VKS58nN1DOVdcIICMMfxpDR81bkY5i5Qxcy7AaZTN6xxE2SlCO-pKKub0jBUtnug20-BL2YgcPhLFOYWfj2cuyapOA9Omwu6CPhmZHgsL1P2oK_f4jA9JxNDYcV0losDbD86r8Wg3anM2lVM5BTHkiUr2grg"] ) \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/EntityLogicTest.kt b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/EntityLogicTest.kt new file mode 100644 index 00000000..7ba05790 --- /dev/null +++ b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/EntityLogicTest.kt @@ -0,0 +1,56 @@ +package com.sphereon.oid.fed.common.logic + +import com.sphereon.oid.fed.openapi.models.EntityStatement +import com.sphereon.oid.fed.openapi.models.Metadata +import kotlinx.serialization.json.Json +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class EntityLogicTest { + + private val leafEntityString = """{"metadata":{"openid_relying_party":{"client_registration_types":["automatic"],"client_name":"JESISERVIZI SRL","grant_types":["authorization_code","refresh_token"],"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]},"redirect_uris":["https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/callback"],"response_types":["code"],"client_id":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","id_token_signed_response_alg":"RS256","id_token_encrypted_response_alg":"RSA-OAEP","id_token_encrypted_response_enc":"A256CBC-HS512","userinfo_signed_response_alg":"RS256","userinfo_encrypted_response_alg":"RSA-OAEP","userinfo_encrypted_response_enc":"A256CBC-HS512","token_endpoint_auth_method":"private_key_jwt"},"federation_entity":{"contacts":["jesiservizi@pec.it"],"organization_name":"JESISERVIZI SRL","homepage_uri":"https://cohesion2.regione.marche.it","policy_uri":"https://www.regione.marche.it/Privacy","logo_uri":"https://cohesion2.regione.marche.it/Common/assets/images/cohesion.svg","federation_resolve_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/resolve"}},"trust_marks":[{"id":"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public","iss":"https://cohesion2.regione.marche.it/oidc/sa/","trust_mark":"eyJ0eXAiOiJ0cnVzdC1tYXJrXHUwMDJCand0Iiwia2lkIjoiQjZFQjg0ODhDQzg0QzQxMDE3MTM0QkM3N0Y0MTMyQTA0NjdDQ0MwRSIsImFsZyI6IlJTMjU2In0.eyJpZCI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0L29wZW5pZF9yZWx5aW5nX3BhcnR5L3B1YmxpYyIsImlzcyI6Imh0dHBzOi8vY29oZXNpb24yLnJlZ2lvbmUubWFyY2hlLml0L29pZGMvc2EvIiwic3ViIjoiaHR0cHM6Ly9jb2hlc2lvbjIucmVnaW9uZS5tYXJjaGUuaXQvb2lkYy9zYS8yQkxTODJPRC8iLCJpYXQiOjE3MDMyNTA0MDYsIm9yZ2FuaXphdGlvbl90eXBlIjoicHVibGljIiwiaWRfY29kZSI6eyJpcGFfY29kZSI6IjJCTFM4Mk9EIn0sImVtYWlsIjoiamVzaXNlcnZpemlAcGVjLml0IiwiZXhwIjoxODYxMTAzMjA2LCJvcmdhbml6YXRpb25fbmFtZSI6Ikplc2kgc2Vydml6aSBzcmwiLCJyZWYiOiJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC90ZXN0Y29oZXNpb24ifQ.KYhjjcTXWsymdXJpkOoB4NcsZPAFxCbRa1jsFKqJrimxTlwMB05uOtZxOntiy1Qyu9eTu2pujnh-tNI0gMqHn81lgoSYCbrKZ-nip4ya-Tu-lGa5ocN_3ngcgOge-EeBVCrmBXIIVCx83o0ML_bKVsDCgTM2-1BqI_Vix6UAV_tZMOCkM6s6lAkwkZ_Ub-TayPCjLYEYoslRK7Hvi6vhpX2a1N6-Af8u7VkB2Iq8u-hHHioXgOKEo4ZbD72goOO1ZDOmoE0X3JrJhd7yYaOIaOEwnUFlZnvsILm8OAn-bFSBr-uzkoB-qe6U35dtQPw2adZOTnxEu-6bq-5PrNPwc2vn-UBInQUuws2OymmpT3N-QVvt472ER_EYXoJX2egI46d4SJ3edF9kvi3FZy0jH0lE9hfEdXwAyqsfu4RjD9WKNsn35kbxfC62u8sHKF3DXJG2YmEUct5KQMeBlMmsnqrMfDYeRDdKhl1bOCjFrPL8JEUladLcoViBNCOnAT4q"}],"authority_hints":["https://cohesion2.regione.marche.it/oidc/sa/","https://oidc.registry.servizicie.interno.gov.it"],"iss":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","sub":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","iat":1721029952,"exp":1721202752,"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]}}""" + private val intermediateEntityString = """{"metadata":{"federation_entity":{"organization_name":"Regione Marche","homepage_uri":"https://cohesion2.regione.marche.it","policy_uri":"https://www.regione.marche.it/Privacy","logo_uri":"https://cohesion2.regione.marche.it/Common/assets/images/cohesion.svg","contacts":["regione.marche.protocollogiunta@emarche.it"],"federation_resolve_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/resolve","federation_fetch_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/fetch","federation_list_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/list","federation_trust_mark_status_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/trust_mark_status"}},"trust_marks":[{"id":"https://oidc.registry.servizicie.interno.gov.it/intermediate/public","iss":"https://oidc.registry.servizicie.interno.gov.it","trust_mark":"eyJraWQiOiJkZWZhdWx0UlNBU2lnbiIsInR5cCI6InRydXN0LW1hcmsrand0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsInNhX3Byb2ZpbGUiOiJbXCJmdWxsXCJdIiwiaXNzIjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJvcmdhbml6YXRpb25fdHlwZSI6InB1YmxpYyIsImlkIjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyIsImV4cCI6MTczNDc5NTEyMCwiaWF0IjoxNzAzMTcyNzIwfQ.QoOpnGZS2UxwhMLkIgCQ7jhWK8BcS6Mukez8VEGpNUf6CgCUxto4xx7XC4p9mxLCP_xikUJpWqlVBW0WFPqLyf8-HK6Z9YEfo5mAuZ4_fPUXnTkKmHi_gKHtwOXaB8QT8qTWwRlhk2wAjepeIl9E0FLKO4GLYNzlQlZPByxVIAXav2WmIE3VrwIWRD-Fn8W_hX0EhS-t4lxaf2w88ZEJcdHfDn-9HSbm7QaVpYSIT5FXpbkunO9FpjdzBzMK_GyWpgWKdZiVwKKJDvSC5dYAssg4NEynoLg_vhhj4_hvhGI2bIFiPZoyxmgKKp8LnTIeJnmH4a2VBF_DDfnGq4TfzQ"}],"authority_hints":["https://oidc.registry.servizicie.interno.gov.it"],"iss":"https://cohesion2.regione.marche.it/oidc/sa/","sub":"https://cohesion2.regione.marche.it/oidc/sa/","iat":1721027703,"exp":1721200503,"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]}}""" + private val trustAnchorEntityString = """{"sub":"https://oidc.registry.servizicie.interno.gov.it","metadata":{"federation_entity":{"federation_fetch_endpoint":"https://oidc.registry.servizicie.interno.gov.it/fetch","federation_resolve_endpoint":"https://oidc.registry.servizicie.interno.gov.it/resolve","federation_trust_mark_status_endpoint":"https://oidc.registry.servizicie.interno.gov.it/trust_mark_status","federation_list_endpoint":"https://oidc.registry.servizicie.interno.gov.it/list"}},"jwks":{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"defaultRSASign","n":"qRTJHQgb2f8cln9dJb-Wgik4qEL5GG__sPzlAU4i69S6yHxeMg32YgLfUzpNBx_8kX2ndzYXM_RKmo3jhjQxuxCK1IHSQcMkg1hGii-xRw8x45t8SGlWcSHi7_6RaAY1SyFcEElNAqHi5oeBaB3FGvfrV-EP-cNkUvGEVbys_CbxyGDQ9QM0NErsilVlMARDErENZcrY0rNKt52WoZgy3psVcd8U5D0LqfC77bPjG35PaVhwYAnlP0ez0Hf6tuyWJHeA52dCde-na3WjmParkclpFr-KjXeIC8BwfjEpAXbKcp8NmuQFj9fD9KnR6vCdO91RyBIbDluL5LH8s0qDCQ"},{"kty":"EC","use":"sig","crv":"P-256","kid":"defaultECSign","x":"xMkWIa1EZyjgmk3JQLtHDA9p0TpP9wMSbJK0oAitgck","y":"CVLFstOwKwtQrut_voHjYO6Jz1K0NXRu8OLCTmKosLg"},{"kty":"RSA","e":"AQAB","use":"enc","kid":"defaultRSAEnc","n":"wew22xcpfASkQQp7SOo_Gs6cKj2Xy7xVZK_tgZxzAyQxLSxm5sU4ZGs6mdIAHdEvQ91SnEHTtjpeAS9wCvNXVmVxNIjFAPJzCYpsfFxGzW1PR3SCBeKPYzUjSyBSel5-mSwU80yYAqOlZ1QRZNQI5ESUvNPoePFjGCofxnFRsmqy_mAwZynd2NrrsT2Ayp0L6PQwz-EkOhjEBpzsyq0pMujnZEfvPy9P-Xv2SUFLeJPrmcDye64Z2Y9WPh2jpknhOxDK8RML-2YTvb4uSOjZ0XZOW9mVogNJRJm2zePTeeLPqGluLcDzplby0nLbLjdX7K3oLbqhDaewj7VraKemsQ"}]},"trust_mark_issuers":{"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public":["https://oidc.registry.servizicie.interno.gov.it","https://cohesion2.regione.marche.it/oidc/sa/","https://auth.toscana.it/auth/realms/enti/federation-entity/r_toscan_sa_enti","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/private":["https://oidc.registry.servizicie.interno.gov.it","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"]},"iss":"https://oidc.registry.servizicie.interno.gov.it","exp":1720878673,"iat":1720792273,"constraints":{"max_path_length":1},"trust_marks_issuers":{"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public":["https://oidc.registry.servizicie.interno.gov.it","https://cohesion2.regione.marche.it/oidc/sa/","https://auth.toscana.it/auth/realms/enti/federation-entity/r_toscan_sa_enti","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/private":["https://oidc.registry.servizicie.interno.gov.it","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"]}}""" + + private val entityLogic = EntityLogic() + + private lateinit var leafEntityStatement: EntityStatement + private lateinit var intermediateEntityStatement: EntityStatement + private lateinit var trustAnchorEntityStatement: EntityStatement + + + @BeforeTest + fun setUp() { + // ignoreUnknownKeys added because OpenAPI model misses few objects + // Need to fix OpenAPI model + val json = Json { ignoreUnknownKeys = true } + leafEntityStatement = json.decodeFromString(leafEntityString) + intermediateEntityStatement = json.decodeFromString(intermediateEntityString) + trustAnchorEntityStatement = json.decodeFromString(trustAnchorEntityString) + } + + @Test + fun shouldReturnTrustAnchor() { + assertEquals(EntityType.TRUST_ANCHOR, entityLogic.getEntityType(trustAnchorEntityStatement)) + } + + @Test + fun shouldReturnIntermediate() { + assertEquals(EntityType.INTERMEDIATE, entityLogic.getEntityType(intermediateEntityStatement)) + } + + @Test + fun shouldReturnLeafEntity() { + assertEquals(EntityType.LEAF, entityLogic.getEntityType(leafEntityStatement)) + } + + @Test + fun shouldReturnUndefined() { + val entityStatement = EntityStatement( + metadata = Metadata(federationEntity = null), + authorityHints = emptyList() + ) + assertEquals(EntityType.UNDEFINED, entityLogic.getEntityType(entityStatement)) + } +} \ No newline at end of file From 78ce211a0c07e6bcd6822e80a0df7ac6626bf38e Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Thu, 25 Jul 2024 10:59:48 +0200 Subject: [PATCH 12/25] refactor: Refactored the unit tests --- .../common/httpclient/OidFederationClient.kt | 4 +- .../httpclient/OidFederationClientTest.kt | 51 +++++++++++++------ 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt index 6fa78a6b..bdb77f3f 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt @@ -19,8 +19,8 @@ import io.ktor.utils.io.core.* class OidFederationClient( engine: HttpClientEngine, - isRequestAuthenticated: Boolean = false, - isRequestCached: Boolean = false + private val isRequestAuthenticated: Boolean = false, + private val isRequestCached: Boolean = false ) { private val client: HttpClient = HttpClient(engine) { install(HttpCache) diff --git a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt index 19925cd4..98e16253 100644 --- a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt +++ b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt @@ -1,11 +1,8 @@ package com.sphereon.oid.fed.common.httpclient -import com.sphereon.oid.fed.openapi.models.EntityStatement -import com.sphereon.oid.fed.openapi.models.FederationEntityMetadata -import com.sphereon.oid.fed.openapi.models.Metadata +import com.sphereon.oid.fed.openapi.models.* import io.ktor.client.engine.mock.* import io.ktor.http.* -import io.ktor.utils.io.* import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -14,23 +11,32 @@ import kotlin.test.Test class OidFederationClientTest { private val entityStatement = EntityStatement( - iss = "test_iss", - sub = "test_sub", - metadata = Metadata( - federationEntity = FederationEntityMetadata( - federationListEndpoint = "http://www.example.com/list", - federationResolveEndpoint = "http://www.example.com/resolve", - organizationName = "test organization", - homepageUri = "http://www.example.com", - federationFetchEndpoint = "http://www.example.com/fetch", + iss = "https://edugain.org/federation", + sub = "https://openid.sunet.se", + exp = 1568397247, + iat = 1568310847, + sourceEndpoint = "https://edugain.org/federation/federation_fetch_endpoint", + jwks = JWKS( + propertyKeys = listOf( + JWK( + // missing e and n ? + kid = "dEEtRjlzY3djcENuT01wOGxrZlkxb3RIQVJlMTY0...", + kty = "RSA" + ) + ) + ), + metadata = Metadata( + federationEntity = FederationEntityMetadata( + organizationName = "SUNET" + ) ) - ) ) private val mockEngine = MockEngine { respond( - content = ByteReadChannel(Json.encodeToString(entityStatement)), + content = Json.encodeToString(entityStatement), status = HttpStatusCode.OK, + // Must be application/entity-statement+jwt, at the moment it's not supported headers = headersOf(HttpHeaders.ContentType, "application/json") ) } @@ -39,7 +45,20 @@ class OidFederationClientTest { fun testGetEntityStatement() { runBlocking { val client = OidFederationClient(mockEngine) - val response = client.fetchEntityStatement("test_iss", HttpMethod.Get) + val response = client.fetchEntityStatement("https://www.example.com", HttpMethod.Get) + assert(response == entityStatement) + } + } + + @Test + fun testPostEntityStatement() { + runBlocking { + val client = OidFederationClient(mockEngine) + val response = client.fetchEntityStatement("https://www.example.com", HttpMethod.Post, + Parameters.build { + append("iss","https://edugain.org/federation") + append("sub","https://openid.sunet.se") + }) assert(response == entityStatement) } } From 91f6da88a00d77eb5d4c4119b5e49cc088200b83 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Thu, 25 Jul 2024 15:29:30 +0200 Subject: [PATCH 13/25] chore: Added nexus configuration --- modules/openapi/build.gradle.kts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index 7d913327..64c3fc69 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -24,6 +24,10 @@ repositories { kotlin { tasks { + named("build") { + finalizedBy("publish") + } + // Temporary fix for this issue: https://github.com/OpenAPITools/openapi-generator/issues/17658 register("fixOpenApiGeneratorIssue") { from( @@ -161,4 +165,16 @@ publishing { from(components["kotlin"]) } } + repositories { + maven { + name = "sphereon-opensource-snapshots" + val snapshotsUrl = "https://nexus.sphereon.com/content/groups/sphereon-opensource-snapshots" + val releasesUrl = "https://nexus.sphereon.com/content/groups/sphereon-opensource-releases" + url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsUrl else releasesUrl) + credentials { + username = System.getenv("NEXUS_USERNAME") + password = System.getenv("NEXUS_PASSWORD") + } + } + } } From 89685dcc6ee9a0237baf4536c01ed0e4c94d9457 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Thu, 25 Jul 2024 19:02:17 +0200 Subject: [PATCH 14/25] refactor: Updated nexus urls --- modules/openapi/build.gradle.kts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index 64c3fc69..04997961 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -24,10 +24,6 @@ repositories { kotlin { tasks { - named("build") { - finalizedBy("publish") - } - // Temporary fix for this issue: https://github.com/OpenAPITools/openapi-generator/issues/17658 register("fixOpenApiGeneratorIssue") { from( @@ -168,8 +164,8 @@ publishing { repositories { maven { name = "sphereon-opensource-snapshots" - val snapshotsUrl = "https://nexus.sphereon.com/content/groups/sphereon-opensource-snapshots" - val releasesUrl = "https://nexus.sphereon.com/content/groups/sphereon-opensource-releases" + val snapshotsUrl = "https://nexus.sphereon.com/repository/sphereon-opensource-snapshots/" + val releasesUrl = "https://nexus.sphereon.com/repository/sphereon-opensource-releases/" url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsUrl else releasesUrl) credentials { username = System.getenv("NEXUS_USERNAME") From 938b968d4cd604a564443d6ad18cc21fc946d17d Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Fri, 26 Jul 2024 12:05:53 +0530 Subject: [PATCH 15/25] chores: moved decode code --- .../oid/fed/common/mapper/JWTMapper.kt | 30 ------------------- .../oid/fed/common/mapper/JsonMapper.kt | 28 +++++++++++++++++ .../{JWTMapperTest.kt => JsonMapperTest.kt} | 10 ++++--- 3 files changed, 34 insertions(+), 34 deletions(-) delete mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapper.kt rename modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/{JWTMapperTest.kt => JsonMapperTest.kt} (85%) diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapper.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapper.kt deleted file mode 100644 index cbd0ecb0..00000000 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapper.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.sphereon.oid.fed.common.mapper - -import com.sphereon.oid.fed.common.model.JWTHeader -import com.sphereon.oid.fed.common.model.JWTSignature -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonElement - -import kotlin.io.encoding.Base64 -import kotlin.io.encoding.ExperimentalEncodingApi - - -@OptIn(ExperimentalEncodingApi::class) -fun decodeJWTComponents(jwtToken: String): Triple { - val parts = jwtToken.split(".") - if (parts.size != 3) { - return Triple(null, null, null) - } - - val headerJson = Base64.decode(parts[0]).decodeToString() - val payloadJson = Base64.decode(parts[1]).decodeToString() - - return try { - Triple( - Json.decodeFromString(headerJson), Json.parseToJsonElement(payloadJson), JWTSignature(parts[2]) - ) - } catch (e: Exception) { - println(e.printStackTrace()) - Triple(null, null, null) - } -} diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt index bc504a52..7c5e7be7 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt @@ -1,8 +1,13 @@ package com.sphereon.oid.fed.common.mapper +import com.sphereon.oid.fed.common.model.JWTHeader +import com.sphereon.oid.fed.common.model.JWTSignature import com.sphereon.oid.fed.openapi.models.EntityStatement import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.decodeFromJsonElement +import kotlin.io.encoding.Base64 +import kotlin.io.encoding.ExperimentalEncodingApi class JsonMapper { @@ -28,4 +33,27 @@ class JsonMapper { } return list } + + /* + * Used for decoding JWT to a triple with Header, Payload and Signature + */ + @OptIn(ExperimentalEncodingApi::class) + fun decodeJWTComponents(jwtToken: String): Triple { + val parts = jwtToken.split(".") + if (parts.size != 3) { + return Triple(null, null, null) + } + + val headerJson = Base64.decode(parts[0]).decodeToString() + val payloadJson = Base64.decode(parts[1]).decodeToString() + + return try { + Triple( + Json.decodeFromString(headerJson), Json.parseToJsonElement(payloadJson), JWTSignature(parts[2]) + ) + } catch (e: Exception) { + println(e.printStackTrace()) + Triple(null, null, null) + } + } } \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapperTest.kt b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt similarity index 85% rename from modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapperTest.kt rename to modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt index d616ffd0..ddeb33f5 100644 --- a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JWTMapperTest.kt +++ b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt @@ -7,13 +7,15 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull -class JWTMapperTest { +class JsonMapperTest { + + private val mapper = JsonMapper() @Test fun testDecodeValidJWT() { val jwt = "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTUxNjIzOTAyMn0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc" - val (header, payload, signature) = decodeJWTComponents(jwt) + val (header, payload, signature) = mapper.decodeJWTComponents(jwt) assertEquals("RS256", header?.alg) assertEquals("B6EB8488CC84C41017134BC77F4132A0467CCC0E", header?.kid) @@ -30,7 +32,7 @@ class JWTMapperTest { @Test fun testDecodeJWTWithInvalidStructure() { val invalidJWT = "header.payload.signature" // Missing dots - val (header, payload, signature) = decodeJWTComponents(invalidJWT) + val (header, payload, signature) = mapper.decodeJWTComponents(invalidJWT) assertNull(header) assertNull(payload) @@ -41,7 +43,7 @@ class JWTMapperTest { fun testDecodeJWTWithInvalidJSON() { val jwtWithInvalidJson = "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJhZG1pbiI6dHJ1ZX0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc" // Missing quote in payload - val (header, payload, signature) = decodeJWTComponents(jwtWithInvalidJson) + val (header, payload, signature) = mapper.decodeJWTComponents(jwtWithInvalidJson) assertNull(header) assertNull(payload) From 466c0decee21830e5bfad2c4703abb27aca13b21 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Fri, 26 Jul 2024 09:28:10 +0200 Subject: [PATCH 16/25] chore: Added Nexus repositories to the openid-federation-common module --- settings.gradle.kts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/settings.gradle.kts b/settings.gradle.kts index 62604efb..3d31d829 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -12,6 +12,12 @@ pluginManagement { } mavenLocal() mavenCentral() + maven { + url = uri("https://nexus.sphereon.com/content/groups/sphereon-opensource-snapshots") + } + maven { + url = uri("https://nexus.sphereon.com/content/groups/sphereon-opensource-releases") + } gradlePluginPortal() } } @@ -27,6 +33,12 @@ dependencyResolutionManagement { } mavenLocal() mavenCentral() + maven { + url = uri("https://nexus.sphereon.com/content/groups/sphereon-opensource-snapshots") + } + maven { + url = uri("https://nexus.sphereon.com/content/groups/sphereon-opensource-releases") + } } } From 20cbdf816e89e93a38885b08276cbbf7bcb7afcb Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Fri, 26 Jul 2024 14:43:06 +0530 Subject: [PATCH 17/25] chores: PR feedback changes --- .../com/sphereon/oid/fed/openapi/openapi.yaml | 31 +++++++++++++++++ .../oid/fed/common/logic/EntityLogic.kt | 7 ++-- .../oid/fed/common/mapper/JsonMapper.kt | 6 ++-- .../oid/fed/common/model/JWTHeader.kt | 13 ------- .../oid/fed/common/model/JWTSignature.kt | 4 --- .../oid/fed/common/logic/Constants.kt | 10 ++++++ .../oid/fed/common/logic/EntityLogicTest.kt | 34 +++++++------------ .../oid/fed/common/mapper/JsonMapperTest.kt | 2 +- settings.gradle.kts | 2 +- 9 files changed, 60 insertions(+), 49 deletions(-) delete mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt delete mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTSignature.kt create mode 100644 modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/Constants.kt diff --git a/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml b/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml index ff3e156b..02476887 100644 --- a/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml +++ b/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml @@ -161,6 +161,37 @@ components: items: $ref: '#/components/schemas/JWK' + JWTHeader: + type: object + x-tags: + - federation + properties: + alg: + type: string + description: The algorithm used to sign the JWT (e.g., RS256) + kid: + type: string + description: The unique identifier for the key used to sign the JWT + typ: + type: string + description: The type of token (optional, e.g., "entity-statement+jwt") + nullable: true + trust_chain: + type: array + description: An optional list of trust chain certificates or keys + items: + type: string + nullable: true + + JWTSignature: + type: object + x-tags: + - federation + properties: + value: + type: string + description: The encoded JWT signature value. + EntityStatement: type: object x-tags: diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt index ac937fa1..f69aa1c5 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt @@ -26,8 +26,5 @@ class EntityLogic { } enum class EntityType { - LEAF, - INTERMEDIATE, - TRUST_ANCHOR, - UNDEFINED -} \ No newline at end of file + LEAF, INTERMEDIATE, TRUST_ANCHOR, UNDEFINED +} diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt index 7c5e7be7..e1f28197 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt @@ -1,8 +1,8 @@ package com.sphereon.oid.fed.common.mapper -import com.sphereon.oid.fed.common.model.JWTHeader -import com.sphereon.oid.fed.common.model.JWTSignature import com.sphereon.oid.fed.openapi.models.EntityStatement +import com.sphereon.oid.fed.openapi.models.JWTHeader +import com.sphereon.oid.fed.openapi.models.JWTSignature import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.decodeFromJsonElement @@ -56,4 +56,4 @@ class JsonMapper { Triple(null, null, null) } } -} \ No newline at end of file +} diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt deleted file mode 100644 index b1937f06..00000000 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTHeader.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.sphereon.oid.fed.common.model - -import kotlinx.serialization.Serializable - -import kotlinx.serialization.SerialName - -@Serializable -data class JWTHeader( - @SerialName("alg") val alg: String, // RS256 - @SerialName("kid") val kid: String, // B6EB8488CC84C41017134BC77F4132A0467CCC0E - @SerialName("typ") val typ: String? = null, // entity-statement+jwt - @SerialName("trust_chain") val trustChain: List? = null // ["eyJhbGciOiJSUzI1NiIsImtpZCI6IlpXRlRRbWhmVFdaSVRuRlRZM0ZTV2pKdU5HMWZWV05hZWxkNmNtUjFRa0pEYlhaWlRYQm1hM1JWUVEiLCJ0eXAiOiJlbnRpdHktc3RhdGVtZW50K2p3dCJ9.eyJleHAiOjE2OTY1ODMzMzQsImlhdCI6MTY5NjI4MzMzNCwiaXNzIjoiaHR0cHM6Ly90cnVzdC1hbmNob3IuZXhhbXBsZS5vcmciLCJzdWIiOiJodHRwczovL2ludGVybWVkaWF0ZS5laWRhcy5leGFtcGxlLm9yZyIsImp3a3MiOnsia2V5cyI6W3sia3R5IjoiUlNBIiwia2lkIjoiWmxKd05tNDVUMmxVY1hsSFRHZzFaV2hsYmxkalVXbGxjbVF0U1VsUVdYcEhTMUpFUTA4eVRXVnZOQSIsImUiOiJBUUFCIiwibiI6ImtSQUlzLVRBblF6T29lc195RW9oaDNUeGlaWFlPRC1xekI2T25JalZCaVI0WFNGbkw4djhRQ0IxamJiSlZTQ1hBZmdObTlBZjdVRDNBX0E2T1pQOUtacldSUk00NEp0TVAzZmxVSU5CQ2xzNFBrdVd2RklmWEtaaWVUNGhBMzNYdUlTSndqT2NlNnRrbUZTUl9wQmI3S0JHbnB4d3dnRlJjeUM2RU1VQWtWUGdQRl9mbXM3NEEyTF83TGVaNzh2X053VUhsY2VxVHB1OUx6VTRuTTd1RTZQY0JPSmJweXI2SFFuUTR1VHN6WThsWHVmT3pHZ2IzVXNDNmRnQWVVVERIZlFROE4xYXV2bkJUNmR0SHNHNWMxS2NCT2QzLVp6ZTZ5WVE5c2JLUlUtWVoydDZKdUJIbS1xLTVOamxiRWVwNDAwbFgxSXlKdG9Tc3F0d3lCX1djdyJ9XX19.CvBvN0aG-r13UG4uITH72tC5CbAG0rT4qYQ5wwHOtGE021etZFQd40RFnQT5e-Gy_Y8Wiin-Zmc1hWW2rVyZ1RRInjYGUt26QI6ujR-5w9Y_LHVp-6RzYEF0lg9otpAyszQE4hf5qBZYAj8t39FvCYWTYVci6mtpovJQ380ha8I4QL__fZtEgDLQ-7VKS58nN1DOVdcIICMMfxpDR81bkY5i5Qxcy7AaZTN6xxE2SlCO-pKKub0jBUtnug20-BL2YgcPhLFOYWfj2cuyapOA9Omwu6CPhmZHgsL1P2oK_f4jA9JxNDYcV0losDbD86r8Wg3anM2lVM5BTHkiUr2grg"] -) \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTSignature.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTSignature.kt deleted file mode 100644 index f9cf7995..00000000 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/model/JWTSignature.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.sphereon.oid.fed.common.model - - -data class JWTSignature(val value: String) \ No newline at end of file diff --git a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/Constants.kt b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/Constants.kt new file mode 100644 index 00000000..bde9c66a --- /dev/null +++ b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/Constants.kt @@ -0,0 +1,10 @@ +package com.sphereon.oid.fed.common.logic + +const val LEAF_ENTITY_STATEMENT = + """{"metadata":{"openid_relying_party":{"client_registration_types":["automatic"],"client_name":"JESISERVIZI SRL","grant_types":["authorization_code","refresh_token"],"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]},"redirect_uris":["https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/callback"],"response_types":["code"],"client_id":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","id_token_signed_response_alg":"RS256","id_token_encrypted_response_alg":"RSA-OAEP","id_token_encrypted_response_enc":"A256CBC-HS512","userinfo_signed_response_alg":"RS256","userinfo_encrypted_response_alg":"RSA-OAEP","userinfo_encrypted_response_enc":"A256CBC-HS512","token_endpoint_auth_method":"private_key_jwt"},"federation_entity":{"contacts":["jesiservizi@pec.it"],"organization_name":"JESISERVIZI SRL","homepage_uri":"https://cohesion2.regione.marche.it","policy_uri":"https://www.regione.marche.it/Privacy","logo_uri":"https://cohesion2.regione.marche.it/Common/assets/images/cohesion.svg","federation_resolve_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/resolve"}},"trust_marks":[{"id":"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public","iss":"https://cohesion2.regione.marche.it/oidc/sa/","trust_mark":"eyJ0eXAiOiJ0cnVzdC1tYXJrXHUwMDJCand0Iiwia2lkIjoiQjZFQjg0ODhDQzg0QzQxMDE3MTM0QkM3N0Y0MTMyQTA0NjdDQ0MwRSIsImFsZyI6IlJTMjU2In0.eyJpZCI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0L29wZW5pZF9yZWx5aW5nX3BhcnR5L3B1YmxpYyIsImlzcyI6Imh0dHBzOi8vY29oZXNpb24yLnJlZ2lvbmUubWFyY2hlLml0L29pZGMvc2EvIiwic3ViIjoiaHR0cHM6Ly9jb2hlc2lvbjIucmVnaW9uZS5tYXJjaGUuaXQvb2lkYy9zYS8yQkxTODJPRC8iLCJpYXQiOjE3MDMyNTA0MDYsIm9yZ2FuaXphdGlvbl90eXBlIjoicHVibGljIiwiaWRfY29kZSI6eyJpcGFfY29kZSI6IjJCTFM4Mk9EIn0sImVtYWlsIjoiamVzaXNlcnZpemlAcGVjLml0IiwiZXhwIjoxODYxMTAzMjA2LCJvcmdhbml6YXRpb25fbmFtZSI6Ikplc2kgc2Vydml6aSBzcmwiLCJyZWYiOiJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC90ZXN0Y29oZXNpb24ifQ.KYhjjcTXWsymdXJpkOoB4NcsZPAFxCbRa1jsFKqJrimxTlwMB05uOtZxOntiy1Qyu9eTu2pujnh-tNI0gMqHn81lgoSYCbrKZ-nip4ya-Tu-lGa5ocN_3ngcgOge-EeBVCrmBXIIVCx83o0ML_bKVsDCgTM2-1BqI_Vix6UAV_tZMOCkM6s6lAkwkZ_Ub-TayPCjLYEYoslRK7Hvi6vhpX2a1N6-Af8u7VkB2Iq8u-hHHioXgOKEo4ZbD72goOO1ZDOmoE0X3JrJhd7yYaOIaOEwnUFlZnvsILm8OAn-bFSBr-uzkoB-qe6U35dtQPw2adZOTnxEu-6bq-5PrNPwc2vn-UBInQUuws2OymmpT3N-QVvt472ER_EYXoJX2egI46d4SJ3edF9kvi3FZy0jH0lE9hfEdXwAyqsfu4RjD9WKNsn35kbxfC62u8sHKF3DXJG2YmEUct5KQMeBlMmsnqrMfDYeRDdKhl1bOCjFrPL8JEUladLcoViBNCOnAT4q"}],"authority_hints":["https://cohesion2.regione.marche.it/oidc/sa/","https://oidc.registry.servizicie.interno.gov.it"],"iss":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","sub":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","iat":1721029952,"exp":1721202752,"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]}}""" + +const val INTERMEDIATE_ENTITY_STATEMENT = + """{"metadata":{"federation_entity":{"organization_name":"Regione Marche","homepage_uri":"https://cohesion2.regione.marche.it","policy_uri":"https://www.regione.marche.it/Privacy","logo_uri":"https://cohesion2.regione.marche.it/Common/assets/images/cohesion.svg","contacts":["regione.marche.protocollogiunta@emarche.it"],"federation_resolve_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/resolve","federation_fetch_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/fetch","federation_list_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/list","federation_trust_mark_status_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/trust_mark_status"}},"trust_marks":[{"id":"https://oidc.registry.servizicie.interno.gov.it/intermediate/public","iss":"https://oidc.registry.servizicie.interno.gov.it","trust_mark":"eyJraWQiOiJkZWZhdWx0UlNBU2lnbiIsInR5cCI6InRydXN0LW1hcmsrand0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsInNhX3Byb2ZpbGUiOiJbXCJmdWxsXCJdIiwiaXNzIjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJvcmdhbml6YXRpb25fdHlwZSI6InB1YmxpYyIsImlkIjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyIsImV4cCI6MTczNDc5NTEyMCwiaWF0IjoxNzAzMTcyNzIwfQ.QoOpnGZS2UxwhMLkIgCQ7jhWK8BcS6Mukez8VEGpNUf6CgCUxto4xx7XC4p9mxLCP_xikUJpWqlVBW0WFPqLyf8-HK6Z9YEfo5mAuZ4_fPUXnTkKmHi_gKHtwOXaB8QT8qTWwRlhk2wAjepeIl9E0FLKO4GLYNzlQlZPByxVIAXav2WmIE3VrwIWRD-Fn8W_hX0EhS-t4lxaf2w88ZEJcdHfDn-9HSbm7QaVpYSIT5FXpbkunO9FpjdzBzMK_GyWpgWKdZiVwKKJDvSC5dYAssg4NEynoLg_vhhj4_hvhGI2bIFiPZoyxmgKKp8LnTIeJnmH4a2VBF_DDfnGq4TfzQ"}],"authority_hints":["https://oidc.registry.servizicie.interno.gov.it"],"iss":"https://cohesion2.regione.marche.it/oidc/sa/","sub":"https://cohesion2.regione.marche.it/oidc/sa/","iat":1721027703,"exp":1721200503,"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]}}""" + +const val TRUST_ANCHOR_ENTITY_STATEMENT = + """{"sub":"https://oidc.registry.servizicie.interno.gov.it","metadata":{"federation_entity":{"federation_fetch_endpoint":"https://oidc.registry.servizicie.interno.gov.it/fetch","federation_resolve_endpoint":"https://oidc.registry.servizicie.interno.gov.it/resolve","federation_trust_mark_status_endpoint":"https://oidc.registry.servizicie.interno.gov.it/trust_mark_status","federation_list_endpoint":"https://oidc.registry.servizicie.interno.gov.it/list"}},"jwks":{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"defaultRSASign","n":"qRTJHQgb2f8cln9dJb-Wgik4qEL5GG__sPzlAU4i69S6yHxeMg32YgLfUzpNBx_8kX2ndzYXM_RKmo3jhjQxuxCK1IHSQcMkg1hGii-xRw8x45t8SGlWcSHi7_6RaAY1SyFcEElNAqHi5oeBaB3FGvfrV-EP-cNkUvGEVbys_CbxyGDQ9QM0NErsilVlMARDErENZcrY0rNKt52WoZgy3psVcd8U5D0LqfC77bPjG35PaVhwYAnlP0ez0Hf6tuyWJHeA52dCde-na3WjmParkclpFr-KjXeIC8BwfjEpAXbKcp8NmuQFj9fD9KnR6vCdO91RyBIbDluL5LH8s0qDCQ"},{"kty":"EC","use":"sig","crv":"P-256","kid":"defaultECSign","x":"xMkWIa1EZyjgmk3JQLtHDA9p0TpP9wMSbJK0oAitgck","y":"CVLFstOwKwtQrut_voHjYO6Jz1K0NXRu8OLCTmKosLg"},{"kty":"RSA","e":"AQAB","use":"enc","kid":"defaultRSAEnc","n":"wew22xcpfASkQQp7SOo_Gs6cKj2Xy7xVZK_tgZxzAyQxLSxm5sU4ZGs6mdIAHdEvQ91SnEHTtjpeAS9wCvNXVmVxNIjFAPJzCYpsfFxGzW1PR3SCBeKPYzUjSyBSel5-mSwU80yYAqOlZ1QRZNQI5ESUvNPoePFjGCofxnFRsmqy_mAwZynd2NrrsT2Ayp0L6PQwz-EkOhjEBpzsyq0pMujnZEfvPy9P-Xv2SUFLeJPrmcDye64Z2Y9WPh2jpknhOxDK8RML-2YTvb4uSOjZ0XZOW9mVogNJRJm2zePTeeLPqGluLcDzplby0nLbLjdX7K3oLbqhDaewj7VraKemsQ"}]},"trust_mark_issuers":{"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public":["https://oidc.registry.servizicie.interno.gov.it","https://cohesion2.regione.marche.it/oidc/sa/","https://auth.toscana.it/auth/realms/enti/federation-entity/r_toscan_sa_enti","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/private":["https://oidc.registry.servizicie.interno.gov.it","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"]},"iss":"https://oidc.registry.servizicie.interno.gov.it","exp":1720878673,"iat":1720792273,"constraints":{"max_path_length":1},"trust_marks_issuers":{"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public":["https://oidc.registry.servizicie.interno.gov.it","https://cohesion2.regione.marche.it/oidc/sa/","https://auth.toscana.it/auth/realms/enti/federation-entity/r_toscan_sa_enti","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/private":["https://oidc.registry.servizicie.interno.gov.it","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"]}}""" diff --git a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/EntityLogicTest.kt b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/EntityLogicTest.kt index 7ba05790..5f8b3e23 100644 --- a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/EntityLogicTest.kt +++ b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/logic/EntityLogicTest.kt @@ -3,54 +3,44 @@ package com.sphereon.oid.fed.common.logic import com.sphereon.oid.fed.openapi.models.EntityStatement import com.sphereon.oid.fed.openapi.models.Metadata import kotlinx.serialization.json.Json -import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals class EntityLogicTest { - private val leafEntityString = """{"metadata":{"openid_relying_party":{"client_registration_types":["automatic"],"client_name":"JESISERVIZI SRL","grant_types":["authorization_code","refresh_token"],"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]},"redirect_uris":["https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/callback"],"response_types":["code"],"client_id":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","id_token_signed_response_alg":"RS256","id_token_encrypted_response_alg":"RSA-OAEP","id_token_encrypted_response_enc":"A256CBC-HS512","userinfo_signed_response_alg":"RS256","userinfo_encrypted_response_alg":"RSA-OAEP","userinfo_encrypted_response_enc":"A256CBC-HS512","token_endpoint_auth_method":"private_key_jwt"},"federation_entity":{"contacts":["jesiservizi@pec.it"],"organization_name":"JESISERVIZI SRL","homepage_uri":"https://cohesion2.regione.marche.it","policy_uri":"https://www.regione.marche.it/Privacy","logo_uri":"https://cohesion2.regione.marche.it/Common/assets/images/cohesion.svg","federation_resolve_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/resolve"}},"trust_marks":[{"id":"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public","iss":"https://cohesion2.regione.marche.it/oidc/sa/","trust_mark":"eyJ0eXAiOiJ0cnVzdC1tYXJrXHUwMDJCand0Iiwia2lkIjoiQjZFQjg0ODhDQzg0QzQxMDE3MTM0QkM3N0Y0MTMyQTA0NjdDQ0MwRSIsImFsZyI6IlJTMjU2In0.eyJpZCI6Imh0dHBzOi8vb2lkYy5yZWdpc3RyeS5zZXJ2aXppY2llLmludGVybm8uZ292Lml0L29wZW5pZF9yZWx5aW5nX3BhcnR5L3B1YmxpYyIsImlzcyI6Imh0dHBzOi8vY29oZXNpb24yLnJlZ2lvbmUubWFyY2hlLml0L29pZGMvc2EvIiwic3ViIjoiaHR0cHM6Ly9jb2hlc2lvbjIucmVnaW9uZS5tYXJjaGUuaXQvb2lkYy9zYS8yQkxTODJPRC8iLCJpYXQiOjE3MDMyNTA0MDYsIm9yZ2FuaXphdGlvbl90eXBlIjoicHVibGljIiwiaWRfY29kZSI6eyJpcGFfY29kZSI6IjJCTFM4Mk9EIn0sImVtYWlsIjoiamVzaXNlcnZpemlAcGVjLml0IiwiZXhwIjoxODYxMTAzMjA2LCJvcmdhbml6YXRpb25fbmFtZSI6Ikplc2kgc2Vydml6aSBzcmwiLCJyZWYiOiJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC90ZXN0Y29oZXNpb24ifQ.KYhjjcTXWsymdXJpkOoB4NcsZPAFxCbRa1jsFKqJrimxTlwMB05uOtZxOntiy1Qyu9eTu2pujnh-tNI0gMqHn81lgoSYCbrKZ-nip4ya-Tu-lGa5ocN_3ngcgOge-EeBVCrmBXIIVCx83o0ML_bKVsDCgTM2-1BqI_Vix6UAV_tZMOCkM6s6lAkwkZ_Ub-TayPCjLYEYoslRK7Hvi6vhpX2a1N6-Af8u7VkB2Iq8u-hHHioXgOKEo4ZbD72goOO1ZDOmoE0X3JrJhd7yYaOIaOEwnUFlZnvsILm8OAn-bFSBr-uzkoB-qe6U35dtQPw2adZOTnxEu-6bq-5PrNPwc2vn-UBInQUuws2OymmpT3N-QVvt472ER_EYXoJX2egI46d4SJ3edF9kvi3FZy0jH0lE9hfEdXwAyqsfu4RjD9WKNsn35kbxfC62u8sHKF3DXJG2YmEUct5KQMeBlMmsnqrMfDYeRDdKhl1bOCjFrPL8JEUladLcoViBNCOnAT4q"}],"authority_hints":["https://cohesion2.regione.marche.it/oidc/sa/","https://oidc.registry.servizicie.interno.gov.it"],"iss":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","sub":"https://cohesion2.regione.marche.it/oidc/sa/2BLS82OD/","iat":1721029952,"exp":1721202752,"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]}}""" - private val intermediateEntityString = """{"metadata":{"federation_entity":{"organization_name":"Regione Marche","homepage_uri":"https://cohesion2.regione.marche.it","policy_uri":"https://www.regione.marche.it/Privacy","logo_uri":"https://cohesion2.regione.marche.it/Common/assets/images/cohesion.svg","contacts":["regione.marche.protocollogiunta@emarche.it"],"federation_resolve_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/resolve","federation_fetch_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/fetch","federation_list_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/list","federation_trust_mark_status_endpoint":"https://cohesion2.regione.marche.it/oidc/sa/trust_mark_status"}},"trust_marks":[{"id":"https://oidc.registry.servizicie.interno.gov.it/intermediate/public","iss":"https://oidc.registry.servizicie.interno.gov.it","trust_mark":"eyJraWQiOiJkZWZhdWx0UlNBU2lnbiIsInR5cCI6InRydXN0LW1hcmsrand0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJodHRwczovL2NvaGVzaW9uMi5yZWdpb25lLm1hcmNoZS5pdC9vaWRjL3NhLyIsInNhX3Byb2ZpbGUiOiJbXCJmdWxsXCJdIiwiaXNzIjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQiLCJvcmdhbml6YXRpb25fdHlwZSI6InB1YmxpYyIsImlkIjoiaHR0cHM6Ly9vaWRjLnJlZ2lzdHJ5LnNlcnZpemljaWUuaW50ZXJuby5nb3YuaXQvaW50ZXJtZWRpYXRlL3B1YmxpYyIsImV4cCI6MTczNDc5NTEyMCwiaWF0IjoxNzAzMTcyNzIwfQ.QoOpnGZS2UxwhMLkIgCQ7jhWK8BcS6Mukez8VEGpNUf6CgCUxto4xx7XC4p9mxLCP_xikUJpWqlVBW0WFPqLyf8-HK6Z9YEfo5mAuZ4_fPUXnTkKmHi_gKHtwOXaB8QT8qTWwRlhk2wAjepeIl9E0FLKO4GLYNzlQlZPByxVIAXav2WmIE3VrwIWRD-Fn8W_hX0EhS-t4lxaf2w88ZEJcdHfDn-9HSbm7QaVpYSIT5FXpbkunO9FpjdzBzMK_GyWpgWKdZiVwKKJDvSC5dYAssg4NEynoLg_vhhj4_hvhGI2bIFiPZoyxmgKKp8LnTIeJnmH4a2VBF_DDfnGq4TfzQ"}],"authority_hints":["https://oidc.registry.servizicie.interno.gov.it"],"iss":"https://cohesion2.regione.marche.it/oidc/sa/","sub":"https://cohesion2.regione.marche.it/oidc/sa/","iat":1721027703,"exp":1721200503,"jwks":{"keys":[{"kty":"RSA","use":"sig","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E"},{"kty":"RSA","use":"enc","n":"yF7zakG7N8G2meDjsgqFowtxE51FtG8HacCDxA_qiMGp5lrcC4CggEdHkpdI3RrYTZ9WvADMWZEdIwydbIPn1HsPNCEy1UpsWQEZ-_8mHXGVz6p7ePrPXjIKl2eGqyQG_iCdAjqVpQ43Fqe3Mg17V-Phnn3gN_zMS7-eOXwuhWPiLZn7mFkiGin2LKECok4aaOcxIWRhsiNJdT5j0T1ORuk9y-gfJ-ljauVLh4hn5cwz7nj2lKBA0e-FOBTDSbpL_jYCj0NkvCrgFJSPDitne4M_M6YM1GpSNuBNNCOGYzjmynGpqu3btgdd5ONh2Ym4Kzwspu_RnLY3lyWR6lC_ad7q4fl4Zjlhp6murcKt15OkvijFVILraFqglugP6lHb89j1QQKKeBRNj_k93YQ5o1cT3iV-j-2BMcgB5Rfp-1sKlz10QQlMWXnbN7ruKs6Q2M5XNOGu8fJ9ohYM9rECmPmmVQI5vzoH65JfbKT0Mgfer59QY1s4IEgn5csGEw2p","e":"AQAB","kid":"B6EB8488CC84C41017134BC77F4132A0467CCC0E_enc"}]}}""" - private val trustAnchorEntityString = """{"sub":"https://oidc.registry.servizicie.interno.gov.it","metadata":{"federation_entity":{"federation_fetch_endpoint":"https://oidc.registry.servizicie.interno.gov.it/fetch","federation_resolve_endpoint":"https://oidc.registry.servizicie.interno.gov.it/resolve","federation_trust_mark_status_endpoint":"https://oidc.registry.servizicie.interno.gov.it/trust_mark_status","federation_list_endpoint":"https://oidc.registry.servizicie.interno.gov.it/list"}},"jwks":{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"defaultRSASign","n":"qRTJHQgb2f8cln9dJb-Wgik4qEL5GG__sPzlAU4i69S6yHxeMg32YgLfUzpNBx_8kX2ndzYXM_RKmo3jhjQxuxCK1IHSQcMkg1hGii-xRw8x45t8SGlWcSHi7_6RaAY1SyFcEElNAqHi5oeBaB3FGvfrV-EP-cNkUvGEVbys_CbxyGDQ9QM0NErsilVlMARDErENZcrY0rNKt52WoZgy3psVcd8U5D0LqfC77bPjG35PaVhwYAnlP0ez0Hf6tuyWJHeA52dCde-na3WjmParkclpFr-KjXeIC8BwfjEpAXbKcp8NmuQFj9fD9KnR6vCdO91RyBIbDluL5LH8s0qDCQ"},{"kty":"EC","use":"sig","crv":"P-256","kid":"defaultECSign","x":"xMkWIa1EZyjgmk3JQLtHDA9p0TpP9wMSbJK0oAitgck","y":"CVLFstOwKwtQrut_voHjYO6Jz1K0NXRu8OLCTmKosLg"},{"kty":"RSA","e":"AQAB","use":"enc","kid":"defaultRSAEnc","n":"wew22xcpfASkQQp7SOo_Gs6cKj2Xy7xVZK_tgZxzAyQxLSxm5sU4ZGs6mdIAHdEvQ91SnEHTtjpeAS9wCvNXVmVxNIjFAPJzCYpsfFxGzW1PR3SCBeKPYzUjSyBSel5-mSwU80yYAqOlZ1QRZNQI5ESUvNPoePFjGCofxnFRsmqy_mAwZynd2NrrsT2Ayp0L6PQwz-EkOhjEBpzsyq0pMujnZEfvPy9P-Xv2SUFLeJPrmcDye64Z2Y9WPh2jpknhOxDK8RML-2YTvb4uSOjZ0XZOW9mVogNJRJm2zePTeeLPqGluLcDzplby0nLbLjdX7K3oLbqhDaewj7VraKemsQ"}]},"trust_mark_issuers":{"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public":["https://oidc.registry.servizicie.interno.gov.it","https://cohesion2.regione.marche.it/oidc/sa/","https://auth.toscana.it/auth/realms/enti/federation-entity/r_toscan_sa_enti","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/private":["https://oidc.registry.servizicie.interno.gov.it","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"]},"iss":"https://oidc.registry.servizicie.interno.gov.it","exp":1720878673,"iat":1720792273,"constraints":{"max_path_length":1},"trust_marks_issuers":{"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/oauth_resource/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/public":["https://oidc.registry.servizicie.interno.gov.it","https://cohesion2.regione.marche.it/oidc/sa/","https://auth.toscana.it/auth/realms/enti/federation-entity/r_toscan_sa_enti","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"],"https://oidc.registry.servizicie.interno.gov.it/intermediate/private":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_provider/public":["https://oidc.registry.servizicie.interno.gov.it"],"https://oidc.registry.servizicie.interno.gov.it/openid_relying_party/private":["https://oidc.registry.servizicie.interno.gov.it","https://oidcsa.webloom.it","https://secure.eremind.it/identita-digitale-oidc/oidc-fed","https://cie-oidc.comune-online.it/AuthServiceOIDC/oidc/sa","https://php-cie.andxor.it","https://oidc.studioamica.com","https://idp.entranext.it/services/oidc/sa/sso","https://cwolsso.nuvolapalitalsoft.it/services/oidc/sa/sso","https://federa.lepida.it/gw/OidcSaFull/","https://www.eurocontab.it/api"]}}""" - private val entityLogic = EntityLogic() - private lateinit var leafEntityStatement: EntityStatement - private lateinit var intermediateEntityStatement: EntityStatement - private lateinit var trustAnchorEntityStatement: EntityStatement - - - @BeforeTest - fun setUp() { - // ignoreUnknownKeys added because OpenAPI model misses few objects - // Need to fix OpenAPI model - val json = Json { ignoreUnknownKeys = true } - leafEntityStatement = json.decodeFromString(leafEntityString) - intermediateEntityStatement = json.decodeFromString(intermediateEntityString) - trustAnchorEntityStatement = json.decodeFromString(trustAnchorEntityString) - } + // ignoreUnknownKeys added because OpenAPI model misses few objects + // Need to fix OpenAPI model + private val json = Json { ignoreUnknownKeys = true } @Test fun shouldReturnTrustAnchor() { + val trustAnchorEntityStatement = json.decodeFromString(TRUST_ANCHOR_ENTITY_STATEMENT) + assertEquals(EntityType.TRUST_ANCHOR, entityLogic.getEntityType(trustAnchorEntityStatement)) } @Test fun shouldReturnIntermediate() { + val intermediateEntityStatement = json.decodeFromString(INTERMEDIATE_ENTITY_STATEMENT) + assertEquals(EntityType.INTERMEDIATE, entityLogic.getEntityType(intermediateEntityStatement)) } @Test fun shouldReturnLeafEntity() { + val leafEntityStatement = json.decodeFromString(LEAF_ENTITY_STATEMENT) + assertEquals(EntityType.LEAF, entityLogic.getEntityType(leafEntityStatement)) } @Test fun shouldReturnUndefined() { val entityStatement = EntityStatement( - metadata = Metadata(federationEntity = null), - authorityHints = emptyList() + metadata = Metadata(federationEntity = null), authorityHints = emptyList() ) + assertEquals(EntityType.UNDEFINED, entityLogic.getEntityType(entityStatement)) } -} \ No newline at end of file +} diff --git a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt index ddeb33f5..4a04f6ca 100644 --- a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt +++ b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt @@ -49,4 +49,4 @@ class JsonMapperTest { assertNull(payload) assertNull(signature) } -} \ No newline at end of file +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 05458317..62604efb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -32,4 +32,4 @@ dependencyResolutionManagement { include(":modules:openid-federation-common") include(":modules:admin-server") -include(":modules:openapi") \ No newline at end of file +include(":modules:openapi") From f483622b3e816cfe7de84899dd92ddf430595729 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Fri, 26 Jul 2024 12:20:40 +0200 Subject: [PATCH 18/25] refactor: Updated nexus urls and added artifacts to be published to Nexus --- modules/openapi/build.gradle.kts | 10 +++++++++- settings.gradle.kts | 12 ++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index 04997961..71a13855 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -158,7 +158,15 @@ kotlin { publishing { publications { create("mavenKotlin") { - from(components["kotlin"]) + artifacts { + from(components["kotlin"]) + artifact(tasks["jsJar"]) { + classifier = "js" + } + artifact(tasks["allMetadataJar"]) { + classifier = "metadata" + } + } } } repositories { diff --git a/settings.gradle.kts b/settings.gradle.kts index 3d31d829..3d525cbe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,13 +10,13 @@ pluginManagement { includeGroupAndSubgroups("com.google") } } - mavenLocal() + //mavenLocal() mavenCentral() maven { - url = uri("https://nexus.sphereon.com/content/groups/sphereon-opensource-snapshots") + url = uri("https://nexus.sphereon.com/repository/sphereon-opensource-snapshots") } maven { - url = uri("https://nexus.sphereon.com/content/groups/sphereon-opensource-releases") + url = uri("https://nexus.sphereon.com/repository/sphereon-opensource-releases") } gradlePluginPortal() } @@ -31,13 +31,13 @@ dependencyResolutionManagement { includeGroupAndSubgroups("com.google") } } - mavenLocal() + //mavenLocal() mavenCentral() maven { - url = uri("https://nexus.sphereon.com/content/groups/sphereon-opensource-snapshots") + url = uri("https://nexus.sphereon.com/repository/sphereon-opensource-snapshots") } maven { - url = uri("https://nexus.sphereon.com/content/groups/sphereon-opensource-releases") + url = uri("https://nexus.sphereon.com/repository/sphereon-opensource-releases") } } } From 8ce68f9c36636e7159fddf046da535a0aa2b337f Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Fri, 26 Jul 2024 12:46:32 +0200 Subject: [PATCH 19/25] refactor: Extended build task with the publish task --- modules/openapi/build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index 71a13855..1e544510 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -24,6 +24,9 @@ repositories { kotlin { tasks { + build { + finalizedBy("publish") + } // Temporary fix for this issue: https://github.com/OpenAPITools/openapi-generator/issues/17658 register("fixOpenApiGeneratorIssue") { from( From 4e23e8c02799b240c85acfcc3bbdb446d422e6e7 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Fri, 26 Jul 2024 12:51:20 +0200 Subject: [PATCH 20/25] refactor: Removed the publish task from gradle build task --- modules/openapi/build.gradle.kts | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/openapi/build.gradle.kts b/modules/openapi/build.gradle.kts index 1e544510..71a13855 100644 --- a/modules/openapi/build.gradle.kts +++ b/modules/openapi/build.gradle.kts @@ -24,9 +24,6 @@ repositories { kotlin { tasks { - build { - finalizedBy("publish") - } // Temporary fix for this issue: https://github.com/OpenAPITools/openapi-generator/issues/17658 register("fixOpenApiGeneratorIssue") { from( From 3801385144e9b31f232a709348daaf59718d0c49 Mon Sep 17 00:00:00 2001 From: Zoe Maas Date: Fri, 26 Jul 2024 13:59:51 +0200 Subject: [PATCH 21/25] chore: Added content negotiation and content-type entity-statement+jwt --- .../httpclient/EntityStatementJwtConverter.kt | 45 +++++++++++++++++++ .../common/httpclient/OidFederationClient.kt | 1 + .../httpclient/OidFederationContentType.kt | 5 +++ .../httpclient/OidFederationClientTest.kt | 7 ++- 4 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/EntityStatementJwtConverter.kt create mode 100644 modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationContentType.kt diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/EntityStatementJwtConverter.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/EntityStatementJwtConverter.kt new file mode 100644 index 00000000..ed7c83d9 --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/EntityStatementJwtConverter.kt @@ -0,0 +1,45 @@ +package com.sphereon.oid.fed.common.httpclient + +import com.sphereon.oid.fed.common.mapper.JsonMapper +import com.sphereon.oid.fed.openapi.models.EntityStatement +import io.ktor.http.* +import io.ktor.http.content.* +import io.ktor.serialization.* +import io.ktor.util.reflect.* +import io.ktor.utils.io.* +import io.ktor.utils.io.charsets.* +import io.ktor.utils.io.core.* +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json + +class EntityStatementJwtConverter: ContentConverter { + + override suspend fun serializeNullable( + contentType: ContentType, + charset: Charset, + typeInfo: TypeInfo, + value: Any? + ): OutgoingContent? { + if (value is EntityStatement) { + return OutgoingEntityStatementContent(value) + } else if (value is String) { + JsonMapper().mapEntityStatement(value)?.let { + return OutgoingEntityStatementContent(it) + } + } + return null + } + + override suspend fun deserialize(charset: Charset, typeInfo: TypeInfo, content: ByteReadChannel): Any? { + val text = content.readRemaining().readText(charset) + return Json.decodeFromString(EntityStatement.serializer(), text) + } +} + +class OutgoingEntityStatementContent(private val entityStatement: EntityStatement): OutgoingContent.ByteArrayContent() { + + override fun bytes(): ByteArray { + val serializedData = Json.encodeToString(entityStatement) + return serializedData.toByteArray(Charsets.UTF_8) + } +} diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt index bdb77f3f..21b3c548 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt @@ -25,6 +25,7 @@ class OidFederationClient( private val client: HttpClient = HttpClient(engine) { install(HttpCache) install(ContentNegotiation) { + register(EntityStatementJwt, EntityStatementJwtConverter()) json() } install(Logging) { diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationContentType.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationContentType.kt new file mode 100644 index 00000000..bd26d658 --- /dev/null +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationContentType.kt @@ -0,0 +1,5 @@ +package com.sphereon.oid.fed.common.httpclient + +import io.ktor.http.* + +val EntityStatementJwt get() = ContentType("application", "entity-statement+jwt") diff --git a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt index 98e16253..d95a7de8 100644 --- a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt +++ b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt @@ -36,8 +36,7 @@ class OidFederationClientTest { respond( content = Json.encodeToString(entityStatement), status = HttpStatusCode.OK, - // Must be application/entity-statement+jwt, at the moment it's not supported - headers = headersOf(HttpHeaders.ContentType, "application/json") + headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") ) } @@ -45,7 +44,7 @@ class OidFederationClientTest { fun testGetEntityStatement() { runBlocking { val client = OidFederationClient(mockEngine) - val response = client.fetchEntityStatement("https://www.example.com", HttpMethod.Get) + val response = client.fetchEntityStatement("https://www.example.com?iss=https://edugain.org/federation&sub=https://openid.sunet.se", HttpMethod.Get) assert(response == entityStatement) } } @@ -62,4 +61,4 @@ class OidFederationClientTest { assert(response == entityStatement) } } -} \ No newline at end of file +} From c82ec0377ed8ec4fc93afc358aeab239ffe12353 Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Mon, 29 Jul 2024 16:08:22 +0530 Subject: [PATCH 22/25] fix: enabled logger and updated GET call --- .../common/httpclient/OidFederationClient.kt | 27 ++++++++++++------- .../httpclient/OidFederationClientTest.kt | 14 +++++----- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt index 21b3c548..849be404 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt @@ -22,6 +22,8 @@ class OidFederationClient( private val isRequestAuthenticated: Boolean = false, private val isRequestCached: Boolean = false ) { + private val BASE_URL = "https://www.example.com" + private val client: HttpClient = HttpClient(engine) { install(HttpCache) install(ContentNegotiation) { @@ -29,8 +31,12 @@ class OidFederationClient( json() } install(Logging) { - logger = Logger.DEFAULT - level = LogLevel.INFO + logger = object : Logger { + override fun log(message: String) { + com.sphereon.oid.fed.common.logging.Logger.info("API", message) + } + } + level = LogLevel.ALL } if (isRequestAuthenticated) { install(Auth) { @@ -47,21 +53,24 @@ class OidFederationClient( } } - suspend fun fetchEntityStatement(url: String, httpMethod: HttpMethod = Get, parameters: Parameters = Parameters.Empty): EntityStatement { + suspend fun fetchEntityStatement(httpMethod: HttpMethod = Get, parameters: Parameters = Parameters.Empty): EntityStatement { return when (httpMethod) { - Get -> getEntityStatement(url) - Post -> postEntityStatement(url, parameters) + Get -> getEntityStatement(parameters) + Post -> postEntityStatement(parameters) else -> throw IllegalArgumentException("Unsupported HTTP method: $httpMethod") } } - private suspend fun getEntityStatement(url: String): EntityStatement { - return client.use { it.get(url).body() } + private suspend fun getEntityStatement(parameters: Parameters): EntityStatement { + // Appends parameters to the URL + val urlWithParams = if (parameters.isEmpty()) BASE_URL else "$BASE_URL?${parameters.formUrlEncode()}" + + return client.use { it.get(urlWithParams).body() } } - private suspend fun postEntityStatement(url: String, parameters: Parameters): EntityStatement { + private suspend fun postEntityStatement(parameters: Parameters): EntityStatement { return client.use { - it.post(url) { + it.post(BASE_URL) { setBody(FormDataContent(parameters)) }.body() } diff --git a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt index d95a7de8..eef1afab 100644 --- a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt +++ b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt @@ -44,7 +44,10 @@ class OidFederationClientTest { fun testGetEntityStatement() { runBlocking { val client = OidFederationClient(mockEngine) - val response = client.fetchEntityStatement("https://www.example.com?iss=https://edugain.org/federation&sub=https://openid.sunet.se", HttpMethod.Get) + val response = client.fetchEntityStatement(HttpMethod.Get, Parameters.build { + append("iss", "https://edugain.org/federation") + append("sub", "https://openid.sunet.se") + }) assert(response == entityStatement) } } @@ -53,11 +56,10 @@ class OidFederationClientTest { fun testPostEntityStatement() { runBlocking { val client = OidFederationClient(mockEngine) - val response = client.fetchEntityStatement("https://www.example.com", HttpMethod.Post, - Parameters.build { - append("iss","https://edugain.org/federation") - append("sub","https://openid.sunet.se") - }) + val response = client.fetchEntityStatement(HttpMethod.Post, Parameters.build { + append("iss", "https://edugain.org/federation") + append("sub", "https://openid.sunet.se") + }) assert(response == entityStatement) } } From 889eef47a011c7397af1eeb0a2c7202dbe700aa9 Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Mon, 29 Jul 2024 18:49:29 +0530 Subject: [PATCH 23/25] Revert "fix: enabled logger and updated GET call" This reverts commit c82ec0377ed8ec4fc93afc358aeab239ffe12353. --- .../common/httpclient/OidFederationClient.kt | 27 +++++++------------ .../httpclient/OidFederationClientTest.kt | 14 +++++----- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt index 849be404..21b3c548 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClient.kt @@ -22,8 +22,6 @@ class OidFederationClient( private val isRequestAuthenticated: Boolean = false, private val isRequestCached: Boolean = false ) { - private val BASE_URL = "https://www.example.com" - private val client: HttpClient = HttpClient(engine) { install(HttpCache) install(ContentNegotiation) { @@ -31,12 +29,8 @@ class OidFederationClient( json() } install(Logging) { - logger = object : Logger { - override fun log(message: String) { - com.sphereon.oid.fed.common.logging.Logger.info("API", message) - } - } - level = LogLevel.ALL + logger = Logger.DEFAULT + level = LogLevel.INFO } if (isRequestAuthenticated) { install(Auth) { @@ -53,24 +47,21 @@ class OidFederationClient( } } - suspend fun fetchEntityStatement(httpMethod: HttpMethod = Get, parameters: Parameters = Parameters.Empty): EntityStatement { + suspend fun fetchEntityStatement(url: String, httpMethod: HttpMethod = Get, parameters: Parameters = Parameters.Empty): EntityStatement { return when (httpMethod) { - Get -> getEntityStatement(parameters) - Post -> postEntityStatement(parameters) + Get -> getEntityStatement(url) + Post -> postEntityStatement(url, parameters) else -> throw IllegalArgumentException("Unsupported HTTP method: $httpMethod") } } - private suspend fun getEntityStatement(parameters: Parameters): EntityStatement { - // Appends parameters to the URL - val urlWithParams = if (parameters.isEmpty()) BASE_URL else "$BASE_URL?${parameters.formUrlEncode()}" - - return client.use { it.get(urlWithParams).body() } + private suspend fun getEntityStatement(url: String): EntityStatement { + return client.use { it.get(url).body() } } - private suspend fun postEntityStatement(parameters: Parameters): EntityStatement { + private suspend fun postEntityStatement(url: String, parameters: Parameters): EntityStatement { return client.use { - it.post(BASE_URL) { + it.post(url) { setBody(FormDataContent(parameters)) }.body() } diff --git a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt index eef1afab..d95a7de8 100644 --- a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt +++ b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/httpclient/OidFederationClientTest.kt @@ -44,10 +44,7 @@ class OidFederationClientTest { fun testGetEntityStatement() { runBlocking { val client = OidFederationClient(mockEngine) - val response = client.fetchEntityStatement(HttpMethod.Get, Parameters.build { - append("iss", "https://edugain.org/federation") - append("sub", "https://openid.sunet.se") - }) + val response = client.fetchEntityStatement("https://www.example.com?iss=https://edugain.org/federation&sub=https://openid.sunet.se", HttpMethod.Get) assert(response == entityStatement) } } @@ -56,10 +53,11 @@ class OidFederationClientTest { fun testPostEntityStatement() { runBlocking { val client = OidFederationClient(mockEngine) - val response = client.fetchEntityStatement(HttpMethod.Post, Parameters.build { - append("iss", "https://edugain.org/federation") - append("sub", "https://openid.sunet.se") - }) + val response = client.fetchEntityStatement("https://www.example.com", HttpMethod.Post, + Parameters.build { + append("iss","https://edugain.org/federation") + append("sub","https://openid.sunet.se") + }) assert(response == entityStatement) } } From 80b008e072c222325f1401595e3baea8487f3b2a Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Mon, 29 Jul 2024 19:40:19 +0530 Subject: [PATCH 24/25] chores: PR changes --- .../oid/fed/common/logic/EntityLogic.kt | 25 ++++++----------- .../oid/fed/common/mapper/JsonMapper.kt | 28 ++++++------------- .../oid/fed/common/mapper/JsonMapperTest.kt | 6 ++-- 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt index f69aa1c5..3ae15dd3 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/logic/EntityLogic.kt @@ -4,25 +4,18 @@ import com.sphereon.oid.fed.openapi.models.EntityStatement class EntityLogic { - fun getEntityType(entityStatement: EntityStatement): EntityType { - if (isFederationListEndpointPresent(entityStatement) == true && isAuthorityHintPresent(entityStatement) == false) { - return EntityType.TRUST_ANCHOR - } else if (isFederationListEndpointPresent(entityStatement) == true && isAuthorityHintPresent(entityStatement) == true) { - return EntityType.INTERMEDIATE - } else if (isFederationListEndpointPresent(entityStatement) == false && isAuthorityHintPresent(entityStatement) == true) { - return EntityType.LEAF - } else { - return EntityType.UNDEFINED - } + fun getEntityType(entityStatement: EntityStatement): EntityType = when { + isFederationListEndpointPresent(entityStatement) && !isAuthorityHintPresent(entityStatement) -> EntityType.TRUST_ANCHOR + isFederationListEndpointPresent(entityStatement) && isAuthorityHintPresent(entityStatement) -> EntityType.INTERMEDIATE + !isFederationListEndpointPresent(entityStatement) && isAuthorityHintPresent(entityStatement) -> EntityType.LEAF + else -> EntityType.UNDEFINED } - private fun isAuthorityHintPresent(entityStatement: EntityStatement): Boolean { - return entityStatement.authorityHints?.isEmpty() == false - } + private fun isAuthorityHintPresent(entityStatement: EntityStatement): Boolean = + entityStatement.authorityHints?.isNotEmpty() ?: false - private fun isFederationListEndpointPresent(entityStatement: EntityStatement): Boolean { - return entityStatement.metadata?.federationEntity?.federationListEndpoint?.isNotEmpty() == true - } + private fun isFederationListEndpointPresent(entityStatement: EntityStatement): Boolean = + entityStatement.metadata?.federationEntity?.federationListEndpoint?.isNotEmpty() ?: false } enum class EntityType { diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt index e1f28197..0ea17a62 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt @@ -1,5 +1,6 @@ package com.sphereon.oid.fed.common.mapper +import com.sphereon.oid.fed.common.logging.Logger import com.sphereon.oid.fed.openapi.models.EntityStatement import com.sphereon.oid.fed.openapi.models.JWTHeader import com.sphereon.oid.fed.openapi.models.JWTSignature @@ -14,34 +15,23 @@ class JsonMapper { /* * Used for mapping JWT token to EntityStatement object */ - fun mapEntityStatement(jwtToken: String): EntityStatement? { - val data = decodeJWTComponents(jwtToken) - return if (data.second != null) { - Json.decodeFromJsonElement(data.second!!) - } else { - null - } - } + fun mapEntityStatement(jwtToken: String): EntityStatement? = + decodeJWTComponents(jwtToken)?.second?.let { Json.decodeFromJsonElement(it) } /* * Used for mapping trust chain */ - fun mapTrustChain(jwtTokenList: List): List { - val list: MutableList = mutableListOf() - jwtTokenList.forEach { jwtToken -> - list.add(mapEntityStatement(jwtToken)) - } - return list - } + fun mapTrustChain(jwtTokenList: List): List = jwtTokenList.map { mapEntityStatement(it) } /* * Used for decoding JWT to a triple with Header, Payload and Signature */ @OptIn(ExperimentalEncodingApi::class) - fun decodeJWTComponents(jwtToken: String): Triple { + fun decodeJWTComponents(jwtToken: String): Triple? { val parts = jwtToken.split(".") if (parts.size != 3) { - return Triple(null, null, null) + Logger.error(tag = "OIDF", message = "Invalid JWT format: Expected 3 parts, found ${parts.size}") + return null } val headerJson = Base64.decode(parts[0]).decodeToString() @@ -52,8 +42,8 @@ class JsonMapper { Json.decodeFromString(headerJson), Json.parseToJsonElement(payloadJson), JWTSignature(parts[2]) ) } catch (e: Exception) { - println(e.printStackTrace()) - Triple(null, null, null) + Logger.error(tag = "OIDF", message = "Error decoding from string", e) + return null } } } diff --git a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt index 4a04f6ca..d986cee3 100644 --- a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt +++ b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt @@ -15,7 +15,7 @@ class JsonMapperTest { fun testDecodeValidJWT() { val jwt = "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTUxNjIzOTAyMn0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc" - val (header, payload, signature) = mapper.decodeJWTComponents(jwt) + val (header, payload, signature) = mapper.decodeJWTComponents(jwt) ?: Triple(null, null, null) assertEquals("RS256", header?.alg) assertEquals("B6EB8488CC84C41017134BC77F4132A0467CCC0E", header?.kid) @@ -32,7 +32,7 @@ class JsonMapperTest { @Test fun testDecodeJWTWithInvalidStructure() { val invalidJWT = "header.payload.signature" // Missing dots - val (header, payload, signature) = mapper.decodeJWTComponents(invalidJWT) + val (header, payload, signature) = mapper.decodeJWTComponents(invalidJWT) ?: Triple(null, null, null) assertNull(header) assertNull(payload) @@ -43,7 +43,7 @@ class JsonMapperTest { fun testDecodeJWTWithInvalidJSON() { val jwtWithInvalidJson = "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJhZG1pbiI6dHJ1ZX0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc" // Missing quote in payload - val (header, payload, signature) = mapper.decodeJWTComponents(jwtWithInvalidJson) + val (header, payload, signature) = mapper.decodeJWTComponents(jwtWithInvalidJson) ?: Triple(null, null, null) assertNull(header) assertNull(payload) From 6503586a78ff44aa8dd801539f4c51dce510f512 Mon Sep 17 00:00:00 2001 From: Robert Mathew Date: Tue, 30 Jul 2024 14:12:11 +0530 Subject: [PATCH 25/25] fix: PR changes --- .../oid/fed/common/mapper/JsonMapper.kt | 22 +++++++++------- .../oid/fed/common/mapper/JsonMapperTest.kt | 26 +++++++++++-------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt index 0ea17a62..29de6d62 100644 --- a/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt +++ b/modules/openid-federation-common/src/commonMain/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapper.kt @@ -1,6 +1,5 @@ package com.sphereon.oid.fed.common.mapper -import com.sphereon.oid.fed.common.logging.Logger import com.sphereon.oid.fed.openapi.models.EntityStatement import com.sphereon.oid.fed.openapi.models.JWTHeader import com.sphereon.oid.fed.openapi.models.JWTSignature @@ -16,7 +15,7 @@ class JsonMapper { * Used for mapping JWT token to EntityStatement object */ fun mapEntityStatement(jwtToken: String): EntityStatement? = - decodeJWTComponents(jwtToken)?.second?.let { Json.decodeFromJsonElement(it) } + decodeJWTComponents(jwtToken)?.payload?.let { Json.decodeFromJsonElement(it) } /* * Used for mapping trust chain @@ -24,26 +23,31 @@ class JsonMapper { fun mapTrustChain(jwtTokenList: List): List = jwtTokenList.map { mapEntityStatement(it) } /* - * Used for decoding JWT to a triple with Header, Payload and Signature + * Used for decoding JWT to an object of JWT with Header, Payload and Signature */ @OptIn(ExperimentalEncodingApi::class) - fun decodeJWTComponents(jwtToken: String): Triple? { + fun decodeJWTComponents(jwtToken: String): JWT { val parts = jwtToken.split(".") if (parts.size != 3) { - Logger.error(tag = "OIDF", message = "Invalid JWT format: Expected 3 parts, found ${parts.size}") - return null + throw InvalidJwtException("Invalid JWT format: Expected 3 parts, found ${parts.size}") } val headerJson = Base64.decode(parts[0]).decodeToString() val payloadJson = Base64.decode(parts[1]).decodeToString() return try { - Triple( + JWT( Json.decodeFromString(headerJson), Json.parseToJsonElement(payloadJson), JWTSignature(parts[2]) ) } catch (e: Exception) { - Logger.error(tag = "OIDF", message = "Error decoding from string", e) - return null + throw JwtDecodingException("Error decoding JWT components", e) } } + + data class JWT(val header: JWTHeader, val payload: JsonElement, val signature: JWTSignature) + + + // Custom Exceptions + class InvalidJwtException(message: String) : Exception(message) + class JwtDecodingException(message: String, cause: Throwable) : Exception(message, cause) } diff --git a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt index d986cee3..934d482f 100644 --- a/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt +++ b/modules/openid-federation-common/src/commonTest/kotlin/com/sphereon/oid/fed/common/mapper/JsonMapperTest.kt @@ -5,7 +5,8 @@ import kotlinx.serialization.json.boolean import kotlinx.serialization.json.jsonPrimitive import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertNull +import kotlin.test.assertFails +import kotlin.test.assertIs class JsonMapperTest { @@ -15,7 +16,7 @@ class JsonMapperTest { fun testDecodeValidJWT() { val jwt = "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTUxNjIzOTAyMn0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc" - val (header, payload, signature) = mapper.decodeJWTComponents(jwt) ?: Triple(null, null, null) + val (header, payload, signature) = mapper.decodeJWTComponents(jwt) assertEquals("RS256", header?.alg) assertEquals("B6EB8488CC84C41017134BC77F4132A0467CCC0E", header?.kid) @@ -31,22 +32,25 @@ class JsonMapperTest { @Test fun testDecodeJWTWithInvalidStructure() { - val invalidJWT = "header.payload.signature" // Missing dots - val (header, payload, signature) = mapper.decodeJWTComponents(invalidJWT) ?: Triple(null, null, null) + val invalidJWT = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQSflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" // Missing dots - assertNull(header) - assertNull(payload) - assertNull(signature) + val exception = assertFails { + mapper.decodeJWTComponents(invalidJWT) + } + + assertIs(exception) } @Test fun testDecodeJWTWithInvalidJSON() { val jwtWithInvalidJson = "eyJraWQiOiJCNkVCODQ4OENDODRDNDEwMTcxMzRCQzc3RjQxMzJBMDQ2N0NDQzBFIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudFx1MDAyQmp3dCIsImFsZyI6IlJTMjU2In0.eyJzdWI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJhZG1pbiI6dHJ1ZX0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc" // Missing quote in payload - val (header, payload, signature) = mapper.decodeJWTComponents(jwtWithInvalidJson) ?: Triple(null, null, null) - assertNull(header) - assertNull(payload) - assertNull(signature) + val exception = assertFails { + mapper.decodeJWTComponents(jwtWithInvalidJson) + } + + assertIs(exception) } }