Skip to content

Commit

Permalink
revert the local changes
Browse files Browse the repository at this point in the history
Signed-off-by: mineme0110 <[email protected]>

scalafmt

Signed-off-by: mineme0110 <[email protected]>

Updated unit test to support kid

Signed-off-by: mineme0110 <[email protected]>

OIDC feature doesnt have kid support in JWT

Signed-off-by: mineme0110 <[email protected]>

style: apply linters automatic fixes (#1425)

Signed-off-by: Hyperledger Bot <[email protected]>
Co-authored-by: Hyperledger Bot <[email protected]>

Add new keyid test for JWT with ED25519 signed credential

Signed-off-by: mineme0110 <[email protected]>
  • Loading branch information
mineme0110 committed Oct 30, 2024
1 parent 91baa36 commit 4f36468
Show file tree
Hide file tree
Showing 12 changed files with 290 additions and 49 deletions.
13 changes: 10 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ inThisBuild(
// scalacOptions += "-Ysafe-init",
// scalacOptions += "-Werror", // <=> "-Xfatal-warnings"
scalacOptions += "-Dquill.macro.log=false", // disable quill macro logs // TODO https://github.com/zio/zio-protoquill/issues/470,
scalacOptions ++= Seq("-Xmax-inlines", "50") // manually increase max-inlines above 32 (https://github.com/circe/circe/issues/2162)
scalacOptions ++= Seq(
"-Xmax-inlines",
"50"
) // manually increase max-inlines above 32 (https://github.com/circe/circe/issues/2162)
)
)

Expand Down Expand Up @@ -107,15 +110,19 @@ lazy val D = new {
val zioConcurrent: ModuleID = "dev.zio" %% "zio-concurrent" % V.zio
val zioHttp: ModuleID = "dev.zio" %% "zio-http" % V.zioHttp
val zioKafka: ModuleID = "dev.zio" %% "zio-kafka" % V.zioKafka excludeAll (
ExclusionRule("dev.zio", "zio_3"), ExclusionRule("dev.zio", "zio-streams_3")
ExclusionRule("dev.zio", "zio_3"),
ExclusionRule("dev.zio", "zio-streams_3")
)
val zioCatsInterop: ModuleID = "dev.zio" %% "zio-interop-cats" % V.zioCatsInterop
val zioMetricsConnectorMicrometer: ModuleID = "dev.zio" %% "zio-metrics-connectors-micrometer" % V.zioMetricsConnector
val tapirPrometheusMetrics: ModuleID = "com.softwaremill.sttp.tapir" %% "tapir-prometheus-metrics" % V.tapir
val micrometer: ModuleID = "io.micrometer" % "micrometer-registry-prometheus" % V.micrometer
val micrometerPrometheusRegistry = "io.micrometer" % "micrometer-core" % V.micrometer
val scalaUri = Seq(
"io.lemonlabs" %% "scala-uri" % V.scalaUri exclude ("org.typelevel", "cats-parse_3"), // Exclude cats-parse to avoid deps conflict
"io.lemonlabs" %% "scala-uri" % V.scalaUri exclude (
"org.typelevel",
"cats-parse_3"
), // Exclude cats-parse to avoid deps conflict
"org.typelevel" % "cats-parse_3" % "1.0.0", // Replace with version 1.0.0
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,45 +38,59 @@ object MockDIDService extends Mock[DIDService] {
}
}

def createDID(
verificationRelationship: VerificationRelationship
private def createDIDInternal(
verificationRelationship: VerificationRelationship,
addEd25519Key: Boolean = false
): (PrismDIDOperation.Create, Secp256k1KeyPair, DIDMetadata, DIDData) = {
val masterKeyPair = Apollo.default.secp256k1.generateKeyPair
val keyPair = Apollo.default.secp256k1.generateKeyPair

val createOperation = PrismDIDOperation.Create(
publicKeys = Seq(
InternalPublicKey(
id = KeyId("master-0"),
purpose = InternalKeyPurpose.Master,
publicKeyData = PublicKeyData.ECCompressedKeyData(
crv = EllipticCurve.SECP256K1,
data = Base64UrlString.fromByteArray(masterKeyPair.publicKey.getEncodedCompressed)
)
),
PublicKey(
id = KeyId("key-0"),
purpose = verificationRelationship,
publicKeyData = PublicKeyData.ECCompressedKeyData(
crv = EllipticCurve.SECP256K1,
data = Base64UrlString.fromByteArray(keyPair.publicKey.getEncodedCompressed)
)
),
val basePublicKeys = Seq(
InternalPublicKey(
id = KeyId("master-0"),
purpose = InternalKeyPurpose.Master,
publicKeyData = PublicKeyData.ECCompressedKeyData(
crv = EllipticCurve.SECP256K1,
data = Base64UrlString.fromByteArray(masterKeyPair.publicKey.getEncodedCompressed)
)
),
PublicKey(
id = KeyId("key-0"),
purpose = verificationRelationship,
publicKeyData = PublicKeyData.ECCompressedKeyData(
crv = EllipticCurve.SECP256K1,
data = Base64UrlString.fromByteArray(keyPair.publicKey.getEncodedCompressed)
)
)
)

val publicKeys = if (addEd25519Key) {
val keyPair2 = Apollo.default.ed25519.generateKeyPair
basePublicKeys :+ PublicKey(
id = KeyId("key-1"),
purpose = verificationRelationship,
publicKeyData = PublicKeyData.ECKeyData(
crv = EllipticCurve.ED25519,
x = Base64UrlString.fromByteArray(keyPair2.publicKey.getEncoded),
y = Base64UrlString.fromByteArray(Array.emptyByteArray),
)
)
} else basePublicKeys

val createOperation = PrismDIDOperation.Create(
publicKeys = publicKeys,
services = Nil,
context = Nil,
)
val longFormDid = PrismDID.buildLongFormFromOperation(createOperation)
// val canonicalDid = longFormDid.asCanonical

val didMetadata =
DIDMetadata(
lastOperationHash = ArraySeq.from(longFormDid.stateHash.toByteArray),
canonicalId = None, // unpublished DID must not contain canonicalId
deactivated = false, // unpublished DID cannot be deactivated
created = None, // unpublished DID cannot have timestamp
updated = None // unpublished DID cannot have timestamp
)
val didMetadata = DIDMetadata(
lastOperationHash = ArraySeq.from(longFormDid.stateHash.toByteArray),
canonicalId = None,
deactivated = false,
created = None,
updated = None
)
val didData = DIDData(
id = longFormDid.asCanonical,
publicKeys = createOperation.publicKeys.collect { case pk: PublicKey => pk },
Expand All @@ -87,6 +101,125 @@ object MockDIDService extends Mock[DIDService] {
(createOperation, keyPair, didMetadata, didData)
}

def createDIDOIDC(
verificationRelationship: VerificationRelationship
): (PrismDIDOperation.Create, Secp256k1KeyPair, DIDMetadata, DIDData) = {
createDIDInternal(verificationRelationship, addEd25519Key = false)
}

def createDID(
verificationRelationship: VerificationRelationship
): (PrismDIDOperation.Create, Secp256k1KeyPair, DIDMetadata, DIDData) = {
createDIDInternal(verificationRelationship, addEd25519Key = true)
}
// def createDIDOIDC(
// verificationRelationship: VerificationRelationship
// ): (PrismDIDOperation.Create, Secp256k1KeyPair, DIDMetadata, DIDData) = {
// val masterKeyPair = Apollo.default.secp256k1.generateKeyPair
// val keyPair = Apollo.default.secp256k1.generateKeyPair
//
// val createOperation = PrismDIDOperation.Create(
// publicKeys = Seq(
// InternalPublicKey(
// id = KeyId("master-0"),
// purpose = InternalKeyPurpose.Master,
// publicKeyData = PublicKeyData.ECCompressedKeyData(
// crv = EllipticCurve.SECP256K1,
// data = Base64UrlString.fromByteArray(masterKeyPair.publicKey.getEncodedCompressed)
// )
// ),
// PublicKey(
// id = KeyId("key-0"),
// purpose = verificationRelationship,
// publicKeyData = PublicKeyData.ECCompressedKeyData(
// crv = EllipticCurve.SECP256K1,
// data = Base64UrlString.fromByteArray(keyPair.publicKey.getEncodedCompressed)
// )
// ),
// ),
// services = Nil,
// context = Nil,
// )
// val longFormDid = PrismDID.buildLongFormFromOperation(createOperation)
// // val canonicalDid = longFormDid.asCanonical
//
// val didMetadata =
// DIDMetadata(
// lastOperationHash = ArraySeq.from(longFormDid.stateHash.toByteArray),
// canonicalId = None, // unpublished DID must not contain canonicalId
// deactivated = false, // unpublished DID cannot be deactivated
// created = None, // unpublished DID cannot have timestamp
// updated = None // unpublished DID cannot have timestamp
// )
// val didData = DIDData(
// id = longFormDid.asCanonical,
// publicKeys = createOperation.publicKeys.collect { case pk: PublicKey => pk },
// services = createOperation.services,
// internalKeys = createOperation.publicKeys.collect { case pk: InternalPublicKey => pk },
// context = createOperation.context
// )
// (createOperation, keyPair, didMetadata, didData)
// }
//
// def createDID(
// verificationRelationship: VerificationRelationship
// ): (PrismDIDOperation.Create, Secp256k1KeyPair, DIDMetadata, DIDData) = {
// val masterKeyPair = Apollo.default.secp256k1.generateKeyPair
// val keyPair = Apollo.default.secp256k1.generateKeyPair
// val keyPair2 = Apollo.default.ed25519.generateKeyPair
//
// val createOperation = PrismDIDOperation.Create(
// publicKeys = Seq(
// InternalPublicKey(
// id = KeyId("master-0"),
// purpose = InternalKeyPurpose.Master,
// publicKeyData = PublicKeyData.ECCompressedKeyData(
// crv = EllipticCurve.SECP256K1,
// data = Base64UrlString.fromByteArray(masterKeyPair.publicKey.getEncodedCompressed)
// )
// ),
// PublicKey(
// id = KeyId("key-0"),
// purpose = verificationRelationship,
// publicKeyData = PublicKeyData.ECCompressedKeyData(
// crv = EllipticCurve.SECP256K1,
// data = Base64UrlString.fromByteArray(keyPair.publicKey.getEncodedCompressed)
// )
// ),
// PublicKey(
// id = KeyId("key-1"),
// purpose = verificationRelationship,
// publicKeyData = PublicKeyData.ECKeyData(
// crv = EllipticCurve.ED25519,
// x = Base64UrlString.fromByteArray(keyPair2.publicKey.getEncoded),
// y = Base64UrlString.fromByteArray(Array.emptyByteArray),
// )
// ),
// ),
// services = Nil,
// context = Nil,
// )
// val longFormDid = PrismDID.buildLongFormFromOperation(createOperation)
// // val canonicalDid = longFormDid.asCanonical
//
// val didMetadata =
// DIDMetadata(
// lastOperationHash = ArraySeq.from(longFormDid.stateHash.toByteArray),
// canonicalId = None, // unpublished DID must not contain canonicalId
// deactivated = false, // unpublished DID cannot be deactivated
// created = None, // unpublished DID cannot have timestamp
// updated = None // unpublished DID cannot have timestamp
// )
// val didData = DIDData(
// id = longFormDid.asCanonical,
// publicKeys = createOperation.publicKeys.collect { case pk: PublicKey => pk },
// services = createOperation.services,
// internalKeys = createOperation.publicKeys.collect { case pk: InternalPublicKey => pk },
// context = createOperation.context
// )
// (createOperation, keyPair, didMetadata, didData)
// }

def resolveDIDExpectation(didMetadata: DIDMetadata, didData: DIDData): Expectation[DIDService] =
MockDIDService.ResolveDID(
assertion = Assertion.anything,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ object OIDCCredentialIssuerServiceSpec
)

private val (_, issuerKp, issuerDidMetadata, issuerDidData) =
MockDIDService.createDID(VerificationRelationship.AssertionMethod)
MockDIDService.createDIDOIDC(VerificationRelationship.AssertionMethod)

private val (holderOp, holderKp, holderDidMetadata, holderDidData) =
MockDIDService.createDID(VerificationRelationship.AssertionMethod)
MockDIDService.createDIDOIDC(VerificationRelationship.AssertionMethod)

private val holderDidServiceExpectations =
MockDIDService.resolveDIDExpectation(holderDidMetadata, holderDidData)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ class CredentialRepositoryInMemory(
updatedAt = Some(Instant.now),
protocolState = protocolState,
subjectId = Some(subjectId),
keyId = keyId,
metaRetries = maxRetries,
metaLastFailure = None,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.hyperledger.identus.pollux.core.service

import io.circe.syntax.*
import io.circe.Json
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.hyperledger.identus.agent.walletapi.service.MockManagedDIDService
import org.hyperledger.identus.castor.core.model.did.*
import org.hyperledger.identus.castor.core.model.did.VerificationRelationship.AssertionMethod
Expand All @@ -15,6 +16,7 @@ import org.hyperledger.identus.pollux.core.model.error.CredentialServiceError.*
import org.hyperledger.identus.pollux.core.model.schema.CredentialDefinition
import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.{ProtocolState, Role}
import org.hyperledger.identus.pollux.core.service.uriResolvers.ResourceUrlResolver
import org.hyperledger.identus.pollux.core.service.CredentialServiceImplSpec.test
import org.hyperledger.identus.pollux.vc.jwt.{CredentialIssuer, JWT, JwtCredential, JwtCredentialPayload}
import org.hyperledger.identus.shared.models.{KeyId, UnmanagedFailureException, WalletAccessContext, WalletId}
import zio.*
Expand All @@ -23,10 +25,11 @@ import zio.test.*
import zio.test.Assertion.*

import java.nio.charset.StandardCharsets
import java.security.Security
import java.util.{Base64, UUID}

object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceSpecHelper {

Security.addProvider(new BouncyCastleProvider());
override def spec = suite("CredentialServiceImpl")(
singleWalletJWTCredentialSpec,
singleWalletAnonCredsCredentialSpec,
Expand Down Expand Up @@ -446,7 +449,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS
offer = offerCredential()
subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3"
offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer)
_ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id")))
_ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("key-0")))
_ <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id)
_ <- holderSvc.markRequestSent(offerReceivedRecord.id)
issue = issueCredential(thid = Some(offerReceivedRecord.thid))
Expand All @@ -462,7 +465,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS
offer = offerCredential()
subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3"
offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer)
_ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id")))
_ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("key-0")))
_ <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id)
_ <- holderSvc.markRequestSent(offerReceivedRecord.id)
issue = issueCredential(thid = Some(offerReceivedRecord.thid))
Expand All @@ -481,7 +484,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS
offer = offerCredential()
subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3"
offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer)
_ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id")))
_ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("key-0")))
_ <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id)
_ <- holderSvc.markRequestSent(offerReceivedRecord.id)
issue = issueCredential(thid = Some(DidCommID()))
Expand All @@ -498,7 +501,62 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS
issuerSvc <- ZIO.service[CredentialService].provideSomeLayer(credentialServiceLayer)
holderSvc <- ZIO.service[CredentialService].provideSomeLayer(credentialServiceLayer)
// Issuer creates offer
offerCreatedRecord <- issuerSvc.createJWTIssueCredentialRecord()
offerCreatedRecord <- issuerSvc.createJWTIssueCredentialRecord(kidIssuer = Some(KeyId("key-0")))
issuerRecordId = offerCreatedRecord.id
// Issuer sends offer
_ <- issuerSvc.markOfferSent(issuerRecordId)
msg <- ZIO.fromEither(offerCreatedRecord.offerCredentialData.get.makeMessage.asJson.as[Message])
// Holder receives offer
offerCredential <- ZIO.fromEither(OfferCredential.readFromMessage(msg))
offerReceivedRecord <- holderSvc.receiveCredentialOffer(offerCredential)
holderRecordId = offerReceivedRecord.id
subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3"
// Holder accepts offer
_ <- holderSvc.acceptCredentialOffer(holderRecordId, Some(subjectId), Some(KeyId("key-0")))
// Holder generates proof
requestGeneratedRecord <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id)
// Holder sends offer
_ <- holderSvc.markRequestSent(holderRecordId)
msg <- ZIO.fromEither(requestGeneratedRecord.requestCredentialData.get.makeMessage.asJson.as[Message])
// Issuer receives request
requestCredential <- ZIO.fromEither(RequestCredential.readFromMessage(msg))
requestReceivedRecord <- issuerSvc.receiveCredentialRequest(requestCredential)
// Issuer accepts request
requestAcceptedRecord <- issuerSvc.acceptCredentialRequest(issuerRecordId)
// Issuer generates credential
credentialGenerateRecord <- issuerSvc.generateJWTCredential(
issuerRecordId,
"status-list-registry"
)
decodedJWT <- credentialGenerateRecord.issueCredentialData.get.attachments.head.data match {
case MyBase64(value) =>
val ba = new String(Base64.getUrlDecoder.decode(value))
JwtCredential.decodeJwt(JWT(ba))
case _ => ZIO.fail("Error")
}
// Issuer sends credential
_ <- issuerSvc.markCredentialSent(issuerRecordId)
msg <- ZIO.fromEither(credentialGenerateRecord.issueCredentialData.get.makeMessage.asJson.as[Message])
// Holder receives credential
issueCredential <- ZIO.fromEither(IssueCredential.readFromMessage(msg))
_ <- holderSvc.receiveCredentialIssue(issueCredential)
} yield assertTrue(
decodedJWT.issuer ==
CredentialIssuer(
id = decodedJWT.iss,
`type` = "Profile"
)
)
}.provideSomeLayer(
(holderDidServiceExpectations ++ issuerDidServiceExpectations).toLayer
++ (holderManagedDIDServiceExpectations ++ issuerManagedDIDServiceExpectations).toLayer
),
test("Happy flow is successfully executed with ED25519") {
for {
issuerSvc <- ZIO.service[CredentialService].provideSomeLayer(credentialServiceLayer)
holderSvc <- ZIO.service[CredentialService].provideSomeLayer(credentialServiceLayer)
// Issuer creates offer
offerCreatedRecord <- issuerSvc.createJWTIssueCredentialRecord(kidIssuer = Some(KeyId("key-1")))
issuerRecordId = offerCreatedRecord.id
// Issuer sends offer
_ <- issuerSvc.markOfferSent(issuerRecordId)
Expand All @@ -509,7 +567,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS
holderRecordId = offerReceivedRecord.id
subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3"
// Holder accepts offer
_ <- holderSvc.acceptCredentialOffer(holderRecordId, Some(subjectId), Some(KeyId("my-key-id")))
_ <- holderSvc.acceptCredentialOffer(holderRecordId, Some(subjectId), Some(KeyId("key-1")))
// Holder generates proof
requestGeneratedRecord <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id)
// Holder sends offer
Expand Down
Loading

0 comments on commit 4f36468

Please sign in to comment.