diff --git a/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/VerifierContext.kt b/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/VerifierContext.kt index 7cfae6db..bb0b438d 100644 --- a/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/VerifierContext.kt +++ b/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/VerifierContext.kt @@ -123,9 +123,14 @@ internal fun beans(clock: Clock) = beans { } bean { GenerateResponseCode.Random } - bean { PostWalletResponseLive(ref(), ref(), ref(), clock, ref(), ref(), ref(), ref(), createZKPVerifier( - getIssuerEcKey(env).toECPublicKey()), - ) } + bean { + PostWalletResponseLive( + ref(), ref(), ref(), clock, ref(), ref(), ref(), ref(), + createZKPVerifier( + getIssuerEcKey(env).toECPublicKey(), + ), + ) + } bean { GenerateEphemeralEncryptionKeyPairNimbus } bean { GetWalletResponseLive(ref()) } bean { GetJarmJwksLive(ref()) } @@ -290,8 +295,8 @@ private fun jarSigningConfig(environment: Environment, clock: Clock): SigningCon fun getIssuerEcKey(environment: Environment): ECKey { val issuerCert = environment.getRequiredProperty("verifier.issuer.cert") val pemKey = "-----BEGIN CERTIFICATE-----\n" + - "${issuerCert}\n" + - "-----END CERTIFICATE-----" + "${issuerCert}\n" + + "-----END CERTIFICATE-----" val certificateFactory: CertificateFactory = CertificateFactory.getInstance("X.509") val certificate = diff --git a/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletApi.kt b/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletApi.kt index 2decf34b..f61e1381 100644 --- a/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletApi.kt +++ b/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletApi.kt @@ -17,7 +17,6 @@ package eu.europa.ec.eudi.verifier.endpoint.adapter.input.web import arrow.core.None import arrow.core.Some -import arrow.core.getOrElse import arrow.core.raise.either import com.nimbusds.jose.jwk.JWK import com.nimbusds.jose.jwk.JWKSet @@ -28,7 +27,6 @@ import eu.europa.ec.eudi.verifier.endpoint.domain.RequestId import eu.europa.ec.eudi.verifier.endpoint.port.input.* import eu.europa.ec.eudi.verifier.endpoint.port.input.QueryResponse.* import kotlinx.serialization.SerializationException -import kotlinx.serialization.json.JsonObject import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.http.MediaType @@ -133,130 +131,130 @@ class WalletApi( } } -private suspend fun handleGetPublicJwkSet(): ServerResponse { - logger.info("Handling GetPublicJwkSet ...") - val publicJwkSet = JWKSet(signingKey).toJSONObject(true) - return ok().contentType(MediaType.parseMediaType(JWKSet.MIME_TYPE)).bodyValueAndAwait(publicJwkSet) -} - -/** - * Handles the GET request for fetching the JWKS to be used for JARM. - */ -private suspend fun handleGetJarmJwks(request: ServerRequest): ServerResponse { - val requestId = request.requestId().also { logger.info("Handling GetJarmJwks for $it...") } - return when (val queryResponse = getJarmJwks(requestId)) { - is NotFound -> notFound().buildAndAwait() - is InvalidState -> badRequest().buildAndAwait() - is Found -> ok().contentType(MediaType.parseMediaType(JWKSet.MIME_TYPE)) - .bodyValueAndAwait(queryResponse.value.toJSONObject(true)) + private suspend fun handleGetPublicJwkSet(): ServerResponse { + logger.info("Handling GetPublicJwkSet ...") + val publicJwkSet = JWKSet(signingKey).toJSONObject(true) + return ok().contentType(MediaType.parseMediaType(JWKSet.MIME_TYPE)).bodyValueAndAwait(publicJwkSet) } -} /** - * Handles the POST request for fetching the ephemeral keys used for the ZKP. - */ - -private suspend fun handlePostZkpJwk(request: ServerRequest): ServerResponse = try { - logger.info("Handling PostZkpJwk ...") - val requestId = request.requestId() - logger.info("RequestID PostZkpJwk for $requestId ") - val outcome = either { postZkpJwkRequest(request, requestId) } - outcome.fold( - ifRight = { jwkSet: List -> - logger.info("PostZkpJwk processed") - ok().json().bodyValueAndAwait(jwkSet) - }, - ifLeft = { error: ZkpJwkError -> - logger.error("$error while handling post of ZkpJwk") - badRequest().buildAndAwait() - }, - ) -} catch (t: SerializationException) { - logger.error("While handling post of ZkpJwk, failed to decode JSON", t) - badRequest().buildAndAwait() -} - -companion object { - const val GET_PUBLIC_JWK_SET_PATH = "/wallet/public-keys.json" - - /** - * Path template for the route for - * getting the presentation's request object - */ - const val REQUEST_JWT_PATH = "/wallet/request.jwt/{requestId}" - - /** - * Path template for the route for - * getting the presentation definition - */ - const val PRESENTATION_DEFINITION_PATH = "/wallet/pd/{requestId}" - - /** - * Path template for the route for - * getting the JWKS containing parameters for the - * zero-knowledge proof - */ - const val ZKP_JWK_SET_PATH = "/wallet/zkp/{requestId}/jwks.json" - - /** - * Path template for the route for getting the JWKS that contains the Ephemeral Key for JARM. + * Handles the GET request for fetching the JWKS to be used for JARM. */ - const val JARM_JWK_SET_PATH = "/wallet/jarm/{requestId}/jwks.json" + private suspend fun handleGetJarmJwks(request: ServerRequest): ServerResponse { + val requestId = request.requestId().also { logger.info("Handling GetJarmJwks for $it...") } + return when (val queryResponse = getJarmJwks(requestId)) { + is NotFound -> notFound().buildAndAwait() + is InvalidState -> badRequest().buildAndAwait() + is Found -> ok().contentType(MediaType.parseMediaType(JWKSet.MIME_TYPE)) + .bodyValueAndAwait(queryResponse.value.toJSONObject(true)) + } + } - /** - * Path template for the route for - * posting the Authorisation Response +/** + * Handles the POST request for fetching the ephemeral keys used for the ZKP. */ - const val WALLET_RESPONSE_PATH = "/wallet/direct_post" - /** - * Extracts from the request the [RequestId] - */ - private fun ServerRequest.requestId() = RequestId(pathVariable("requestId")) - - private fun MultiValueMap.walletResponse(): AuthorisationResponse { - fun directPost() = AuthorisationResponseTO( - state = getFirst("state"), - idToken = getFirst("id_token"), - vpToken = getFirst("vp_token"), - presentationSubmission = getFirst("presentation_submission")?.let { - PresentationExchange.jsonParser.decodePresentationSubmission(it).getOrThrow() + private suspend fun handlePostZkpJwk(request: ServerRequest): ServerResponse = try { + logger.info("Handling PostZkpJwk ...") + val requestId = request.requestId() + logger.info("RequestID PostZkpJwk for $requestId ") + val outcome = either { postZkpJwkRequest(request, requestId) } + outcome.fold( + ifRight = { jwkSet: List -> + logger.info("PostZkpJwk processed") + ok().json().bodyValueAndAwait(jwkSet) + }, + ifLeft = { error: ZkpJwkError -> + logger.error("$error while handling post of ZkpJwk") + badRequest().buildAndAwait() }, - error = getFirst("error"), - errorDescription = getFirst("error_description"), - ).run { AuthorisationResponse.DirectPost(this) } + ) + } catch (t: SerializationException) { + logger.error("While handling post of ZkpJwk, failed to decode JSON", t) + badRequest().buildAndAwait() + } - fun directPostJwt() = getFirst("response")?.let { jwt -> - AuthorisationResponse.DirectPostJwt(getFirst("state"), jwt) - } + companion object { + const val GET_PUBLIC_JWK_SET_PATH = "/wallet/public-keys.json" + + /** + * Path template for the route for + * getting the presentation's request object + */ + const val REQUEST_JWT_PATH = "/wallet/request.jwt/{requestId}" + + /** + * Path template for the route for + * getting the presentation definition + */ + const val PRESENTATION_DEFINITION_PATH = "/wallet/pd/{requestId}" + + /** + * Path template for the route for + * getting the JWKS containing parameters for the + * zero-knowledge proof + */ + const val ZKP_JWK_SET_PATH = "/wallet/zkp/{requestId}/jwks.json" + + /** + * Path template for the route for getting the JWKS that contains the Ephemeral Key for JARM. + */ + const val JARM_JWK_SET_PATH = "/wallet/jarm/{requestId}/jwks.json" + + /** + * Path template for the route for + * posting the Authorisation Response + */ + const val WALLET_RESPONSE_PATH = "/wallet/direct_post" + + /** + * Extracts from the request the [RequestId] + */ + private fun ServerRequest.requestId() = RequestId(pathVariable("requestId")) + + private fun MultiValueMap.walletResponse(): AuthorisationResponse { + fun directPost() = AuthorisationResponseTO( + state = getFirst("state"), + idToken = getFirst("id_token"), + vpToken = getFirst("vp_token"), + presentationSubmission = getFirst("presentation_submission")?.let { + PresentationExchange.jsonParser.decodePresentationSubmission(it).getOrThrow() + }, + error = getFirst("error"), + errorDescription = getFirst("error_description"), + ).run { AuthorisationResponse.DirectPost(this) } + + fun directPostJwt() = getFirst("response")?.let { jwt -> + AuthorisationResponse.DirectPostJwt(getFirst("state"), jwt) + } - return directPostJwt() ?: directPost() - } + return directPostJwt() ?: directPost() + } - fun requestZkpKey(baseUrl: String): EmbedOption.ByReference = - urlBuilder(baseUrl = baseUrl, pathTemplate = ZKP_JWK_SET_PATH) + fun requestZkpKey(baseUrl: String): EmbedOption.ByReference = + urlBuilder(baseUrl = baseUrl, pathTemplate = ZKP_JWK_SET_PATH) - fun requestJwtByReference(baseUrl: String): EmbedOption.ByReference = - urlBuilder(baseUrl = baseUrl, pathTemplate = REQUEST_JWT_PATH) + fun requestJwtByReference(baseUrl: String): EmbedOption.ByReference = + urlBuilder(baseUrl = baseUrl, pathTemplate = REQUEST_JWT_PATH) - fun presentationDefinitionByReference(baseUrl: String): EmbedOption.ByReference = - urlBuilder(baseUrl = baseUrl, pathTemplate = PRESENTATION_DEFINITION_PATH) + fun presentationDefinitionByReference(baseUrl: String): EmbedOption.ByReference = + urlBuilder(baseUrl = baseUrl, pathTemplate = PRESENTATION_DEFINITION_PATH) - fun publicJwkSet(baseUrl: String): EmbedOption.ByReference = EmbedOption.ByReference { _ -> - DefaultUriBuilderFactory(baseUrl).uriString(GET_PUBLIC_JWK_SET_PATH).build().toURL() - } + fun publicJwkSet(baseUrl: String): EmbedOption.ByReference = EmbedOption.ByReference { _ -> + DefaultUriBuilderFactory(baseUrl).uriString(GET_PUBLIC_JWK_SET_PATH).build().toURL() + } - fun jarmJwksByReference(baseUrl: String): EmbedOption.ByReference = - urlBuilder(baseUrl, JARM_JWK_SET_PATH) + fun jarmJwksByReference(baseUrl: String): EmbedOption.ByReference = + urlBuilder(baseUrl, JARM_JWK_SET_PATH) - fun directPost(baseUrl: String): URL = - DefaultUriBuilderFactory(baseUrl).uriString(WALLET_RESPONSE_PATH).build().toURL() + fun directPost(baseUrl: String): URL = + DefaultUriBuilderFactory(baseUrl).uriString(WALLET_RESPONSE_PATH).build().toURL() - private fun urlBuilder( - baseUrl: String, - pathTemplate: String, - ) = EmbedOption.byReference { requestId -> - DefaultUriBuilderFactory(baseUrl).uriString(pathTemplate).build(requestId.value).toURL() + private fun urlBuilder( + baseUrl: String, + pathTemplate: String, + ) = EmbedOption.byReference { requestId -> + DefaultUriBuilderFactory(baseUrl).uriString(pathTemplate).build(requestId.value).toURL() + } } } -} diff --git a/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/port/input/PostWalletResponse.kt b/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/port/input/PostWalletResponse.kt index 6b25408d..a737c52f 100644 --- a/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/port/input/PostWalletResponse.kt +++ b/src/main/kotlin/eu/europa/ec/eudi/verifier/endpoint/port/input/PostWalletResponse.kt @@ -68,7 +68,7 @@ sealed interface AuthorisationResponse { data class DirectPostJwt(val state: String?, val jarm: Jwt) : AuthorisationResponse } -open class WalletResponseValidationError: Exception() { +open class WalletResponseValidationError : Exception() { class InvalidMdoc : WalletResponseValidationError() class InvalidFormat : WalletResponseValidationError() class InvalidVPToken : WalletResponseValidationError() @@ -89,7 +89,6 @@ open class WalletResponseValidationError: Exception() { class MissingVpTokenOrPresentationSubmission : WalletResponseValidationError() } - internal fun AuthorisationResponseTO.toDomain(presentation: RequestObjectRetrieved): WalletResponse { fun requiredIdToken(): WalletResponse.IdToken { if (idToken == null) { throw WalletResponseValidationError.MissingIdToken() } @@ -97,7 +96,7 @@ internal fun AuthorisationResponseTO.toDomain(presentation: RequestObjectRetriev } fun requiredVpToken(): WalletResponse.VpToken { - if (vpToken == null){ throw WalletResponseValidationError.MissingVpTokenOrPresentationSubmission() } + if (vpToken == null) { throw WalletResponseValidationError.MissingVpTokenOrPresentationSubmission() } if (presentationSubmission == null) { throw WalletResponseValidationError.MissingVpTokenOrPresentationSubmission() } return WalletResponse.VpToken(vpToken, presentationSubmission) } @@ -149,7 +148,7 @@ class PostWalletResponseLive( private val generateResponseCode: GenerateResponseCode, private val createQueryWalletResponseRedirectUri: CreateQueryWalletResponseRedirectUri, private val getIssuerEcKey: ECKey, - private val zkpVerifier: ZKPVerifier + private val zkpVerifier: ZKPVerifier, ) : PostWalletResponse { private val logger: Logger = LoggerFactory.getLogger(PostWalletResponseLive::class.java) @@ -175,68 +174,68 @@ class PostWalletResponseLive( throw WalletResponseValidationError.MissingVpTokenOrPresentationSubmission() } if (responseObject.vpToken != null) { - //map through the response and call the proper verification methods for every descriptor + // map through the response and call the proper verification methods for every descriptor responseObject.presentationSubmission.descriptorMaps.map { descriptor -> - val path = descriptor.path.value - val token = extractPresentation(responseObject.vpToken, path) - if (token == null) { - logger.error("Missing VPToken") - throw WalletResponseValidationError.MissingVpTokenOrPresentationSubmission() - } - - when (descriptor.format) { - "vc+sd-jwt" -> { - checkSdJwtSignature(token) - logger.info("Successfully verified the sdjwt") - } - - "mso_mdoc" -> { - checkMdocSignature(token) - logger.info("Successfully verified the mdoc") + val path = descriptor.path.value + val token = extractPresentation(responseObject.vpToken, path) + if (token == null) { + logger.error("Missing VPToken") + throw WalletResponseValidationError.MissingVpTokenOrPresentationSubmission() } - "vc+sd-jwt+zkp" -> { - logger.info("Starting zkp verification for SDJWT") - val descriptorId: String = descriptor.id.value - - val key = presentation.zkpKeys?.get(descriptorId) ?: throw WalletResponseValidationError.InvalidVPToken() + when (descriptor.format) { + "vc+sd-jwt" -> { + checkSdJwtSignature(token) + logger.info("Successfully verified the sdjwt") + } - val sdjwtToken = token.split("~").first() - if (!zkpVerifier.verifyChallenge(VpTokenFormat.SDJWT, sdjwtToken, key)) { - throw WalletResponseValidationError.InvalidVPToken() + "mso_mdoc" -> { + checkMdocSignature(token) + logger.info("Successfully verified the mdoc") } - logger.info("Proofed SD-JWT with ZK") - } - "mso_mdoc+zkp" -> { - logger.info("Starting zkp verification for mDoc") - val descriptorId: String = descriptor.id.value - val key = presentation.zkpKeys?.get(descriptorId) ?: throw WalletResponseValidationError.InvalidVPToken() + "vc+sd-jwt+zkp" -> { + logger.info("Starting zkp verification for SDJWT") + val descriptorId: String = descriptor.id.value - val data = DataElement.fromCBOR(Base64.getUrlDecoder().decode(token)) - val documents = - data.value[MapKey("documents")] as? ListElement ?: throw WalletResponseValidationError.InvalidMdoc() + val key = presentation.zkpKeys?.get(descriptorId) ?: throw WalletResponseValidationError.InvalidVPToken() - documents.value.forEach { - val doc = it as? MapElement ?: throw WalletResponseValidationError.InvalidMdoc() - val encodedDoc = Base64.getUrlEncoder().encodeToString(doc.toCBOR()) - if (!zkpVerifier.verifyChallenge(VpTokenFormat.MSOMDOC, encodedDoc, key)) { - logger.error("MDoc verification failed for document") + val sdjwtToken = token.split("~").first() + if (!zkpVerifier.verifyChallenge(VpTokenFormat.SDJWT, sdjwtToken, key)) { throw WalletResponseValidationError.InvalidVPToken() } + logger.info("Proofed SD-JWT with ZK") } - logger.info("Proofed MDOC with ZK") - } + "mso_mdoc+zkp" -> { + logger.info("Starting zkp verification for mDoc") + val descriptorId: String = descriptor.id.value + val key = presentation.zkpKeys?.get(descriptorId) ?: throw WalletResponseValidationError.InvalidVPToken() + + val data = DataElement.fromCBOR(Base64.getUrlDecoder().decode(token)) + val documents = + data.value[MapKey("documents")] as? ListElement ?: throw WalletResponseValidationError.InvalidMdoc() + + documents.value.forEach { + val doc = it as? MapElement ?: throw WalletResponseValidationError.InvalidMdoc() + val encodedDoc = Base64.getUrlEncoder().encodeToString(doc.toCBOR()) + if (!zkpVerifier.verifyChallenge(VpTokenFormat.MSOMDOC, encodedDoc, key)) { + logger.error("MDoc verification failed for document") + throw WalletResponseValidationError.InvalidVPToken() + } + } + + logger.info("Proofed MDOC with ZK") + } - else -> { - logger.error("Unknown format in descriptor path: ${descriptor.path}") - throw WalletResponseValidationError.InvalidFormat() + else -> { + logger.error("Unknown format in descriptor path: ${descriptor.path}") + throw WalletResponseValidationError.InvalidFormat() + } } } } - } // for this use case (let frontend display the submitted data) we store the wallet response // Put wallet response into presentation object and store into db val submitted = submit(presentation, responseObject).also { storePresentation(it) } @@ -285,7 +284,7 @@ class PostWalletResponseLive( ).getOrThrow() } catch (e: SdJwtVerificationException) { logger.error("SD-JWT Verification failed: ${e.reason}", e) - throw WalletResponseValidationError.InvalidSDJwt() + throw WalletResponseValidationError.InvalidSDJwt() } catch (e: Exception) { logger.error("Unexpected error during SD-JWT Verification: ${e.message}", e) throw WalletResponseValidationError.InvalidSDJwt() @@ -338,7 +337,7 @@ class PostWalletResponseLive( } } - suspend fun submit( + suspend fun submit( presentation: RequestObjectRetrieved, responseObject: AuthorisationResponseTO, ): Presentation.Submitted { diff --git a/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/TestContext.kt b/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/TestContext.kt index 42aa2cbd..d643738b 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/TestContext.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/TestContext.kt @@ -117,6 +117,7 @@ object TestContext { /** * Meta annotation to be used with integration tests of [PidIssuerApplication]. */ +@Suppress("ktlint:standard:max-line-length") @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) @SpringBootTest( diff --git a/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletApiClient.kt b/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletApiClient.kt index ca56a48a..81089a09 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletApiClient.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletApiClient.kt @@ -18,7 +18,6 @@ package eu.europa.ec.eudi.verifier.endpoint.adapter.input.web import eu.europa.ec.eudi.verifier.endpoint.domain.RequestId import eu.europa.ec.eudi.verifier.endpoint.port.input.ChallengeRequest import eu.europa.ec.eudi.verifier.endpoint.port.input.EphemeralKeyResponse -import eu.europa.ec.eudi.verifier.endpoint.port.input.JwtSecuredAuthorizationRequestTO import kotlinx.serialization.json.JsonObject import org.json.JSONObject import org.junit.jupiter.api.Assertions.assertNotNull @@ -31,8 +30,6 @@ import org.springframework.test.web.reactive.server.expectBody import org.springframework.test.web.reactive.server.returnResult import org.springframework.util.MultiValueMap import org.springframework.web.reactive.function.BodyInserters -import org.springframework.web.reactive.function.server.ServerRequest -import reactor.core.publisher.Flux import software.tice.ChallengeRequestData object WalletApiClient { @@ -172,18 +169,18 @@ object WalletApiClient { fun fetchZkpKeys( client: WebTestClient, challengeRequestData: ChallengeRequestData, - requestId: RequestId + requestId: RequestId, ): List { val requestPayload = arrayOf( ChallengeRequest( id = "eu.europa.ec.eudiw.pid.1", digest = challengeRequestData.digest, r = challengeRequestData.r, - proofType = "secp256r1-sha256" - ) + proofType = "secp256r1-sha256", + ), ) - return client.post().uri(WalletApi.ZKP_JWK_SET_PATH, requestId.value) + return client.post().uri(WalletApi.ZKP_JWK_SET_PATH, requestId.value) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .bodyValue(requestPayload) diff --git a/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletResponseDirectPostWithIdTokenAndVpTokenTest.kt b/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletResponseDirectPostWithIdTokenAndVpTokenTest.kt index 3a8bfb64..4b8df8f7 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletResponseDirectPostWithIdTokenAndVpTokenTest.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/WalletResponseDirectPostWithIdTokenAndVpTokenTest.kt @@ -105,7 +105,6 @@ internal class WalletResponseDirectPostWithIdTokenAndVpTokenTest { */ @Test @Order(value = 3) - fun `get wallet response for format vc+sd-jwt - confirm returns 200`() = runTest { // given val initTransaction = VerifierApiClient.loadInitTransactionTO("02-presentationDefinitionWithRedirect.json") @@ -132,12 +131,10 @@ internal class WalletResponseDirectPostWithIdTokenAndVpTokenTest { // then assertNotNull(response) - } @Test @Order(value = 4) - fun `get wallet response for format mso_mdoc - confirm returns 200`() = runTest { // given val initTransaction = VerifierApiClient.loadInitTransactionTO("02-presentationDefinitionWithRedirect.json") @@ -163,12 +160,10 @@ internal class WalletResponseDirectPostWithIdTokenAndVpTokenTest { // then assertNotNull(response) - } @Test @Order(value = 5) - fun `fetch ephemeral key response for zkp flow - returns list of ephemeral keys`() = runTest { // given val initTransaction = VerifierApiClient.loadInitTransactionTO("02-presentationDefinitionWithRedirect.json") @@ -208,7 +203,6 @@ internal class WalletResponseDirectPostWithIdTokenAndVpTokenTest { assertNotNull(ephemeralKeys) } - /** * Verifies that a Transaction expecting a direct_post Wallet response, doesn't accept a direct_post.jwt Wallet response. */ diff --git a/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/ZkpTests.kt b/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/ZkpTests.kt index 5017f327..9326fcb6 100644 --- a/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/ZkpTests.kt +++ b/src/test/kotlin/eu/europa/ec/eudi/verifier/endpoint/adapter/input/web/ZkpTests.kt @@ -1,7 +1,21 @@ +/* + * Copyright (c) 2023 European Commission + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package eu.europa.ec.eudi.verifier.endpoint.adapter.input.web import arrow.core.Some -import com.nimbusds.jose.crypto.ECDSAVerifier import com.nimbusds.jose.jwk.ECKey import eu.europa.ec.eudi.prex.* import eu.europa.ec.eudi.sdjwt.* @@ -18,8 +32,8 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.fail import org.mockito.Mock import org.mockito.Mockito.* -import org.mockito.kotlin.eq import org.mockito.MockitoAnnotations +import org.mockito.kotlin.eq import org.mockito.kotlin.whenever import software.tice.VpTokenFormat import software.tice.ZKPVerifier @@ -34,7 +48,6 @@ import java.time.ZoneId import java.util.concurrent.ConcurrentHashMap import kotlin.test.assertEquals - class ZkpTests { @Mock private lateinit var loadPresentationByRequestId: LoadPresentationByRequestId @@ -71,14 +84,14 @@ class ZkpTests { val fixedResponseCode = ResponseCode("test") val generateResponseCode: GenerateResponseCode = GenerateResponseCode.fixed(fixedResponseCode) - // Override CreateQueryWalletResponseRedirectUri for the test val createQueryWalletResponseRedirectUri = object : CreateQueryWalletResponseRedirectUri { override fun redirectUri(template: String, responseCode: ResponseCode): Result = runCatching { URI( template.replace( - CreateQueryWalletResponseRedirectUri.RESPONSE_CODE_PLACE_HOLDER, responseCode.value - ) + CreateQueryWalletResponseRedirectUri.RESPONSE_CODE_PLACE_HOLDER, + responseCode.value, + ), ).toURL() } @@ -95,7 +108,7 @@ class ZkpTests { generateResponseCode, createQueryWalletResponseRedirectUri, getIssuerEcKey, - zkpVerifier + zkpVerifier, ) // Generate KeyPair for zkp @@ -104,7 +117,7 @@ class ZkpTests { val keyPair: KeyPair = keyPairGenerator.generateKeyPair() privateKey = keyPair.private as ECPrivateKey val hashMapkeys: ConcurrentHashMap = ConcurrentHashMap() - hashMapkeys["1"] = privateKey as ECPrivateKey + hashMapkeys["1"] = privateKey zkpKeys = ConcurrentHashMap().apply { put("id", privateKey) } @@ -113,11 +126,14 @@ class ZkpTests { val transactionId = TransactionId("transactionId") val instant = Instant.now() val presentationType: PresentationType = PresentationType.IdAndVpToken( - idTokenType = listOf(IdTokenType.SubjectSigned), presentationDefinition = PresentationDefinition( - name = null, id = Id("id"), inputDescriptors = listOf( - InputDescriptor(constraints = Constraints.LimitDisclosure.PREFERRED, id = InputDescriptorId("id")) - ) - ) + idTokenType = listOf(IdTokenType.SubjectSigned), + presentationDefinition = PresentationDefinition( + name = null, + id = Id("id"), + inputDescriptors = listOf( + InputDescriptor(constraints = Constraints.LimitDisclosure.PREFERRED, id = InputDescriptorId("id")), + ), + ), ) val redirectUriTemplate = "http://localhost:0/wallet-redirect#response_code=${CreateQueryWalletResponseRedirectUri.RESPONSE_CODE_PLACE_HOLDER}" @@ -135,7 +151,7 @@ class ZkpTests { ephemeralEcPrivateKey = null, responseMode = responseMode, getWalletResponseMethod = GetWalletResponseMethod.Redirect(redirectUriTemplate), - zkpKeys = zkpKeys + zkpKeys = zkpKeys, ) } @@ -150,7 +166,7 @@ class ZkpTests { state = "state", vpToken = "vpToken", presentationSubmission = presentationSubmission, - ) + ), ) whenever(loadPresentationByRequestId.invoke(RequestId("state"))).thenReturn(presentation) @@ -168,7 +184,7 @@ class ZkpTests { assertEquals( "http://localhost:0/wallet-redirect#response_code=test", acceptedTO.redirectUri, - "Redirect URI does not match expected value" + "Redirect URI does not match expected value", ) }) } @@ -187,7 +203,7 @@ class ZkpTests { state = "state", vpToken = vpToken, presentationSubmission = presentationSubmission, - ) + ), ) whenever(loadPresentationByRequestId.invoke(RequestId("state"))).thenReturn(presentation) @@ -206,8 +222,8 @@ class ZkpTests { assertEquals( "http://localhost:0/wallet-redirect#response_code=test", acceptedTO.redirectUri, - "Redirect URI does not match expected value" + "Redirect URI does not match expected value", ) }) } -} \ No newline at end of file +}