From 504340d4228491bf6aaa11f79d199fd5fd735c2e Mon Sep 17 00:00:00 2001 From: Bassam Date: Tue, 16 Apr 2024 10:19:29 -0400 Subject: [PATCH] feat: VC Verification Audiance check (#969) Signed-off-by: Bassam Riman --- .../service/verification/VcVerification.scala | 50 ++++++++----------- .../verification/VcVerificationService.scala | 5 -- .../VcVerificationServiceImpl.scala | 47 +++++++++-------- .../VcVerificationControllerImpl.scala | 26 +++++----- .../controller/http/VcVerification.scala | 41 +++++++++------ .../http/VcVerificationParameter.scala | 9 ---- .../http/VcVerificationRequest.scala | 19 ++++--- 7 files changed, 100 insertions(+), 97 deletions(-) diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerification.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerification.scala index f38e79809f..f2209c4f46 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerification.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerification.scala @@ -1,37 +1,29 @@ package io.iohk.atala.pollux.core.service.verification -import io.iohk.atala.pollux.core.service.verification.VcVerificationFailureType.ERROR -import sttp.tapir.Schema -import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} +sealed trait VcVerification -enum VcVerificationFailureType { - case WARN extends VcVerificationFailureType - case ERROR extends VcVerificationFailureType -} +object VcVerification { + case object SignatureVerification extends VcVerification -enum VcVerification( - val failureType: VcVerificationFailureType -) { - case SignatureVerification extends VcVerification(ERROR) - case IssuerIdentification extends VcVerification(ERROR) - case ExpirationCheck extends VcVerification(ERROR) - case NotBeforeCheck extends VcVerification(ERROR) - case AudienceCheck extends VcVerification(ERROR) - case SubjectVerification extends VcVerification(ERROR) - case IntegrityOfClaims extends VcVerification(ERROR) - case ComplianceWithStandards extends VcVerification(ERROR) - case RevocationCheck extends VcVerification(ERROR) - case AlgorithmVerification extends VcVerification(ERROR) - case SchemaCheck extends VcVerification(ERROR) - case SemanticCheckOfClaims extends VcVerification(ERROR) -} + case object IssuerIdentification extends VcVerification -object VcVerification { - given encoder: JsonEncoder[VcVerification] = - DeriveJsonEncoder.gen[VcVerification] + case object ExpirationCheck extends VcVerification + + case object NotBeforeCheck extends VcVerification + + case class AudienceCheck(aud: String) extends VcVerification + + case object SubjectVerification extends VcVerification + + case object IntegrityOfClaims extends VcVerification + + case object ComplianceWithStandards extends VcVerification + + case object RevocationCheck extends VcVerification + + case object AlgorithmVerification extends VcVerification - given decoder: JsonDecoder[VcVerification] = - DeriveJsonDecoder.gen[VcVerification] + case object SchemaCheck extends VcVerification - given schema: Schema[VcVerification] = Schema.derivedEnumeration.defaultStringBased + case object SemanticCheckOfClaims extends VcVerification } diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerificationService.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerificationService.scala index 980e276965..915bd6e10b 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerificationService.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerificationService.scala @@ -6,14 +6,9 @@ trait VcVerificationService { def verify(request: List[VcVerificationRequest]): IO[VcVerificationServiceError, List[VcVerificationResult]] } -sealed trait VcVerificationParameter - -case class AudienceParameter(aud: String) extends VcVerificationParameter - final case class VcVerificationRequest( credential: String, verification: VcVerification, - parameter: Option[VcVerificationParameter] ) final case class VcVerificationResult( diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerificationServiceImpl.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerificationServiceImpl.scala index 30df433ba6..66666520ed 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerificationServiceImpl.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/verification/VcVerificationServiceImpl.scala @@ -3,7 +3,6 @@ package io.iohk.atala.pollux.core.service.verification import io.iohk.atala.pollux.core.model.schema.CredentialSchema import io.iohk.atala.pollux.core.service.URIDereferencer import io.iohk.atala.pollux.vc.jwt.{DidResolver, JWT, JWTVerification, JwtCredential} -import sttp.tapir.Schema import zio.{IO, *} class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDereferencer) @@ -13,7 +12,7 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe ): IO[VcVerificationServiceError, List[VcVerificationResult]] = { ZIO.collectAll( vcVerificationRequests.map(vcVerificationRequest => - verify(vcVerificationRequest.credential, vcVerificationRequest.verification, vcVerificationRequest.parameter) + verify(vcVerificationRequest.credential, vcVerificationRequest.verification) ) ) } @@ -21,22 +20,21 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe private def verify( credential: String, verification: VcVerification, - maybeParameter: Option[VcVerificationParameter] ): IO[VcVerificationServiceError, VcVerificationResult] = { - (verification, maybeParameter) match { - case (VcVerification.SchemaCheck, None) => verifySchema(credential) - case (VcVerification.SignatureVerification, None) => verifySignature(credential) - case (VcVerification.ExpirationCheck, None) => verifyExpiration(credential) - case (VcVerification.NotBeforeCheck, None) => verifyNotBefore(credential) - case (VcVerification.AlgorithmVerification, None) => verifyAlgorithm(credential) - case (VcVerification.IssuerIdentification, None) => verifyIssuerIdentification(credential) - case (VcVerification.SubjectVerification, None) => verifySubjectVerification(credential) - case (VcVerification.SemanticCheckOfClaims, None) => verifySemanticCheckOfClaims(credential) - case (VcVerification.AudienceCheck, Some(AudienceParameter(aud))) => verifyAudienceCheck(credential, aud) + verification match { + case VcVerification.SchemaCheck => verifySchema(credential) + case VcVerification.SignatureVerification => verifySignature(credential) + case VcVerification.ExpirationCheck => verifyExpiration(credential) + case VcVerification.NotBeforeCheck => verifyNotBefore(credential) + case VcVerification.AlgorithmVerification => verifyAlgorithm(credential) + case VcVerification.IssuerIdentification => verifyIssuerIdentification(credential) + case VcVerification.SubjectVerification => verifySubjectVerification(credential) + case VcVerification.SemanticCheckOfClaims => verifySemanticCheckOfClaims(credential) + case VcVerification.AudienceCheck(aud) => verifyAudienceCheck(credential, aud) case _ => ZIO.fail( VcVerificationServiceError.UnexpectedError( - s"Unsupported Verification:$verification and Parameters:$maybeParameter" + s"Unsupported Verification:$verification" ) ) } @@ -222,13 +220,22 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe credential: String, aud: String ): IO[VcVerificationServiceError, VcVerificationResult] = { - ZIO.succeed( - VcVerificationResult( - credential = credential, - verification = VcVerification.SubjectVerification, - success = true + val result = + for { + decodedJwt <- + JwtCredential + .decodeJwt(JWT(credential)) + .mapError(error => VcVerificationServiceError.UnexpectedError(s"Unable decode JWT: $error")) + } yield decodedJwt.aud.contains(aud) + + result + .map(success => + VcVerificationResult( + credential = credential, + verification = VcVerification.SubjectVerification, + success = success + ) ) - ) } } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/VcVerificationControllerImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/VcVerificationControllerImpl.scala index e83c3fc3ad..cadea75b8e 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/VcVerificationControllerImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/VcVerificationControllerImpl.scala @@ -11,18 +11,20 @@ class VcVerificationControllerImpl(vcVerificationService: VcVerificationService) requests: List[controller.http.VcVerificationRequest] )(implicit rc: RequestContext): IO[ErrorResponse, List[controller.http.VcVerificationResponse]] = { val result = - ZIO.collectAll(requests.map(request => { - val serviceRequests = controller.http.VcVerificationRequest.toService(request) - for { - results <- - vcVerificationService - .verify(serviceRequests) - .mapError(error => VcVerificationController.toHttpError(error)) - } yield controller.http.VcVerificationResponse( - request.credential, - results.map(result => controller.http.VcVerificationResult.toService(result)) - ) - })) + ZIO.collectAll( + requests.map(request => { + for { + serviceRequests <- controller.http.VcVerificationRequest.toService(request) + results <- + vcVerificationService + .verify(serviceRequests) + .mapError(error => VcVerificationController.toHttpError(error)) + } yield controller.http.VcVerificationResponse( + request.credential, + results.map(result => controller.http.VcVerificationResult.toService(result)) + ) + }) + ) ZIO.succeed(List.empty) } } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerification.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerification.scala index 0458e03583..07b784c8eb 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerification.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerification.scala @@ -1,9 +1,11 @@ package io.iohk.atala.verification.controller.http +import io.iohk.atala.api.http.ErrorResponse import io.iohk.atala.pollux.core.service import io.iohk.atala.pollux.core.service.verification.VcVerification as ServiceVcVerification import sttp.tapir.Schema import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} +import zio.{IO, *} enum VcVerification { case SignatureVerification @@ -29,20 +31,29 @@ object VcVerification { given schema: Schema[VcVerification] = Schema.derivedEnumeration.defaultStringBased - def convert(verification: VcVerification): ServiceVcVerification = { - verification match { - case SignatureVerification => ServiceVcVerification.SignatureVerification - case IssuerIdentification => ServiceVcVerification.IssuerIdentification - case ExpirationCheck => ServiceVcVerification.ExpirationCheck - case NotBeforeCheck => ServiceVcVerification.NotBeforeCheck - case AudienceCheck => ServiceVcVerification.AudienceCheck - case SubjectVerification => ServiceVcVerification.SubjectVerification - case IntegrityOfClaims => ServiceVcVerification.IntegrityOfClaims - case ComplianceWithStandards => ServiceVcVerification.ComplianceWithStandards - case RevocationCheck => ServiceVcVerification.RevocationCheck - case AlgorithmVerification => ServiceVcVerification.AlgorithmVerification - case SchemaCheck => ServiceVcVerification.SchemaCheck - case SemanticCheckOfClaims => ServiceVcVerification.SemanticCheckOfClaims + def convert( + verification: VcVerification, + maybeParameter: Option[VcVerificationParameter] + ): IO[ErrorResponse, ServiceVcVerification] = { + (verification, maybeParameter) match { + case (SignatureVerification, None) => ZIO.succeed(ServiceVcVerification.SignatureVerification) + case (IssuerIdentification, None) => ZIO.succeed(ServiceVcVerification.IssuerIdentification) + case (ExpirationCheck, None) => ZIO.succeed(ServiceVcVerification.ExpirationCheck) + case (NotBeforeCheck, None) => ZIO.succeed(ServiceVcVerification.NotBeforeCheck) + case (AudienceCheck, Some(AudienceParameter(aud))) => ZIO.succeed(ServiceVcVerification.AudienceCheck(aud)) + case (SubjectVerification, None) => ZIO.succeed(ServiceVcVerification.SubjectVerification) + case (IntegrityOfClaims, None) => ZIO.succeed(ServiceVcVerification.IntegrityOfClaims) + case (ComplianceWithStandards, None) => ZIO.succeed(ServiceVcVerification.ComplianceWithStandards) + case (RevocationCheck, None) => ZIO.succeed(ServiceVcVerification.RevocationCheck) + case (AlgorithmVerification, None) => ZIO.succeed(ServiceVcVerification.AlgorithmVerification) + case (SchemaCheck, None) => ZIO.succeed(ServiceVcVerification.SchemaCheck) + case (SemanticCheckOfClaims, None) => ZIO.succeed(ServiceVcVerification.SemanticCheckOfClaims) + case _ => + ZIO.fail( + ErrorResponse.badRequest(detail = + Some(s"Unsupported Verification:$verification and Parameters:$maybeParameter") + ) + ) } } @@ -52,7 +63,7 @@ object VcVerification { case ServiceVcVerification.IssuerIdentification => IssuerIdentification case ServiceVcVerification.ExpirationCheck => ExpirationCheck case ServiceVcVerification.NotBeforeCheck => NotBeforeCheck - case ServiceVcVerification.AudienceCheck => AudienceCheck + case ServiceVcVerification.AudienceCheck(_) => AudienceCheck case ServiceVcVerification.SubjectVerification => SubjectVerification case ServiceVcVerification.IntegrityOfClaims => IntegrityOfClaims case ServiceVcVerification.ComplianceWithStandards => ComplianceWithStandards diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerificationParameter.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerificationParameter.scala index 43e7c93f6f..6004a679da 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerificationParameter.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerificationParameter.scala @@ -1,9 +1,5 @@ package io.iohk.atala.verification.controller.http -import io.iohk.atala.pollux.core.service.verification.{ - AudienceParameter as ServiceAudienceParameter, - VcVerificationParameter as ServiceVcVerificationParameter -} import sttp.tapir.Schema import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} @@ -17,11 +13,6 @@ object VcVerificationParameter { DeriveJsonDecoder.gen[VcVerificationParameter] given schema: Schema[VcVerificationParameter] = Schema.derived - - def convert(parameter: VcVerificationParameter): ServiceVcVerificationParameter = { - parameter match - case AudienceParameter(aud) => ServiceAudienceParameter(aud) - } } case class AudienceParameter(aud: String) extends VcVerificationParameter diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerificationRequest.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerificationRequest.scala index af1e04eb13..dd7602b3d0 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerificationRequest.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/verification/controller/http/VcVerificationRequest.scala @@ -1,10 +1,11 @@ package io.iohk.atala.verification.controller.http -import io.iohk.atala.api.http.Annotation +import io.iohk.atala.api.http.{Annotation, ErrorResponse} import io.iohk.atala.pollux.core.service.verification.VcVerificationRequest as ServiceVcVerificationRequest import sttp.tapir.Schema import sttp.tapir.Schema.annotations.{description, encodedExample} import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} +import zio.{IO, *} final case class VcVerificationRequest( @description(VcVerificationRequest.annotations.credential.description) @@ -53,12 +54,16 @@ object VcVerificationRequest { given credentialVerificationRequestSchema: Schema[VcVerificationRequest] = Schema.derived - def toService(request: VcVerificationRequest): List[ServiceVcVerificationRequest] = { - request.verifications.map(verification => - ServiceVcVerificationRequest( - credential = request.credential, - verification = VcVerification.convert(verification.verification), - parameter = verification.parameter.map(param => VcVerificationParameter.convert(param)) + def toService(request: VcVerificationRequest): IO[ErrorResponse, List[ServiceVcVerificationRequest]] = { + ZIO.collectAll( + request.verifications.map(verification => + for { + serviceVerification <- VcVerification.convert( + verification.verification, + verification.parameter + ) + + } yield ServiceVcVerificationRequest(credential = request.credential, verification = serviceVerification) ) ) }