Skip to content

Commit

Permalink
feat(prism-agnet): Verifiable Credential (#281)
Browse files Browse the repository at this point in the history
Signed-off-by: Shailesh Patil <shaileshpatil@shaileshs-mbp.home>

Added the JWT verfication

Signed-off-by: Shailesh Patil <shaileshpatil@shaileshs-mbp.home>

cleanup

Co-authored-by: Shailesh Patil <shaileshpatil@shaileshs-mbp.home>
  • Loading branch information
mineme0110 and Shailesh Patil committed Dec 20, 2022
1 parent 6d554d4 commit ae74e20
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 27 deletions.
2 changes: 1 addition & 1 deletion infrastructure/local/.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MERCURY_MEDIATOR_VERSION=0.2.0
IRIS_SERVICE_VERSION=0.1.0
PRISM_AGENT_VERSION=0.22.0
PRISM_NODE_VERSION=2.0.0
PRISM_NODE_VERSION=v2.0.0
PORT=80
8 changes: 6 additions & 2 deletions prism-agent/service/api/http/pollux/schemas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -540,16 +540,20 @@ components:
type: string
PresentationStatus:
description: Presentation Status
required: [presentationId, status, proofs]
required: [presentationId, status, proofs, data]
properties:
presentationId:
type: string
status:
type: string
proofs:
type: array
type: array
items:
$ref: "#/components/schemas/ProofRequestAux"
data:
type: array
items:
type: string
connectionId:
type: string
RequestPresentationAction:
Expand Down
2 changes: 1 addition & 1 deletion prism-agent/service/project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object Dependencies {
val akka = "2.6.20"
val akkaHttp = "10.2.9"
val castor = "0.5.1"
val pollux = "0.13.0"
val pollux = "0.14.0"
val connect = "0.6.0"
val bouncyCastle = "1.70"
val logback = "1.4.5"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ object Main extends ZIOAppDefault {

app <- appComponents(didCommServicePort, restServicePort).provide(
didCommAgentLayer(didCommServiceUrl),
AppModule.didJwtResolverlayer,
AppModule.didServiceLayer,
DIDResolver.layer,
ZioHttpClient.layer,
AppModule.credentialServiceLayer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ import io.circe.DecodingFailure
import io.iohk.atala.agent.walletapi.sql.JdbcDIDSecretStorage
import io.iohk.atala.resolvers.DIDResolver
import io.iohk.atala.agent.walletapi.storage.DIDSecretStorage
import io.iohk.atala.pollux.vc.jwt.{DidResolver => JwtDidResolver}
import io.iohk.atala.castor.core.model.error.DIDOperationError.TooManyDidServiceAccess
import io.iohk.atala.pollux.vc.jwt.PrismDidResolver

object Modules {

Expand Down Expand Up @@ -153,13 +156,16 @@ object Modules {
Server.start(port, app)
}

val didCommExchangesJob
: RIO[DIDResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage, Unit] =
val didCommExchangesJob: RIO[
DIDResolver & JwtDidResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage,
Unit
] =
BackgroundJobs.didCommExchanges
.repeat(Schedule.spaced(10.seconds))
.unit

val presentProofExchangeJob: RIO[DIDResolver & HttpClient & PresentationService & ManagedDIDService, Unit] =
val presentProofExchangeJob
: RIO[DIDResolver & JwtDidResolver & HttpClient & PresentationService & ManagedDIDService, Unit] =
BackgroundJobs.presentProofExchanges
.repeat(Schedule.spaced(10.seconds))
.unit
Expand Down Expand Up @@ -397,6 +403,9 @@ object SystemModule {
object AppModule {
val didOpValidatorLayer: ULayer[DIDOperationValidator] = DIDOperationValidator.layer()

val didJwtResolverlayer: URLayer[DIDService, JwtDidResolver] =
ZLayer.fromFunction(PrismDidResolver(_))

val didServiceLayer: TaskLayer[DIDService] =
(didOpValidatorLayer ++ GrpcModule.layers) >>> DIDServiceImpl.layer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
given RootJsonFormat[ProofRequestAux] = jsonFormat2(ProofRequestAux.apply)
given RootJsonFormat[RequestPresentationInput] = jsonFormat2(RequestPresentationInput.apply)
given RootJsonFormat[RequestPresentationOutput] = jsonFormat1(RequestPresentationOutput.apply)
given RootJsonFormat[PresentationStatus] = jsonFormat4(PresentationStatus.apply)
given RootJsonFormat[PresentationStatus] = jsonFormat5(PresentationStatus.apply)
given RootJsonFormat[RequestPresentationAction] = jsonFormat2(RequestPresentationAction.apply)

// Connections Management
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import io.iohk.atala.agent.openapi.model.*
import akka.http.scaladsl.server.Directives.*
import akka.http.scaladsl.marshalling.ToEntityMarshaller
import akka.http.scaladsl.server.Route

import zio._
import scala.concurrent.Future
import io.iohk.atala.agent.server.http.model.HttpServiceError
Expand All @@ -24,6 +23,7 @@ import io.iohk.atala.pollux.vc.jwt.Issuer
import io.iohk.atala.pollux.core.service.PresentationService
import io.iohk.atala.pollux.core.model.error.PresentationError
import io.iohk.atala.pollux.core.model.PresentationRecord
import io.iohk.atala.mercury.model.Base64

class PresentProofApiServiceImpl(
presentationService: PresentationService,
Expand Down Expand Up @@ -88,7 +88,18 @@ class PresentProofApiServiceImpl(

presentationStatus = records.map { record =>
val connectionId = record.connectionId
PresentationStatus(record.id.toString, record.protocolState.toString, Seq.empty, connectionId)
val data = record.presentationData match
case Some(p) =>
p.attachments.head.data match {
case Base64(data) =>
val base64Decoded = new String(java.util.Base64.getDecoder().decode(data)).drop(1).dropRight(1)
println(s"Base64decode:\n\n ${base64Decoded} \n\n")
Seq(base64Decoded)
case any => ???
}
case None => Seq.empty

PresentationStatus(record.id.toString, record.protocolState.toString, Seq.empty, data, connectionId)
}
} yield presentationStatus

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import io.iohk.atala.pollux.core.model.IssueCredentialRecord
import io.iohk.atala.pollux.core.model.error.CredentialServiceError
import io.iohk.atala.pollux.core.service.CredentialService
import io.iohk.atala.pollux.vc.jwt.W3cCredentialPayload
import zio.*

import zio.Duration
import java.time.Instant

import java.time.Clock
import java.time.ZoneId
import io.iohk.atala.mercury.DidComm
import io.iohk.atala.mercury.MediaTypes
import io.iohk.atala.mercury.MessagingService
Expand All @@ -22,7 +22,7 @@ import io.iohk.atala.mercury.protocol.presentproof.RequestPresentation
import io.iohk.atala.resolvers.DIDResolver
import io.iohk.atala.resolvers.UniversalDidResolver
import java.io.IOException

import io.iohk.atala.pollux.vc.jwt._
import zhttp.service._
import zhttp.http._
import io.iohk.atala.pollux.vc.jwt.W3CCredential
Expand All @@ -37,7 +37,7 @@ import io.iohk.atala.agent.walletapi.model.error.DIDSecretStorageError
import io.iohk.atala.agent.walletapi.model.ManagedDIDTemplate
import io.iohk.atala.agent.walletapi.sql.JdbcDIDSecretStorage
import io.iohk.atala.pollux.vc.jwt.ES256KSigner
import io.iohk.atala.castor.core.model.did.EllipticCurve
import io.iohk.atala.castor.core.model.did._
import java.security.KeyFactory
import java.security.spec.EncodedKeySpec
import java.security.spec.ECPrivateKeySpec
Expand All @@ -53,6 +53,9 @@ import io.circe.Json
import io.circe.syntax._
import io.iohk.atala.agent.walletapi.storage.DIDSecretStorage
import io.iohk.atala.agent.walletapi.model.error.CreateManagedDIDError
import io.iohk.atala.pollux.vc.jwt.JWT
import io.iohk.atala.pollux.vc.jwt.{DidResolver => JwtDidResolver}
import io.iohk.atala.agent.walletapi.model._

object BackgroundJobs {

Expand All @@ -77,7 +80,10 @@ object BackgroundJobs {

private[this] def performExchange(
record: IssueCredentialRecord
): URIO[DIDResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage, Unit] = {
): URIO[
DIDResolver & JwtDidResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage,
Unit
] = {
import IssueCredentialRecord._
import IssueCredentialRecord.ProtocolState._
import IssueCredentialRecord.PublicationState._
Expand Down Expand Up @@ -249,9 +255,16 @@ object BackgroundJobs {
private[this] def createPrismDIDIssuer(): ZIO[ManagedDIDService & DIDSecretStorage, Throwable, Issuer] = {
for {
managedDIDService <- ZIO.service[ManagedDIDService]
longFormPrismDID <- managedDIDService.createAndStoreDID(ManagedDIDTemplate(Nil, Nil))
longFormPrismDID <- managedDIDService.createAndStoreDID(
ManagedDIDTemplate(
Seq(
DIDPublicKeyTemplate("issuing", VerificationRelationship.Authentication)
),
Nil
)
)
didSecretStorage <- ZIO.service[DIDSecretStorage]
maybeECKeyPair <- didSecretStorage.getKey(longFormPrismDID.asCanonical, "master0")
maybeECKeyPair <- didSecretStorage.getKey(longFormPrismDID.asCanonical, "issuing")
_ <- ZIO.logInfo(s"ECKeyPair => $maybeECKeyPair")
maybeIssuer <- ZIO.succeed(maybeECKeyPair.map(ecKeyPair => {
val ba = ecKeyPair.privateKey.toPaddedByteArray(EllipticCurve.SECP256K1)
Expand Down Expand Up @@ -284,7 +297,7 @@ object BackgroundJobs {

private[this] def performPresentation(
record: PresentationRecord
): URIO[DIDResolver & HttpClient & PresentationService & ManagedDIDService, Unit] = {
): URIO[DIDResolver & JwtDidResolver & HttpClient & PresentationService & ManagedDIDService, Unit] = {
import io.iohk.atala.pollux.core.model.PresentationRecord.ProtocolState._

val aux = for {
Expand Down Expand Up @@ -332,14 +345,43 @@ object BackgroundJobs {
} yield ()
case PresentationRecord(id, _, _, _, _, _, _, _, PresentationSent, _, _, _) =>
ZIO.logDebug("PresentationRecord: PresentationSent") *> ZIO.unit
case PresentationRecord(id, _, _, _, _, _, _, _, PresentationReceived, _, _, _) =>
case PresentationRecord(id, _, _, _, _, _, _, _, PresentationReceived, _, _, presentation) => // Verifier
ZIO.logDebug("PresentationRecord: PresentationReceived") *> ZIO.unit
for {
_ <- ZIO.log(s"PresentationRecord: PresentationPending (Send Massage)")
// TODO Verify https://input-output.atlassian.net/browse/ATL-2702
service <- ZIO.service[PresentationService]
_ <- service.markPresentationVerified(id)
} yield ()
val clock = java.time.Clock.system(ZoneId.systemDefault)
presentation match
case None => ZIO.fail(InvalidState("PresentationRecord in 'PresentationReceived' with no Presentation"))
case Some(p) =>
for {
_ <- ZIO.log(s"PresentationRecord: 'PresentationReceived' ")
didResolverService <- ZIO.service[JwtDidResolver]
credentialsValidationResult <- p.attachments.head.data match {
case Base64(data) =>
val base64Decoded = new String(java.util.Base64.getDecoder().decode(data)).drop(1).dropRight(1)

println(s"Base64decode:\n\n ${base64Decoded} \n\n")
JwtPresentation.verify(
JWT(base64Decoded),
JwtPresentation.PresentationVerificationOptions(
maybeProofPurpose = Some(VerificationRelationship.Authentication),
verifySignature = false,
verifyDates = true,
leeway = Duration.Zero,
maybeCredentialOptions = Some(
CredentialVerification.CredentialVerificationOptions(
verifySignature = true,
verifyDates = false,
leeway = Duration.Zero,
maybeProofPurpose = Some(VerificationRelationship.Authentication)
)
)
)
)(didResolverService)(clock)
case any => ZIO.fail(NotImplemented)
}
_ <- ZIO.log(s"CredentialsValidationResult: $credentialsValidationResult")
service <- ZIO.service[PresentationService]
_ <- service.markPresentationVerified(id)
} yield ()
// TODO move the state to PresentationVerified
case PresentationRecord(id, _, _, _, _, _, _, _, PresentationVerified, _, _, _) =>
ZIO.logDebug("PresentationRecord: PresentationVerified") *> ZIO.unit
Expand Down
2 changes: 1 addition & 1 deletion prism-agent/service/version.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ThisBuild / version := "0.9.0-SNAPSHOT"
ThisBuild / version := "0.17.0-SNAPSHOT"

0 comments on commit ae74e20

Please sign in to comment.