Skip to content

Commit

Permalink
ATL-6913: support parameter
Browse files Browse the repository at this point in the history
Signed-off-by: Bassam Riman <bassam.riman@iohk.io>
  • Loading branch information
CryptoKnightIOG committed Apr 13, 2024
1 parent 759cbe8 commit 913fc5e
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ 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,
verifications: List[VcVerification]
verification: VcVerification,
parameter: Option[VcVerificationParameter]
)

final case class VcVerificationResult(
credential: String,
checks: List[VcVerification],
successfulChecks: List[VcVerification],
failedChecks: List[VcVerification],
failedAsWarningChecks: List[VcVerification]
verification: VcVerification,
success: Boolean
)

final case class VcVerificationOutcome(verification: VcVerification, success: Boolean)
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,46 @@ 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)
extends VcVerificationService {
override def verify(
vcVerificationRequests: List[VcVerificationRequest]
): IO[VcVerificationServiceError, List[VcVerificationResult]] = {
vcVerificationRequests.map(vcVerificationRequest =>
val verificationOutcomesZIO = ZIO.collectAll(
vcVerificationRequest.verifications
.map(verification => verify(vcVerificationRequest.credential, verification))
ZIO.collectAll(
vcVerificationRequests.map(vcVerificationRequest =>
verify(vcVerificationRequest.credential, vcVerificationRequest.verification, vcVerificationRequest.parameter)
)

verificationOutcomesZIO.map(verificationOutcomes => {
val successfulChecks = verificationOutcomes.filter(_.success).map(_.verification)

val failedVerifications = verificationOutcomes.filterNot(_.success).map(_.verification)

val failedAsErrorChecks =
failedVerifications.filter(verification => verification.failureType == VcVerificationFailureType.ERROR)

val failedAsWarningChecks =
failedVerifications.filter(verification => verification.failureType == VcVerificationFailureType.WARN)

VcVerificationResult(
credential = vcVerificationRequest.credential,
checks = vcVerificationRequest.verifications,
successfulChecks = successfulChecks,
failedChecks = failedAsErrorChecks,
failedAsWarningChecks = failedAsWarningChecks
)
})
)
ZIO.succeed(List.empty)
}

private def verify(
credential: String,
verification: VcVerification
): IO[VcVerificationServiceError, VcVerificationOutcome] = {
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 _ => ZIO.fail(VcVerificationServiceError.UnexpectedError(s"Unsupported Verification $verification"))
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)
case _ =>
ZIO.fail(
VcVerificationServiceError.UnexpectedError(
s"Unsupported Verification:$verification and Parameters:$maybeParameter"
)
)
}
}

private def verifySchema(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
private def verifySchema(credential: String): IO[VcVerificationServiceError, VcVerificationResult] = {
val result =
for {
decodedJwt <-
Expand All @@ -77,22 +63,24 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe

result
.as(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.SchemaCheck,
success = true
)
)
.catchAll(_ =>
ZIO.succeed(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.SchemaCheck,
success = false
)
)
)
}

private def verifySubjectVerification(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
private def verifySubjectVerification(credential: String): IO[VcVerificationServiceError, VcVerificationResult] = {
val result =
for {
decodedJwt <-
Expand All @@ -116,27 +104,30 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe

result
.as(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.SubjectVerification,
success = true
)
)
.catchAll(_ =>
ZIO.succeed(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.SubjectVerification,
success = false
)
)
)
}

private def verifySignature(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
private def verifySignature(credential: String): IO[VcVerificationServiceError, VcVerificationResult] = {
JwtCredential
.validateEncodedJWT(JWT(credential))(didResolver)
.mapError(error => VcVerificationServiceError.UnexpectedError(error))
.map(validation =>
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.SignatureVerification,
success = validation
.map(_ => true)
Expand All @@ -145,9 +136,10 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe
)
}

private def verifyExpiration(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
private def verifyExpiration(credential: String): IO[VcVerificationServiceError, VcVerificationResult] = {
ZIO.succeed(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.ExpirationCheck,
success = JwtCredential
.validateExpiration(JWT(credential))
Expand All @@ -157,9 +149,10 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe
)
}

private def verifyNotBefore(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
private def verifyNotBefore(credential: String): IO[VcVerificationServiceError, VcVerificationResult] = {
ZIO.succeed(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.NotBeforeCheck,
success = JwtCredential
.validateNotBefore(JWT(credential))
Expand All @@ -169,9 +162,10 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe
)
}

private def verifyAlgorithm(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
private def verifyAlgorithm(credential: String): IO[VcVerificationServiceError, VcVerificationResult] = {
ZIO.succeed(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.AlgorithmVerification,
success = JWTVerification
.validateAlgorithm(JWT(credential))
Expand All @@ -181,12 +175,13 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe
)
}

private def verifyIssuerIdentification(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
private def verifyIssuerIdentification(credential: String): IO[VcVerificationServiceError, VcVerificationResult] = {
JwtCredential
.validateIssuerJWT(JWT(credential))(didResolver)
.mapError(error => VcVerificationServiceError.UnexpectedError(error))
.map(validation =>
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.IssuerIdentification,
success = validation
.map(_ => true)
Expand All @@ -195,7 +190,7 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe
)
}

private def verifySemanticCheckOfClaims(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
private def verifySemanticCheckOfClaims(credential: String): IO[VcVerificationServiceError, VcVerificationResult] = {
val result =
for {
decodedJwt <-
Expand All @@ -206,20 +201,35 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriDereferencer: URIDe

result
.as(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.SubjectVerification,
success = true
)
)
.catchAll(_ =>
ZIO.succeed(
VcVerificationOutcome(
VcVerificationResult(
credential = credential,
verification = VcVerification.SubjectVerification,
success = false
)
)
)
}

private def verifyAudienceCheck(
credential: String,
aud: String
): IO[VcVerificationServiceError, VcVerificationResult] = {
ZIO.succeed(
VcVerificationResult(
credential = credential,
verification = VcVerification.SubjectVerification,
success = true
)
)
}
}

object VcVerificationServiceImpl {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ package io.iohk.atala.agent.server
import io.iohk.atala.agent.notification.WebhookPublisher
import io.iohk.atala.agent.server.config.AppConfig
import io.iohk.atala.agent.server.http.{ZHttp4sBlazeServer, ZHttpEndpoints}
import io.iohk.atala.agent.server.jobs.{
ConnectBackgroundJobs,
DIDStateSyncBackgroundJobs,
IssueBackgroundJobs,
PresentBackgroundJobs,
StatusListJobs
}
import io.iohk.atala.agent.server.jobs.*
import io.iohk.atala.agent.walletapi.model.{Entity, Wallet, WalletSeed}
import io.iohk.atala.agent.walletapi.service.{EntityService, ManagedDIDService, WalletManagementService}
import io.iohk.atala.agent.walletapi.storage.DIDNonSecretStorage
Expand All @@ -31,8 +25,7 @@ import io.iohk.atala.pollux.credentialschema.{SchemaRegistryServerEndpoints, Ver
import io.iohk.atala.pollux.vc.jwt.DidResolver as JwtDidResolver
import io.iohk.atala.presentproof.controller.PresentProofServerEndpoints
import io.iohk.atala.resolvers.DIDResolver
import io.iohk.atala.shared.models.WalletAdministrationContext
import io.iohk.atala.shared.models.{HexString, WalletAccessContext, WalletId}
import io.iohk.atala.shared.models.{HexString, WalletAccessContext, WalletAdministrationContext, WalletId}
import io.iohk.atala.shared.utils.DurationOps.toMetricsSeconds
import io.iohk.atala.system.controller.SystemServerEndpoints
import io.iohk.atala.verification.controller.VcVerificationServerEndpoints
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.iohk.atala.verification.controller

import io.iohk.atala.api.http.{ErrorResponse, RequestContext}
import io.iohk.atala.pollux.core.service.verification.{VcVerification, VcVerificationRequest, VcVerificationService}
import io.iohk.atala.pollux.core.service.verification.VcVerificationService
import io.iohk.atala.verification.controller
import zio.*

Expand All @@ -10,33 +10,20 @@ class VcVerificationControllerImpl(vcVerificationService: VcVerificationService)
override def verify(
requests: List[controller.http.VcVerificationRequest]
)(implicit rc: RequestContext): IO[ErrorResponse, List[controller.http.VcVerificationResponse]] = {
val serviceRequests =
requests.map(request => {
val verifications =
if (request.verifications.isEmpty)
VcVerification.values.toList
else
request.verifications

VcVerificationRequest(
credential = request.credential,
verifications = verifications
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))
)
})
for {
results <-
vcVerificationService
.verify(serviceRequests)
.mapError(error => VcVerificationController.toHttpError(error))
} yield results.map(result =>
controller.http.VcVerificationResponse(
result.credential,
result.checks,
result.successfulChecks,
result.failedChecks,
result.failedAsWarningChecks
)
)
}))
ZIO.succeed(List.empty)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.iohk.atala.verification.controller.http

import sttp.tapir.Schema
import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder}

final case class ParameterizableVcVerification(
verification: VcVerification,
parameter: Option[VcVerificationParameter]
)
object ParameterizableVcVerification {
given encoder: JsonEncoder[ParameterizableVcVerification] =
DeriveJsonEncoder.gen[ParameterizableVcVerification]

given decoder: JsonDecoder[ParameterizableVcVerification] =
DeriveJsonDecoder.gen[ParameterizableVcVerification]

given schema: Schema[ParameterizableVcVerification] = Schema.derived
}
Loading

0 comments on commit 913fc5e

Please sign in to comment.