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 81622a40..0ad70f8a 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 @@ -3,6 +3,7 @@ package com.sphereon.oid.fed.common.mapper import com.sphereon.oid.fed.openapi.models.EntityConfigurationStatement import com.sphereon.oid.fed.openapi.models.JWTHeader import com.sphereon.oid.fed.openapi.models.JWTSignature +import com.sphereon.oid.fed.openapi.models.SubordinateStatement import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.decodeFromJsonElement @@ -23,6 +24,10 @@ class JsonMapper { decodeJWTComponents(jwtToken).payload.let { Json.decodeFromJsonElement(it) } + fun mapSubordinateStatement(jwtToken: String): SubordinateStatement = + decodeJWTComponents(jwtToken).payload.let { Json.decodeFromJsonElement(it) + } + /* * Used for mapping trust chain */ diff --git a/modules/openid-federation-common/src/jvmMain/kotlin/com/sphereon/oid/fed/common/validation/TrustChainValidation.kt b/modules/openid-federation-common/src/jvmMain/kotlin/com/sphereon/oid/fed/common/validation/TrustChainValidation.kt index eb7369c1..e0568844 100644 --- a/modules/openid-federation-common/src/jvmMain/kotlin/com/sphereon/oid/fed/common/validation/TrustChainValidation.kt +++ b/modules/openid-federation-common/src/jvmMain/kotlin/com/sphereon/oid/fed/common/validation/TrustChainValidation.kt @@ -2,9 +2,15 @@ package com.sphereon.oid.fed.common.validation import com.sphereon.oid.fed.common.httpclient.OidFederationClient import com.sphereon.oid.fed.common.mapper.JsonMapper +import com.sphereon.oid.fed.kms.local.jwt.verify import com.sphereon.oid.fed.openapi.models.EntityConfigurationStatement +import com.sphereon.oid.fed.openapi.models.Jwk +import com.sphereon.oid.fed.openapi.models.SubordinateStatement import io.ktor.client.engine.* import kotlinx.coroutines.runBlocking +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import java.time.OffsetDateTime class TrustChainValidation { @@ -13,9 +19,9 @@ class TrustChainValidation { engine: HttpClientEngine, trustChains: MutableList> = mutableListOf(), trustChain: MutableList = mutableListOf() - ): List>{ + ): List> { requestEntityStatement(partyBId, engine).run { - JsonMapper().mapEntityConfigurationStatement(this)?.let { + JsonMapper().mapEntityConfigurationStatement(this).let { if (it.authorityHints.isNullOrEmpty()) { trustChain.add(it) trustChains.add(trustChain.map { content -> content.copy() }) @@ -36,71 +42,102 @@ class TrustChainValidation { return trustChains } - // -//// TODO must validate subordinate statements too -//fun validateTrustChain(jwts: List): Boolean { -// val entityStatements = jwts.map { JsonMapper().mapEntityStatement(it) } -// -// val firstEntityConfigurationStatement = entityStatements[0] as EntityConfigurationStatement -// val subordinateStatements = entityStatements.map { it as SubordinateStatement }.subList(1, entityStatements.size - 1) -// val lastEntityConfigurationStatement = entityStatements[entityStatements.size - 1] as EntityConfigurationStatement -// -// if(firstEntityConfigurationStatement.iss != firstEntityConfigurationStatement.sub) { -// throw IllegalArgumentException("Entity Configuration of the Trust Chain subject requires that iss is equal to sub") -// } -// -// if (!verify(jwts[0], retrieveJwk(firstEntityConfigurationStatement))) { -// throw IllegalArgumentException("Invalid signature") -// } -// -// subordinateStatements.forEachIndexed { index, current -> -// val next = entityStatements[index + 1] as SubordinateStatement -// if(current.iss != next.sub) { -// throw IllegalArgumentException("Entity Configuration of the Trust Chain subject requires that iss is equal to sub") -// } -// val offsetTime = OffsetDateTime.now() -// if(current.iat > offsetTime.toEpochSecond().toInt()) { -// throw IllegalArgumentException("Invalid iat") -// } -// if(current.exp < offsetTime.toEpochSecond().toInt()) { -// throw IllegalArgumentException("Invalid exp") -// } -// -// if(!verify(jwts[index], retrieveJwk(next))) { -// throw IllegalArgumentException("Invalid signature") -// } -// } -// if(lastEntityConfigurationStatement.iss != "entity_identifier") { -// throw IllegalArgumentException("Entity Configuration of the Trust Chain subject requires that iss is equal to sub") -// } -// if (!verify(jwts[jwts.size - 1], retrieveJwk(lastEntityConfigurationStatement))) { -// throw IllegalArgumentException("Invalid signature") -// } -// return true -//} -// -//fun retrieveJwk(entityStatement: Any?): Jwk { -// return when(entityStatement) { -// is EntityConfigurationStatement -> entityStatement.jwks.let { key -> -// Jwk( -// kid = key.jsonObject["kid"]?.jsonPrimitive?.content, -// kty = key.jsonObject["kty"]?.jsonPrimitive?.content ?: "", -// crv = key.jsonObject["crv"]?.jsonPrimitive?.content, -// x = key.jsonObject["x"]?.jsonPrimitive?.content -// ) -// } -// is SubordinateStatement -> entityStatement.jwks.let { key -> -// Jwk( -// kid = key.jsonObject["kid"]?.jsonPrimitive?.content, -// kty = key.jsonObject["kty"]?.jsonPrimitive?.content ?: "", -// crv = key.jsonObject["crv"]?.jsonPrimitive?.content, -// x = key.jsonObject["x"]?.jsonPrimitive?.content -// ) -// } -// else -> throw IllegalArgumentException("Invalid entity statement") -// } -//} -// + fun fetchSubordinateStatements( + entityConfigurationStatementsList: List>, + engine: HttpClientEngine + ): List> { + val trustChains: MutableList> = mutableListOf() + val trustChain: MutableList = mutableListOf() + entityConfigurationStatementsList.forEach { entityConfigurationStatements -> + entityConfigurationStatements.forEach { it -> + it.metadata?.jsonObject?.get("federation_entity")?.jsonObject?.get("federation_fetch_endpoint")?.jsonPrimitive?.content.let { url -> + requestEntityStatement(url.toString(), engine).run { + trustChain.add(this) + } + } + } + trustChains.add(trustChain) + } + return trustChains + } + + fun validateTrustChain(jwts: List): Boolean { + val entityStatements = jwts.toMutableList() + val firstEntityConfiguration = + entityStatements.removeFirst().let { JsonMapper().mapEntityConfigurationStatement(it) } + val lastEntityConfiguration = + entityStatements.removeLast().let { JsonMapper().mapEntityConfigurationStatement(it) } + val subordinateStatements = entityStatements.map { JsonMapper().mapSubordinateStatement(it) } + + if (firstEntityConfiguration.iss != firstEntityConfiguration.sub) { + throw IllegalArgumentException("Entity Configuration of the Trust Chain subject requires that iss is equal to sub") + } + + if (!verify(jwts[0], retrieveJwk(firstEntityConfiguration))) { + throw IllegalArgumentException("Invalid signature") + } + + subordinateStatements.forEachIndexed { index, current -> + val next = + if (index < subordinateStatements.size - 1) subordinateStatements[index + 1] else lastEntityConfiguration + when (next) { + is EntityConfigurationStatement -> + if (current.iss != next.sub) { + throw IllegalArgumentException("Entity Configuration of the Trust Chain subject requires that iss is equal to sub") + } + + is SubordinateStatement -> + if (current.iss != next.sub) { + throw IllegalArgumentException("Entity Configuration of the Trust Chain subject requires that iss is equal to sub") + } + } + + val offsetTime = OffsetDateTime.now() + if (current.iat > offsetTime.toEpochSecond().toInt()) { + throw IllegalArgumentException("Invalid iat") + } + if (current.exp < offsetTime.toEpochSecond().toInt()) { + throw IllegalArgumentException("Invalid exp") + } + + if (!verify(jwts[index], retrieveJwk(next))) { + throw IllegalArgumentException("Invalid signature") + } + } + + if (lastEntityConfiguration.iss != firstEntityConfiguration.iss) { + throw IllegalArgumentException("Entity Configuration of the Trust Chain subject requires that iss is equal to the Entity Identifier of the Trust Anchor") + } + if (!verify(jwts[jwts.size - 1], retrieveJwk(lastEntityConfiguration))) { + throw IllegalArgumentException("Invalid signature") + } + return true + } + + fun retrieveJwk(entityStatement: Any?): Jwk { + return when (entityStatement) { + is EntityConfigurationStatement -> entityStatement.jwks.let { key -> + Jwk( + kid = key.jsonObject["kid"]?.jsonPrimitive?.content, + kty = key.jsonObject["kty"]?.jsonPrimitive?.content ?: "", + crv = key.jsonObject["crv"]?.jsonPrimitive?.content, + x = key.jsonObject["x"]?.jsonPrimitive?.content + ) + } + + is SubordinateStatement -> entityStatement.jwks.let { key -> + Jwk( + kid = key.jsonObject["kid"]?.jsonPrimitive?.content, + kty = key.jsonObject["kty"]?.jsonPrimitive?.content ?: "", + crv = key.jsonObject["crv"]?.jsonPrimitive?.content, + x = key.jsonObject["x"]?.jsonPrimitive?.content + ) + } + + else -> throw IllegalArgumentException("Invalid entity statement") + } + } + private fun requestEntityStatement(url: String, engine: HttpClientEngine) = runBlocking { return@runBlocking OidFederationClient(engine).fetchEntityStatement(url) } diff --git a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/validation/TrustChainValidationTest.kt b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/validation/TrustChainValidationTest.kt index 6aa565b7..a739983e 100644 --- a/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/validation/TrustChainValidationTest.kt +++ b/modules/openid-federation-common/src/jvmTest/kotlin/com/sphereon/oid/fed/common/validation/TrustChainValidationTest.kt @@ -3,79 +3,187 @@ package com.sphereon.oid.fed.common.validation import com.nimbusds.jose.jwk.Curve import com.nimbusds.jose.jwk.ECKey import com.nimbusds.jose.jwk.gen.ECKeyGenerator +import com.sphereon.oid.fed.kms.local.jwt.sign import com.sphereon.oid.fed.openapi.models.* import io.ktor.client.engine.mock.* import io.ktor.client.engine.mock.MockEngine.Companion.invoke import io.ktor.http.* +import junit.framework.TestCase.assertTrue +import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.jsonObject import org.junit.BeforeClass import java.time.LocalDateTime import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertTrue class TrustChainValidationTest { companion object { // key pairs - lateinit var partyBKeyPair: ECKey - lateinit var intermediateEntityKeyPair: ECKey - lateinit var intermediateEntity1KeyPair: ECKey - lateinit var validTrustAnchorKeyPair: ECKey - lateinit var unknownTrustAnchorKeyPair: ECKey - lateinit var invalidTrustAnchorKeyPair: ECKey + val partyBKeyPair = ECKeyGenerator(Curve.P_256).generate() + val intermediateEntityKeyPair = ECKeyGenerator(Curve.P_256).generate() + val intermediateEntity1KeyPair = ECKeyGenerator(Curve.P_256).generate() + val validTrustAnchorKeyPair = ECKeyGenerator(Curve.P_256).generate() + val unknownTrustAnchorKeyPair = ECKeyGenerator(Curve.P_256).generate() + val invalidTrustAnchorKeyPair = ECKeyGenerator(Curve.P_256).generate() // configurations lateinit var partyBConfiguration: EntityConfigurationStatement lateinit var intermediateEntityConfiguration: EntityConfigurationStatement - lateinit var intermediateEntity1Configuration: EntityConfigurationStatement + lateinit var intermediateEntityConfiguration1: EntityConfigurationStatement lateinit var validTrustAnchorConfiguration: EntityConfigurationStatement lateinit var unknownTrustAnchorConfiguration: EntityConfigurationStatement lateinit var invalidTrustAnchorConfiguration: EntityConfigurationStatement // subordinate statements - lateinit var partyBSubordinateStatement: SubordinateStatement lateinit var intermediateEntitySubordinateStatement: SubordinateStatement lateinit var intermediateEntity1SubordinateStatement: SubordinateStatement lateinit var validTrustAnchorSubordinateStatement: SubordinateStatement lateinit var unknownTrustAnchorSubordinateStatement: SubordinateStatement lateinit var invalidTrustAnchorSubordinateStatement: SubordinateStatement - val listOfEntityConfigurationStatementList = listOf( - listOf( + val partyBJwk = Jwk( + kty = partyBKeyPair.keyType.value, + crv = partyBKeyPair.curve.name, + kid = partyBKeyPair.keyID, + x = partyBKeyPair.x.toString(), + y = partyBKeyPair.y.toString(), + alg = partyBKeyPair.algorithm?.name ?: "ES256", + use = partyBKeyPair.keyUse?.value ?: "sign", + d = partyBKeyPair.d.toString(), + dp = partyBKeyPair.requiredParams.toString() + ) + + val intermediateEntityConfigurationJwk = Jwk( + kty = intermediateEntityKeyPair.keyType.value, + crv = intermediateEntityKeyPair.curve.name, + kid = intermediateEntityKeyPair.keyID, + x = intermediateEntityKeyPair.x.toString(), + y = intermediateEntityKeyPair.y.toString(), + alg = intermediateEntityKeyPair.algorithm?.name ?: "ES256", + use = intermediateEntityKeyPair.keyUse?.value ?: "sign", + d = intermediateEntityKeyPair.d.toString(), + dp = intermediateEntityKeyPair.requiredParams.toString() + ) + + val intermediateEntityConfiguration1Jwk = Jwk( + kty = intermediateEntity1KeyPair.keyType.value, + crv = intermediateEntity1KeyPair.curve.name, + kid = intermediateEntity1KeyPair.keyID, + x = intermediateEntity1KeyPair.x.toString(), + y = intermediateEntity1KeyPair.y.toString(), + alg = intermediateEntity1KeyPair.algorithm?.name ?: "ES256", + use = intermediateEntity1KeyPair.keyUse?.value ?: "sign", + d = intermediateEntity1KeyPair.d.toString(), + dp = intermediateEntity1KeyPair.requiredParams.toString() + ) + + val validTrustAnchorConfigurationJwk = Jwk( + kty = validTrustAnchorKeyPair.keyType.value, + crv = validTrustAnchorKeyPair.curve.name, + kid = validTrustAnchorKeyPair.keyID, + x = validTrustAnchorKeyPair.x.toString(), + y = validTrustAnchorKeyPair.y.toString(), + alg = validTrustAnchorKeyPair.algorithm?.name ?: "ES256", + use = validTrustAnchorKeyPair.keyUse?.value ?: "sign", + d = validTrustAnchorKeyPair.d.toString(), + dp = validTrustAnchorKeyPair.requiredParams.toString() + ) + + val unknownTrustAnchorConfigurationJwk = Jwk( + kty = unknownTrustAnchorKeyPair.keyType.value, + crv = unknownTrustAnchorKeyPair.curve.name, + kid = unknownTrustAnchorKeyPair.keyID, + x = unknownTrustAnchorKeyPair.x.toString(), + y = unknownTrustAnchorKeyPair.y.toString(), + alg = unknownTrustAnchorKeyPair.algorithm?.name ?: "ES256", + use = unknownTrustAnchorKeyPair.keyUse?.value ?: "sign", + d = unknownTrustAnchorKeyPair.d.toString(), + dp = unknownTrustAnchorKeyPair.requiredParams.toString() + ) + + val invalidTrustAnchorConfigurationJwk = Jwk( + kty = invalidTrustAnchorKeyPair.keyType.value, + crv = invalidTrustAnchorKeyPair.curve.name, + kid = invalidTrustAnchorKeyPair.keyID, + x = invalidTrustAnchorKeyPair.x.toString(), + y = invalidTrustAnchorKeyPair.y.toString(), + alg = invalidTrustAnchorKeyPair.algorithm?.name ?: "ES256", + use = invalidTrustAnchorKeyPair.keyUse?.value ?: "sign", + d = invalidTrustAnchorKeyPair.d.toString(), + dp = invalidTrustAnchorKeyPair.requiredParams.toString() + ) + + lateinit var partyBJwt: String + lateinit var intermediateEntityConfigurationJwt: String + lateinit var intermediateEntityConfiguration1Jwt: String + lateinit var validTrustAnchorConfigurationJwt: String + lateinit var unknownTrustAnchorConfigurationJwt: String + lateinit var invalidTrustAnchorConfigurationJwt: String + + lateinit var listOfEntityConfigurationStatementList: MutableList> + + val listOfSubordinateStatementList: MutableList> = mutableListOf( + mutableListOf( "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29wZW5pZC5zdW5ldG9uZS5zZSIsInN1YiI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlIiwiZXhwIjoyMSwiaWF0IjoyMSwiandrcyI6eyJrZXlzIjpbeyJraWQiOm51bGwsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQWdKQzZLb3R2X1FubEI2UENoZEdpeXRydkg2dnVabkFrdzFCN0ZYVlBvZyIsInkiOiJ1M19qOWVETW90RjVDV0R4M2c2V3EybjVWUE1ZZ2plX01Sb1BWME5QX1YwIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiXSwidG9rZW5fZW5kcG9pbnRfYXV0aF9tZXRob2RzX3N1cHBvcnRlZCI6WyJwcml2YXRlX2tleV9qd3QiXX19LCJjcml0IjpudWxsLCJtZXRhZGF0YV9wb2xpY3kiOnsib3BlbmlkX3Byb3ZpZGVyIjp7InN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjp7InZhbHVlIjpbInBhaXJ3aXNlIl19LCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjp7ImRlZmF1bHQiOlsicHJpdmF0ZV9rZXlfand0Il0sInN1YnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiLCJjbGllbnRfc2VjcmV0X2p3dCJdLCJzdXBlcnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiXX19fSwiY29uc3RyYWludHMiOm51bGwsIm1ldGFkYXRhX3BvbGljeV9jcml0IjpudWxsLCJzb3VyY2VfZW5kcG9pbnQiOiJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb24vZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCJ9.psisFesGRDx_-iBEfb_sb6ydpKh9ih5vWTTmmYk4i1ZYZOgLxodrSkRWcDq4agRadcTj8XyZiDd3CYQtQIH8N1fPgrvMJTAGOQxpYG31GN0gDaWmFvpTMEynPY4NxFh5oP9oR7VjYRe_hxLcI_fFhO0GHyPDaHmPXi2jvPQ9Wg-bYOMkHmf9YbbQ30GSHZWhd-Kg3xsbmEqGg91Jj70UYwPQT3h9tI7-OELExU6WSQLT6HSVQTuMdhIoLp_f7ELkeUdO3YLxQyZ8h5QU1lTHrycAIQ1g-9NkyCOJQWrzWojxwP30yLWvaPPfwjz01jHfymIjtE0fOlRqZ-xMrJFzpQ", "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29wZW5pZC5zdW5ldG9uZS5zZSIsInN1YiI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlIiwiZXhwIjoyMSwiaWF0IjoyMSwiandrcyI6eyJrZXlzIjpbeyJraWQiOm51bGwsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQWdKQzZLb3R2X1FubEI2UENoZEdpeXRydkg2dnVabkFrdzFCN0ZYVlBvZyIsInkiOiJ1M19qOWVETW90RjVDV0R4M2c2V3EybjVWUE1ZZ2plX01Sb1BWME5QX1YwIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiXSwidG9rZW5fZW5kcG9pbnRfYXV0aF9tZXRob2RzX3N1cHBvcnRlZCI6WyJwcml2YXRlX2tleV9qd3QiXX19LCJjcml0IjpudWxsLCJtZXRhZGF0YV9wb2xpY3kiOnsib3BlbmlkX3Byb3ZpZGVyIjp7InN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjp7InZhbHVlIjpbInBhaXJ3aXNlIl19LCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjp7ImRlZmF1bHQiOlsicHJpdmF0ZV9rZXlfand0Il0sInN1YnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiLCJjbGllbnRfc2VjcmV0X2p3dCJdLCJzdXBlcnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiXX19fSwiY29uc3RyYWludHMiOm51bGwsIm1ldGFkYXRhX3BvbGljeV9jcml0IjpudWxsLCJzb3VyY2VfZW5kcG9pbnQiOiJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb25fb25lL2ZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQifQ.elvdpFKwSmXO878CeE3iK2LAmlPV9_iBcuDM3JL7_zJ9UWay0K-QCrlwbqWNxkH-d0DrnKh1KHZGarQ1u9OB0Q2CFCplkbdNiQc7qUpSk1aHoaz30O9p7o4qKtNjz8AV3gE0xKFLnkj6M7rJZ3POC8AONelC1eaGe4AfgNzd7JgWd_lQGV2esNUoq5x9udjXrX1HW--PAC6vue-F-Tcx_TU2Dff3qOkW-SJvbvGnxVdvirutsJoXdae9yGMQLoi3Araefr1Tfjvd1MSxhlUL80eASrT3XgHZEeajN8ijeYUuaY36K_gCxzxkrgypXZyfZptSIGDctOuj8GucZNz9FA", "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29wZW5pZC5zdW5ldG9uZS5zZSIsInN1YiI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlIiwiZXhwIjoyMSwiaWF0IjoyMSwiandrcyI6eyJrZXlzIjpbeyJraWQiOm51bGwsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQWdKQzZLb3R2X1FubEI2UENoZEdpeXRydkg2dnVabkFrdzFCN0ZYVlBvZyIsInkiOiJ1M19qOWVETW90RjVDV0R4M2c2V3EybjVWUE1ZZ2plX01Sb1BWME5QX1YwIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiXSwidG9rZW5fZW5kcG9pbnRfYXV0aF9tZXRob2RzX3N1cHBvcnRlZCI6WyJwcml2YXRlX2tleV9qd3QiXX19LCJjcml0IjpudWxsLCJtZXRhZGF0YV9wb2xpY3kiOnsib3BlbmlkX3Byb3ZpZGVyIjp7InN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjp7InZhbHVlIjpbInBhaXJ3aXNlIl19LCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjp7ImRlZmF1bHQiOlsicHJpdmF0ZV9rZXlfand0Il0sInN1YnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiLCJjbGllbnRfc2VjcmV0X2p3dCJdLCJzdXBlcnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiXX19fSwiY29uc3RyYWludHMiOm51bGwsIm1ldGFkYXRhX3BvbGljeV9jcml0IjpudWxsLCJzb3VyY2VfZW5kcG9pbnQiOiJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb25fdHdvL2ZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQifQ.eJCajk2u8NMpq2Qi8tUUW4yT3t8zN5efdMz95Qg2Edc9-xXp32V6POp2Zmj3M99TyUrp9YwK9TEesH_7oz5QXYFR4J5cNkvd4mJvpDudvgayvlW_3z4nLUWru8nCfSyH_PiSwbPdhpiUZGvf5-KZHMdQ0SAbp5GSMSf4CD8fIYEV8u_KyS38g9Zgsv6BoQzCZtEPtY_cLCG9YV1S7V3tLsW5-bhf8da8mEny1cdnSLI6YJanQxmpW9Aq0ooxntIo1cokeL2fFoUvzNw-4JhYLOgqVDSNg3lhNhsbiPxHI3yN04Qcn90h0s1--QFHaf8rgMWyLyKZPId4kxPR-4PZoQ", - "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29wZW5pZC5zdW5ldG9uZS5zZSIsInN1YiI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlIiwiZXhwIjoyMSwiaWF0IjoyMSwiandrcyI6eyJrZXlzIjpbeyJraWQiOm51bGwsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQWdKQzZLb3R2X1FubEI2UENoZEdpeXRydkg2dnVabkFrdzFCN0ZYVlBvZyIsInkiOiJ1M19qOWVETW90RjVDV0R4M2c2V3EybjVWUE1ZZ2plX01Sb1BWME5QX1YwIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiXSwidG9rZW5fZW5kcG9pbnRfYXV0aF9tZXRob2RzX3N1cHBvcnRlZCI6WyJwcml2YXRlX2tleV9qd3QiXX19LCJjcml0IjpudWxsLCJtZXRhZGF0YV9wb2xpY3kiOnsib3BlbmlkX3Byb3ZpZGVyIjp7InN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjp7InZhbHVlIjpbInBhaXJ3aXNlIl19LCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjp7ImRlZmF1bHQiOlsicHJpdmF0ZV9rZXlfand0Il0sInN1YnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiLCJjbGllbnRfc2VjcmV0X2p3dCJdLCJzdXBlcnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiXX19fSwiY29uc3RyYWludHMiOm51bGwsIm1ldGFkYXRhX3BvbGljeV9jcml0IjpudWxsLCJzb3VyY2VfZW5kcG9pbnQiOiJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb25fdGhyZWUvZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCJ9.ZnPDr-p8_RF9vI_DUqEuld-iJSPTMC5IL_B6rp_7mK1L4F_TXg0WJBP7uyn1dpkuS-Cd0V5oqHjtsxJgCoToqXGc2qvewktHOPEVKmIEVm25ALMVfiU0HZE1fU78crpF7xEo4UVBMHq78_Kk1QUg-SPmjGtS3IJ1e-EW8kxdnUVXvSsqP1pPh1iXVIjUHlQsh0SbfIbmLDmu5xYjlXXzad56zJv1G0Jov8gWw8wPYOwWY2j06MwQghu_N-ViyeFDa1UYjo4XChtU_tirFF5NzcxYfUnJUnATRgC_GuuQz5zmBEbrry252EED86lPV8UVTd9RhS1Ks9k8yJeAN8-LvA" - ), + "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29wZW5pZC5zdW5ldG9uZS5zZSIsInN1YiI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlIiwiZXhwIjoyMSwiaWF0IjoyMSwiandrcyI6eyJrZXlzIjpbeyJraWQiOm51bGwsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQWdKQzZLb3R2X1FubEI2UENoZEdpeXRydkg2dnVabkFrdzFCN0ZYVlBvZyIsInkiOiJ1M19qOWVETW90RjVDV0R4M2c2V3EybjVWUE1ZZ2plX01Sb1BWME5QX1YwIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiXSwidG9rZW5fZW5kcG9pbnRfYXV0aF9tZXRob2RzX3N1cHBvcnRlZCI6WyJwcml2YXRlX2tleV9qd3QiXX19LCJjcml0IjpudWxsLCJtZXRhZGF0YV9wb2xpY3kiOnsib3BlbmlkX3Byb3ZpZGVyIjp7InN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjp7InZhbHVlIjpbInBhaXJ3aXNlIl19LCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjp7ImRlZmF1bHQiOlsicHJpdmF0ZV9rZXlfand0Il0sInN1YnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiLCJjbGllbnRfc2VjcmV0X2p3dCJdLCJzdXBlcnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiXX19fSwiY29uc3RyYWludHMiOm51bGwsIm1ldGFkYXRhX3BvbGljeV9jcml0IjpudWxsLCJzb3VyY2VfZW5kcG9pbnQiOiJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb25fdGhyZWUvZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCJ9.ZnPDr-p8_RF9vI_DUqEuld-iJSPTMC5IL_B6rp_7mK1L4F_TXg0WJBP7uyn1dpkuS-Cd0V5oqHjtsxJgCoToqXGc2qvewktHOPEVKmIEVm25ALMVfiU0HZE1fU78crpF7xEo4UVBMHq78_Kk1QUg-SPmjGtS3IJ1e-EW8kxdnUVXvSsqP1pPh1iXVIjUHlQsh0SbfIbmLDmu5xYjlXXzad56zJv1G0Jov8gWw8wPYOwWY2j06MwQghu_N-ViyeFDa1UYjo4XChtU_tirFF5NzcxYfUnJUnATRgC_GuuQz5zmBEbrry252EED86lPV8UVTd9RhS1Ks9k8yJeAN8-LvA", + ) ) @JvmStatic @BeforeClass fun setup(): Unit { - partyBKeyPair = ECKeyGenerator(Curve.P_256).generate() + + // Party B Entity Configuration (federation) + partyBConfiguration = entityConfiguration( publicKey = partyBKeyPair.toPublicJWK(), - authorityHints = arrayOf("https://edugain.org/federation"), + authorityHints = arrayOf( + "https://edugain.org/federation_one", + "https://edugain.org/federation_two" + ), + iss = "https://openid.sunet.se", + sub = "https://openid.sunet.se" ) - partyBSubordinateStatement = intermediateEntity( - publicKey = partyBKeyPair.toPublicJWK() + + partyBJwt = sign( + payload = Json.encodeToJsonElement(serializer = EntityConfigurationStatement.serializer(), partyBConfiguration).jsonObject, + header = JWTHeader( + alg = "ES256", + typ = "entity-statement+jwt", + kid = partyBKeyPair.keyID + ), + key = partyBJwk ) - intermediateEntityKeyPair = ECKeyGenerator(Curve.P_256).generate() + // Intermediate 1 ( Federation 2 ) + intermediateEntityConfiguration = entityConfiguration( publicKey = intermediateEntityKeyPair.toPublicJWK(), authorityHints = arrayOf( - "https://edugain.org/federation_one", - "https://edugain.org/federation_two" + "https://edugain.org/federation_three", + "https://edugain.org/federation_four" ), iss = "https://openid.sunet.se", sub = "https://openid.sunet.se" ) + intermediateEntityConfigurationJwt = sign( + payload = Json.encodeToJsonElement(serializer = EntityConfigurationStatement.serializer(), intermediateEntityConfiguration).jsonObject, + header = JWTHeader( + alg = "ES256", + typ = "entity-statement+jwt", + kid = intermediateEntityKeyPair.keyID + ), + key = intermediateEntityConfigurationJwk + ) + //signed with intermediateEntity1 Private Key intermediateEntitySubordinateStatement = intermediateEntity( publicKey = intermediateEntityKeyPair.toPublicJWK(), @@ -83,100 +191,167 @@ class TrustChainValidationTest { sub = "https://openid.sunet.se" ) - intermediateEntity1KeyPair = ECKeyGenerator(Curve.P_256).generate() - intermediateEntity1Configuration = entityConfiguration( + intermediateEntityConfiguration1 = entityConfiguration( publicKey = intermediateEntity1KeyPair.toPublicJWK(), - authorityHints = arrayOf("https://edugain.org/federation_three"), + authorityHints = arrayOf("https://edugain.org/federation_five"), iss = "https://openid.sunetone.se", sub = "https://openid.sunetone.se" ) + + intermediateEntityConfiguration1Jwt = sign( + payload = Json.encodeToJsonElement(serializer = EntityConfigurationStatement.serializer(), intermediateEntityConfiguration1).jsonObject, + header = JWTHeader( + alg = "ES256", + typ = "entity-statement+jwt", + kid = intermediateEntity1KeyPair.keyID + ), + key = intermediateEntityConfiguration1Jwk + ) + intermediateEntity1SubordinateStatement = intermediateEntity( publicKey = intermediateEntity1KeyPair.toPublicJWK(), iss = "https://openid.sunettwo.se", sub = "https://openid.sunetone.se" ) - validTrustAnchorKeyPair = ECKeyGenerator(Curve.P_256).generate() + // Federation 4 validTrustAnchorConfiguration = entityConfiguration( publicKey = validTrustAnchorKeyPair.toPublicJWK(), authorityHints = arrayOf(), iss = "https://openid.sunetthree.se", sub = "https://openid.sunettwo.se" ) + + validTrustAnchorConfigurationJwt = sign( + payload = Json.encodeToJsonElement(serializer = EntityConfigurationStatement.serializer(), validTrustAnchorConfiguration).jsonObject, + header = JWTHeader( + alg = "ES256", + typ = "entity-statement+jwt", + kid = validTrustAnchorKeyPair.keyID + ), + key = validTrustAnchorConfigurationJwk + ) + validTrustAnchorSubordinateStatement = intermediateEntity( publicKey = validTrustAnchorKeyPair.toPublicJWK(), iss = "https://openid.sunetthree.se", sub = "https://openid.sunetthree.se" ) - unknownTrustAnchorKeyPair = ECKeyGenerator(Curve.P_256).generate() + // Federation 3 unknownTrustAnchorConfiguration = entityConfiguration( publicKey = unknownTrustAnchorKeyPair.toPublicJWK(), authorityHints = arrayOf(), - iss = "https://openid.sunetfour.se", // Should match the id of the trust anchor + iss = "https://openid.sunetfour.se", sub = "https://openid.sunetone.se" ) + + unknownTrustAnchorConfigurationJwt = sign( + payload = Json.encodeToJsonElement(serializer = EntityConfigurationStatement.serializer(), unknownTrustAnchorConfiguration).jsonObject, + header = JWTHeader( + alg = "ES256", + typ = "entity-statement+jwt", + kid = unknownTrustAnchorKeyPair.keyID + ), + key = unknownTrustAnchorConfigurationJwk + ) + unknownTrustAnchorSubordinateStatement = intermediateEntity( publicKey = unknownTrustAnchorKeyPair.toPublicJWK(), iss = "https://openid.sunetfour.se", sub = "https://openid.sunetfour.se" ) - invalidTrustAnchorKeyPair = ECKeyGenerator(Curve.P_256).generate() + // Federation 1 invalidTrustAnchorConfiguration = entityConfiguration( publicKey = invalidTrustAnchorKeyPair.toPublicJWK(), authorityHints = arrayOf(), - iss = "https://openid.sunetfive.se", // Should match the id of the trust anchor + iss = "https://openid.sunetfive.se", sub = "https://openid.sunetfour.se" ) + + invalidTrustAnchorConfigurationJwt = sign( + payload = Json.encodeToJsonElement(serializer = EntityConfigurationStatement.serializer(), invalidTrustAnchorConfiguration).jsonObject, + header = JWTHeader( + alg = "ES256", + typ = "entity-statement+jwt", + kid = invalidTrustAnchorKeyPair.keyID + ), + key = invalidTrustAnchorConfigurationJwk + ) + invalidTrustAnchorSubordinateStatement = intermediateEntity( publicKey = invalidTrustAnchorKeyPair.toPublicJWK(), iss = "https://openid.sunetfive.se", sub = "https://openid.sunetfive.se" ) + + listOfEntityConfigurationStatementList = mutableListOf( + mutableListOf( + partyBConfiguration, invalidTrustAnchorConfiguration + ), + mutableListOf( + partyBConfiguration, intermediateEntityConfiguration, unknownTrustAnchorConfiguration + ), + mutableListOf( + partyBConfiguration, intermediateEntityConfiguration, intermediateEntityConfiguration1, validTrustAnchorConfiguration + ) + ) } } private val mockEngine = MockEngine { request -> when (request.url) { Url("https://edugain.org/federation") -> respond( - content = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiIgaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UiLCJzdWIiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZSIsImV4cCI6NDgsImlhdCI6NDgsImp3a3MiOnsia2V5cyI6W3sia2lkIjpudWxsLCJrdHkiOiJFQyIsImNydiI6IlAyNTYiLCJ4IjoiRmtWYzdmMTZPX0E4UEpVandOVEVFME10eF9FSTM4OXRPdlo1YzhtaVJwWSIsInkiOiJkX0ktTUdwWHh5SzVfR3Y1RHFwZnRJblVyLUo2X3RjQU1TMzdkMXdlY1VRIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsiZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCI6Imh0dHBzOi8vZWR1Z2Fpbi5vcmcvZmVkZXJhdGlvbi9mZWRlcmF0aW9uX2ZldGNoX2VuZHBvaW50IiwiaG9tZXBhZ2VfdXJpIjoiaHR0cHM6Ly93d3cuc3VuZXQuc2UiLCJvcmdhbml6YXRpb25fbmFtZSI6IlNVTkVUIn0sIm9wZW5pZF9wcm92aWRlciI6eyJpc3N1ZXIiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZSIsImF1dGhvcml6YXRpb25fZW5kcG9pbnQiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZS9hdXRob3JpemF0aW9uIiwiZ3JhbnRfdHlwZXNfc3VwcG9ydGVkIjpbImF1dGhvcml6YXRpb25fY29kZSJdLCJpZF90b2tlbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2IiwiRVMyNTYiXSwibG9nb191cmkiOiJodHRwczovL3d3dy51bXUuc2UvaW1nL3VtdS1sb2dvLWxlZnQtbmVnLlNFLnN2ZyIsIm9wX3BvbGljeV91cmkiOiJvcF9wb2xpY3lfdXJpIiwicmVzcG9uc2VfdHlwZXNfc3VwcG9ydGVkIjpbImNvZGUiXSwic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiLCJwdWJsaWMiXSwidG9rZW5fZW5kcG9pbnQiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZS90b2tlbiIsInRva2VuX2VuZHBvaW50X2F1dGhfbWV0aG9kc19zdXBwb3J0ZWQiOlsicHJpdmF0ZV9rZXlfand0Il0sImp3a3NfdXJpIjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UvandrcyJ9fSwiY3JpdCI6bnVsbCwiYXV0aG9yaXR5X2hpbnRzIjpbImh0dHBzOi8vZWR1Z2Fpbi5vcmcvZmVkZXJhdGlvbl9vbmUiXSwidHJ1c3RfbWFya3MiOm51bGwsInRydXN0X21hcmtfaXNzdWVycyI6bnVsbCwidHJ1c3RfbWFya19vd25lcnMiOm51bGx9.tP7ObwU01pj-05f56XDQ5jN6EDY217_L_nvhhKPsmaCPP1IW6w9n_o-AlXcU8lFDwdYmrO-4H_i-TEOsoJYhxcTCsnL4DVNNF7aLNFDlYjnmteQM06uCZbq9XVfCsIpDtcnFTnH7DQAG5Bs0vu-Imnc9LREFr1nSeL2dNTEtEcqH_wjno5d_u3DulrZeIyDwN7W_Q2xFMr245PcI9CMtn6jzPJw3l9qV7EK9A5HqmaUHCi5od8XYcJUq2EnPQBMJ21tOLei_1vTxt_KG5ANvAf8CKr6Ehp5IntA5R-df4xqL6lEhEjhrC6EBpQcaF5gehRbweZNKQlb8Ex39VaU95w", + content = partyBJwt, status = HttpStatusCode.OK, headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") ) - Url("https://edugain.org/federation/federation_fetch_endpoint") -> respond( - content = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29wZW5pZC5zdW5ldG9uZS5zZSIsInN1YiI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlIiwiZXhwIjoyMSwiaWF0IjoyMSwiandrcyI6eyJrZXlzIjpbeyJraWQiOm51bGwsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQWdKQzZLb3R2X1FubEI2UENoZEdpeXRydkg2dnVabkFrdzFCN0ZYVlBvZyIsInkiOiJ1M19qOWVETW90RjVDV0R4M2c2V3EybjVWUE1ZZ2plX01Sb1BWME5QX1YwIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiXSwidG9rZW5fZW5kcG9pbnRfYXV0aF9tZXRob2RzX3N1cHBvcnRlZCI6WyJwcml2YXRlX2tleV9qd3QiXX19LCJjcml0IjpudWxsLCJtZXRhZGF0YV9wb2xpY3kiOnsib3BlbmlkX3Byb3ZpZGVyIjp7InN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjp7InZhbHVlIjpbInBhaXJ3aXNlIl19LCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjp7ImRlZmF1bHQiOlsicHJpdmF0ZV9rZXlfand0Il0sInN1YnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiLCJjbGllbnRfc2VjcmV0X2p3dCJdLCJzdXBlcnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiXX19fSwiY29uc3RyYWludHMiOm51bGwsIm1ldGFkYXRhX3BvbGljeV9jcml0IjpudWxsLCJzb3VyY2VfZW5kcG9pbnQiOiJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb24vZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCJ9.psisFesGRDx_-iBEfb_sb6ydpKh9ih5vWTTmmYk4i1ZYZOgLxodrSkRWcDq4agRadcTj8XyZiDd3CYQtQIH8N1fPgrvMJTAGOQxpYG31GN0gDaWmFvpTMEynPY4NxFh5oP9oR7VjYRe_hxLcI_fFhO0GHyPDaHmPXi2jvPQ9Wg-bYOMkHmf9YbbQ30GSHZWhd-Kg3xsbmEqGg91Jj70UYwPQT3h9tI7-OELExU6WSQLT6HSVQTuMdhIoLp_f7ELkeUdO3YLxQyZ8h5QU1lTHrycAIQ1g-9NkyCOJQWrzWojxwP30yLWvaPPfwjz01jHfymIjtE0fOlRqZ-xMrJFzpQ", + Url("https://edugain.org/federation_one") -> respond( + content = invalidTrustAnchorConfigurationJwt, status = HttpStatusCode.OK, headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") ) - Url("https://edugain.org/federation_one") -> respond( - content = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiIgaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UiLCJzdWIiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZSIsImV4cCI6NDgsImlhdCI6NDgsImp3a3MiOnsia2V5cyI6W3sia2lkIjpudWxsLCJrdHkiOiJFQyIsImNydiI6IlAyNTYiLCJ4IjoiRmtWYzdmMTZPX0E4UEpVandOVEVFME10eF9FSTM4OXRPdlo1YzhtaVJwWSIsInkiOiJkX0ktTUdwWHh5SzVfR3Y1RHFwZnRJblVyLUo2X3RjQU1TMzdkMXdlY1VRIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsiZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCI6Imh0dHBzOi8vZWR1Z2Fpbi5vcmcvZmVkZXJhdGlvbl9vbmUvZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCIsImhvbWVwYWdlX3VyaSI6Imh0dHBzOi8vd3d3LnN1bmV0LnNlIiwib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsiaXNzdWVyIjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UiLCJhdXRob3JpemF0aW9uX2VuZHBvaW50IjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UvYXV0aG9yaXphdGlvbiIsImdyYW50X3R5cGVzX3N1cHBvcnRlZCI6WyJhdXRob3JpemF0aW9uX2NvZGUiXSwiaWRfdG9rZW5fc2lnbmluZ19hbGdfdmFsdWVzX3N1cHBvcnRlZCI6WyJSUzI1NiIsIkVTMjU2Il0sImxvZ29fdXJpIjoiaHR0cHM6Ly93d3cudW11LnNlL2ltZy91bXUtbG9nby1sZWZ0LW5lZy5TRS5zdmciLCJvcF9wb2xpY3lfdXJpIjoib3BfcG9saWN5X3VyaSIsInJlc3BvbnNlX3R5cGVzX3N1cHBvcnRlZCI6WyJjb2RlIl0sInN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjpbInBhaXJ3aXNlIiwicHVibGljIl0sInRva2VuX2VuZHBvaW50IjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UvdG9rZW4iLCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjpbInByaXZhdGVfa2V5X2p3dCJdLCJqd2tzX3VyaSI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlL2p3a3MifX0sImNyaXQiOm51bGwsImF1dGhvcml0eV9oaW50cyI6WyJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb25fdHdvIl0sInRydXN0X21hcmtzIjpudWxsLCJ0cnVzdF9tYXJrX2lzc3VlcnMiOm51bGwsInRydXN0X21hcmtfb3duZXJzIjpudWxsfQ.A6TKVthUEUgjJL-XNa_mPEx_n-gpeFcPvla4HzMepTBv6VjIiG1YSVvgBBA3SiHSPt9Eqx5NKWKN0YpXSNcootff7JZTlQSLRk-K2vwPmNOE2NLg6B40c2cYi36E6rVIon-4Q0zJC0WdvN1lDrS1_gwL_pReToCwFKQG42MyXjJzKlWNIqYLyMcBr5qoHBW3hhCXPdWxw3FKc8_kVqPAjXNkkB4VH44R1XOYvK3OYo27f26GEstChA8nHZwZak0ky2powMwWNh36_YyjxaJvyPiIvNUqcsYgRG3IVrRw7Lhd0qT_Um3z8ZGuSsESSThZQOfw_J2cq7Esem8VKwmo3w", + Url("https://edugain.org/federation_two") -> respond( + content = intermediateEntityConfigurationJwt, status = HttpStatusCode.OK, headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") ) - Url("https://edugain.org/federation_one/federation_fetch_endpoint") -> respond( - content = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29wZW5pZC5zdW5ldG9uZS5zZSIsInN1YiI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlIiwiZXhwIjoyMSwiaWF0IjoyMSwiandrcyI6eyJrZXlzIjpbeyJraWQiOm51bGwsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQWdKQzZLb3R2X1FubEI2UENoZEdpeXRydkg2dnVabkFrdzFCN0ZYVlBvZyIsInkiOiJ1M19qOWVETW90RjVDV0R4M2c2V3EybjVWUE1ZZ2plX01Sb1BWME5QX1YwIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiXSwidG9rZW5fZW5kcG9pbnRfYXV0aF9tZXRob2RzX3N1cHBvcnRlZCI6WyJwcml2YXRlX2tleV9qd3QiXX19LCJjcml0IjpudWxsLCJtZXRhZGF0YV9wb2xpY3kiOnsib3BlbmlkX3Byb3ZpZGVyIjp7InN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjp7InZhbHVlIjpbInBhaXJ3aXNlIl19LCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjp7ImRlZmF1bHQiOlsicHJpdmF0ZV9rZXlfand0Il0sInN1YnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiLCJjbGllbnRfc2VjcmV0X2p3dCJdLCJzdXBlcnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiXX19fSwiY29uc3RyYWludHMiOm51bGwsIm1ldGFkYXRhX3BvbGljeV9jcml0IjpudWxsLCJzb3VyY2VfZW5kcG9pbnQiOiJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb25fb25lL2ZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQifQ.elvdpFKwSmXO878CeE3iK2LAmlPV9_iBcuDM3JL7_zJ9UWay0K-QCrlwbqWNxkH-d0DrnKh1KHZGarQ1u9OB0Q2CFCplkbdNiQc7qUpSk1aHoaz30O9p7o4qKtNjz8AV3gE0xKFLnkj6M7rJZ3POC8AONelC1eaGe4AfgNzd7JgWd_lQGV2esNUoq5x9udjXrX1HW--PAC6vue-F-Tcx_TU2Dff3qOkW-SJvbvGnxVdvirutsJoXdae9yGMQLoi3Araefr1Tfjvd1MSxhlUL80eASrT3XgHZEeajN8ijeYUuaY36K_gCxzxkrgypXZyfZptSIGDctOuj8GucZNz9FA", + Url("https://edugain.org/federation_three") -> respond( + content = unknownTrustAnchorConfigurationJwt, status = HttpStatusCode.OK, headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") ) - Url("https://edugain.org/federation_two") -> respond( - content = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiIgaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UiLCJzdWIiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZSIsImV4cCI6NDgsImlhdCI6NDgsImp3a3MiOnsia2V5cyI6W3sia2lkIjpudWxsLCJrdHkiOiJFQyIsImNydiI6IlAyNTYiLCJ4IjoiRmtWYzdmMTZPX0E4UEpVandOVEVFME10eF9FSTM4OXRPdlo1YzhtaVJwWSIsInkiOiJkX0ktTUdwWHh5SzVfR3Y1RHFwZnRJblVyLUo2X3RjQU1TMzdkMXdlY1VRIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsiZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCI6Imh0dHBzOi8vZWR1Z2Fpbi5vcmcvZmVkZXJhdGlvbl90d28vZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCIsImhvbWVwYWdlX3VyaSI6Imh0dHBzOi8vd3d3LnN1bmV0LnNlIiwib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsiaXNzdWVyIjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UiLCJhdXRob3JpemF0aW9uX2VuZHBvaW50IjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UvYXV0aG9yaXphdGlvbiIsImdyYW50X3R5cGVzX3N1cHBvcnRlZCI6WyJhdXRob3JpemF0aW9uX2NvZGUiXSwiaWRfdG9rZW5fc2lnbmluZ19hbGdfdmFsdWVzX3N1cHBvcnRlZCI6WyJSUzI1NiIsIkVTMjU2Il0sImxvZ29fdXJpIjoiaHR0cHM6Ly93d3cudW11LnNlL2ltZy91bXUtbG9nby1sZWZ0LW5lZy5TRS5zdmciLCJvcF9wb2xpY3lfdXJpIjoib3BfcG9saWN5X3VyaSIsInJlc3BvbnNlX3R5cGVzX3N1cHBvcnRlZCI6WyJjb2RlIl0sInN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjpbInBhaXJ3aXNlIiwicHVibGljIl0sInRva2VuX2VuZHBvaW50IjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UvdG9rZW4iLCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjpbInByaXZhdGVfa2V5X2p3dCJdLCJqd2tzX3VyaSI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlL2p3a3MifX0sImNyaXQiOm51bGwsImF1dGhvcml0eV9oaW50cyI6WyJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb25fdGhyZWUiXSwidHJ1c3RfbWFya3MiOm51bGwsInRydXN0X21hcmtfaXNzdWVycyI6bnVsbCwidHJ1c3RfbWFya19vd25lcnMiOm51bGx9.bfINUjOaCxvVVtnTBCOyGKgHgvym_FD-oFRa33xAWYgs2zBGbj2PZfFma8W4eH_I6GDmHcM0S65C-rT96oqBbUBM0LmnJ5ztJs5DZSc69QN0Q_TgEtq4r6mZQQIbBPxTeWqbiAwMaF0QxBA38Y312aeQU9mCaxOI7CX8PUzSQtps6m81vGfLBscBHfi3Qnh-aC2Ob7NnR_9kACn-9Ddj_AoZgjRGDCqpQd9sBpkcwno7uFqy02-vjuzX-wGio1q7NTXqzuV1eI7OSXj-1pxR09I1k8G3aBud2NMGTohBlA9VB6-oUYZFfIV1b_WXoSxz1oS-67g8FADiYStsiaDVjA", + Url("https://edugain.org/federation_four") -> respond( + content = intermediateEntityConfiguration1Jwt, status = HttpStatusCode.OK, headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") ) - Url("https://edugain.org/federation_two/federation_fetch_endpoint") -> respond( - content = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29wZW5pZC5zdW5ldG9uZS5zZSIsInN1YiI6Imh0dHBzOi8vb3BlbmlkLnN1bmV0LnNlIiwiZXhwIjoyMSwiaWF0IjoyMSwiandrcyI6eyJrZXlzIjpbeyJraWQiOm51bGwsImt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQWdKQzZLb3R2X1FubEI2UENoZEdpeXRydkg2dnVabkFrdzFCN0ZYVlBvZyIsInkiOiJ1M19qOWVETW90RjVDV0R4M2c2V3EybjVWUE1ZZ2plX01Sb1BWME5QX1YwIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsib3JnYW5pemF0aW9uX25hbWUiOiJTVU5FVCJ9LCJvcGVuaWRfcHJvdmlkZXIiOnsic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiXSwidG9rZW5fZW5kcG9pbnRfYXV0aF9tZXRob2RzX3N1cHBvcnRlZCI6WyJwcml2YXRlX2tleV9qd3QiXX19LCJjcml0IjpudWxsLCJtZXRhZGF0YV9wb2xpY3kiOnsib3BlbmlkX3Byb3ZpZGVyIjp7InN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjp7InZhbHVlIjpbInBhaXJ3aXNlIl19LCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjp7ImRlZmF1bHQiOlsicHJpdmF0ZV9rZXlfand0Il0sInN1YnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiLCJjbGllbnRfc2VjcmV0X2p3dCJdLCJzdXBlcnNldF9vZiI6WyJwcml2YXRlX2tleV9qd3QiXX19fSwiY29uc3RyYWludHMiOm51bGwsIm1ldGFkYXRhX3BvbGljeV9jcml0IjpudWxsLCJzb3VyY2VfZW5kcG9pbnQiOiJodHRwczovL2VkdWdhaW4ub3JnL2ZlZGVyYXRpb25fdHdvL2ZlZGVyYXRpb25fZmV0Y2hfZW5kcG9pbnQifQ.eJCajk2u8NMpq2Qi8tUUW4yT3t8zN5efdMz95Qg2Edc9-xXp32V6POp2Zmj3M99TyUrp9YwK9TEesH_7oz5QXYFR4J5cNkvd4mJvpDudvgayvlW_3z4nLUWru8nCfSyH_PiSwbPdhpiUZGvf5-KZHMdQ0SAbp5GSMSf4CD8fIYEV8u_KyS38g9Zgsv6BoQzCZtEPtY_cLCG9YV1S7V3tLsW5-bhf8da8mEny1cdnSLI6YJanQxmpW9Aq0ooxntIo1cokeL2fFoUvzNw-4JhYLOgqVDSNg3lhNhsbiPxHI3yN04Qcn90h0s1--QFHaf8rgMWyLyKZPId4kxPR-4PZoQ", + Url("https://edugain.org/federation_five") -> respond( + content = validTrustAnchorConfigurationJwt, status = HttpStatusCode.OK, headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") ) - Url("https://edugain.org/federation_three") -> respond( - content = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiIgaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UiLCJzdWIiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZSIsImV4cCI6NDgsImlhdCI6NDgsImp3a3MiOnsia2V5cyI6W3sia2lkIjpudWxsLCJrdHkiOiJFQyIsImNydiI6IlAyNTYiLCJ4IjoiRmtWYzdmMTZPX0E4UEpVandOVEVFME10eF9FSTM4OXRPdlo1YzhtaVJwWSIsInkiOiJkX0ktTUdwWHh5SzVfR3Y1RHFwZnRJblVyLUo2X3RjQU1TMzdkMXdlY1VRIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsiZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCI6Imh0dHBzOi8vZWR1Z2Fpbi5vcmcvZmVkZXJhdGlvbl90aHJlZS9mZWRlcmF0aW9uX2ZldGNoX2VuZHBvaW50IiwiaG9tZXBhZ2VfdXJpIjoiaHR0cHM6Ly93d3cuc3VuZXQuc2UiLCJvcmdhbml6YXRpb25fbmFtZSI6IlNVTkVUIn0sIm9wZW5pZF9wcm92aWRlciI6eyJpc3N1ZXIiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZSIsImF1dGhvcml6YXRpb25fZW5kcG9pbnQiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZS9hdXRob3JpemF0aW9uIiwiZ3JhbnRfdHlwZXNfc3VwcG9ydGVkIjpbImF1dGhvcml6YXRpb25fY29kZSJdLCJpZF90b2tlbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2IiwiRVMyNTYiXSwibG9nb191cmkiOiJodHRwczovL3d3dy51bXUuc2UvaW1nL3VtdS1sb2dvLWxlZnQtbmVnLlNFLnN2ZyIsIm9wX3BvbGljeV91cmkiOiJvcF9wb2xpY3lfdXJpIiwicmVzcG9uc2VfdHlwZXNfc3VwcG9ydGVkIjpbImNvZGUiXSwic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiLCJwdWJsaWMiXSwidG9rZW5fZW5kcG9pbnQiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZS90b2tlbiIsInRva2VuX2VuZHBvaW50X2F1dGhfbWV0aG9kc19zdXBwb3J0ZWQiOlsicHJpdmF0ZV9rZXlfand0Il0sImp3a3NfdXJpIjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UvandrcyJ9fSwiY3JpdCI6bnVsbCwidHJ1c3RfbWFya3MiOm51bGwsInRydXN0X21hcmtfaXNzdWVycyI6bnVsbCwidHJ1c3RfbWFya19vd25lcnMiOm51bGx9.K_pBKXuAhkQnLMnZoaKWBHNLvrbRJi9SLWTCgRWBQK0UvkXUzN7AXbitZUNby3WpjzSweIdZKsGbvgEzGQG3IpELEpBC8pEgVn-nZGcFjkxvLfA5wd-FuAt_mNK_NU_qlNx2xRTNXCM2hRxNvbOK2Si9IPaY5Mb8kdQ2CGObUjsyA8ZKHTYT9Uiv_EWOmgKYofQvk2iEUqLMlMiLah4pNe_S1jesB9brksCbtj_rLfketXcPs3mcMun7aP73guL7-BIwAB1TzFsQjYmYZHimPCmgG6nL2zOx2xYJWP6v1xUdzbrB-4vHuay102z6sf46MkSGv_CIzKLPIK5XKbkEKA", + Url("https://edugain.org/federation/federation_fetch_endpoint") -> respond( + content = intermediateEntityConfigurationJwt, + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") + ) + + Url("https://edugain.org/federation_one/federation_fetch_endpoint") -> respond( + content = validTrustAnchorConfigurationJwt, + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") + ) + + Url("https://edugain.org/federation_two/federation_fetch_endpoint") -> respond( + content = invalidTrustAnchorConfigurationJwt, status = HttpStatusCode.OK, headers = headersOf(HttpHeaders.ContentType, "application/entity-statement+jwt") ) @@ -189,22 +364,35 @@ class TrustChainValidationTest { else -> error("Unhandled ${request.url}") } - } +} @Test fun readAuthorityHintsTest() { assertEquals( - listOfEntityConfigurationStatementList, - readAuthorityHints( - jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIgaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UiLCJzdWIiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZSIsImV4cCI6NDgsImlhdCI6NDgsImp3a3MiOnsia2V5cyI6W3sia2lkIjpudWxsLCJrdHkiOiJFQyIsImNydiI6IlAyNTYiLCJ4IjoiRmtWYzdmMTZPX0E4UEpVandOVEVFME10eF9FSTM4OXRPdlo1YzhtaVJwWSIsInkiOiJkX0ktTUdwWHh5SzVfR3Y1RHFwZnRJblVyLUo2X3RjQU1TMzdkMXdlY1VRIn1dfSwibWV0YWRhdGEiOnsiZmVkZXJhdGlvbl9lbnRpdHkiOnsiZmVkZXJhdGlvbl9mZXRjaF9lbmRwb2ludCI6Imh0dHBzOi8vZWR1Z2Fpbi5vcmcvZmVkZXJhdGlvbi9mZWRlcmF0aW9uX2ZldGNoX2VuZHBvaW50IiwiaG9tZXBhZ2VfdXJpIjoiaHR0cHM6Ly93d3cuc3VuZXQuc2UiLCJvcmdhbml6YXRpb25fbmFtZSI6IlNVTkVUIn0sIm9wZW5pZF9wcm92aWRlciI6eyJpc3N1ZXIiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZSIsImF1dGhvcml6YXRpb25fZW5kcG9pbnQiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZS9hdXRob3JpemF0aW9uIiwiZ3JhbnRfdHlwZXNfc3VwcG9ydGVkIjpbImF1dGhvcml6YXRpb25fY29kZSJdLCJpZF90b2tlbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2IiwiRVMyNTYiXSwibG9nb191cmkiOiJodHRwczovL3d3dy51bXUuc2UvaW1nL3VtdS1sb2dvLWxlZnQtbmVnLlNFLnN2ZyIsIm9wX3BvbGljeV91cmkiOiJvcF9wb2xpY3lfdXJpIiwicmVzcG9uc2VfdHlwZXNfc3VwcG9ydGVkIjpbImNvZGUiXSwic3ViamVjdF90eXBlc19zdXBwb3J0ZWQiOlsicGFpcndpc2UiLCJwdWJsaWMiXSwidG9rZW5fZW5kcG9pbnQiOiJodHRwczovL29wZW5pZC5zdW5ldC5zZS90b2tlbiIsInRva2VuX2VuZHBvaW50X2F1dGhfbWV0aG9kc19zdXBwb3J0ZWQiOlsicHJpdmF0ZV9rZXlfand0Il0sImp3a3NfdXJpIjoiaHR0cHM6Ly9vcGVuaWQuc3VuZXQuc2UvandrcyJ9fSwiY3JpdCI6bnVsbCwiYXV0aG9yaXR5X2hpbnRzIjpbImh0dHBzOi8vZWR1Z2Fpbi5vcmcvZmVkZXJhdGlvbiJdLCJ0cnVzdF9tYXJrcyI6bnVsbCwidHJ1c3RfbWFya19pc3N1ZXJzIjpudWxsLCJ0cnVzdF9tYXJrX293bmVycyI6bnVsbH0.imtQl0xm22aNQnw-ZyWPx-h_9sr_LMDP9nlJMsLZcfjABu6zki_LjJdoxeck9H4_H6_Zf1HQw5ZORj6p6LKKQ76OJkp88VqnoVt6Ko6j6CxohtGNo9KmzoW0a0c6Hi2L1eWlMZJsI2WhZ6DZhh3HngyzHX0jk7f51EpDmmnZkzICjA3XtoCBDx6T40h4ncowHfMj4lwfKOwZJAPEow5ISoqc4e3n800Hr6XEDJ9C1dMrzbr5M5bGYHxtQrOkp_kJWndLQPyvasVr9LQ-MDUWvCRfPHDZsCzGsvGkfnIQ617CXdT6dbyzqy7bJT8-sLROuZ6kT9v_ZcRnqnzNe6fd0Q", + listOfEntityConfigurationStatementList.toString(), + TrustChainValidation().readAuthorityHints( + partyBId = "https://edugain.org/federation", engine = mockEngine + ).toString() + ) + } + + @Test + fun fetchSubordinateStatementsTest() { + assertEquals( + listOfSubordinateStatementList, + TrustChainValidation().fetchSubordinateStatements( + entityConfigurationStatementsList = listOfEntityConfigurationStatementList, + engine = mockEngine ) ) } @Test fun validateTrustChainTest() { - assertTrue(validateTrustChain(listOfEntityConfigurationStatementList[0])) + assertTrue( + listOfSubordinateStatementList.all { TrustChainValidation().validateTrustChain(it) } + ) } }