Skip to content

Commit

Permalink
feat: VC Verification Audiance check (#969)
Browse files Browse the repository at this point in the history
Signed-off-by: Bassam Riman <[email protected]>
  • Loading branch information
CryptoKnightIOG committed Apr 23, 2024
1 parent 4d128a7 commit 504340d
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -13,30 +12,29 @@ 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)
)
)
}

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"
)
)
}
Expand Down Expand Up @@ -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
)
)
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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")
)
)
}
}

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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}

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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)
)
)
}
Expand Down

0 comments on commit 504340d

Please sign in to comment.