diff --git a/.mega-linter.yml b/.mega-linter.yml index 52fbf26e7d..8bdeef5477 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -27,9 +27,6 @@ DISABLE_LINTERS: - PYTHON_MYPY - PYTHON_PYRIGHT - PYTHON_RUFF - # TODO: revert before merging to `main`. Disabled to ease the development of keycloak extension - - JAVA_CHECKSTYLE - - JAVA_PMD DISABLE_ERRORS_LINTERS: - KOTLIN_KTLINT diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/domain/Openid4VCIProofJwtOps.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/domain/Openid4VCIProofJwtOps.scala index ec849e0e9d..c26698506e 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/domain/Openid4VCIProofJwtOps.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/domain/Openid4VCIProofJwtOps.scala @@ -1,12 +1,11 @@ package org.hyperledger.identus.oid4vci.domain import com.nimbusds.jose.{JOSEObjectType, JWSAlgorithm, JWSHeader, JWSObject, JWSSigner, Payload} -import org.hyperledger.identus.castor.core.model.did.{DID, LongFormPrismDID, PrismDID} -import org.hyperledger.identus.pollux.vc.jwt.{DidResolver, JWT} +import org.hyperledger.identus.castor.core.model.did.{DID, LongFormPrismDID} +import org.hyperledger.identus.pollux.vc.jwt.JWT import org.hyperledger.identus.pollux.vc.jwt.JwtSignerImplicits.* import org.hyperledger.identus.shared.crypto.Secp256k1PrivateKey -import zio.Task -import zio.ZIO +import zio.{Task, ZIO} import java.util.UUID import scala.jdk.CollectionConverters.* diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/service/NonceService.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/service/NonceService.scala deleted file mode 100644 index 90f28058de..0000000000 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/service/NonceService.scala +++ /dev/null @@ -1,42 +0,0 @@ -package org.hyperledger.identus.oid4vci.service - -import org.hyperledger.identus.oid4vci.service.NonceService.NonceGenerator -import zio.Task - -import java.time.Instant -import scala.collection.concurrent.TrieMap - -trait NonceService { - def generateNonce()(implicit gen: NonceGenerator): String = gen() - def validateNonce(nonce: String): Task[Boolean] - def storeNonce(nonce: String, expireAt: Long): Task[Unit] -} - -object NonceService { - type NonceGenerator = () => String - given randomUUID: NonceGenerator = () => java.util.UUID.randomUUID().toString -} - -case class InMemoryNonceService() extends NonceService { - import zio.{Task, ZIO} - private case class NonceRecord(nonce: String, expireAt: Long, fired: Boolean = false) - - private val nonces: TrieMap[String, NonceRecord] = TrieMap.empty - - override def validateNonce(nonce: String): Task[Boolean] = { - nonces.get(nonce) match { - case None => - ZIO.succeed(false) - case Some(n) if !n.fired && n.expireAt > Instant.now().toEpochMilli => - nonces.replace(nonce, n, n.copy(fired = true)) - ZIO.succeed(true) - } - } - - override def storeNonce(nonce: String, expireAt: Long): Task[Unit] = { - nonces.putIfAbsent(nonce, NonceRecord(nonce, expireAt)) match { - case Some(_) => ZIO.fail(new RuntimeException(s"Nonce $nonce already exists")) - case None => ZIO.succeed(()) - } - } -} diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/service/OIDCCredentialIssuerService.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/service/OIDCCredentialIssuerService.scala index 24d4ee974b..04abcca1d9 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/service/OIDCCredentialIssuerService.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/service/OIDCCredentialIssuerService.scala @@ -7,10 +7,22 @@ import org.hyperledger.identus.castor.core.model.did.{DID, PrismDID, Verificatio import org.hyperledger.identus.oid4vci.domain.IssuanceSession import org.hyperledger.identus.oid4vci.http.* import org.hyperledger.identus.oid4vci.storage.IssuanceSessionStorage -import org.hyperledger.identus.pollux.core.service.CredentialService -import org.hyperledger.identus.pollux.vc.jwt.{Issuer, JWT, JWTVerification, JwtCredential, W3cCredentialPayload} -import org.hyperledger.identus.pollux.vc.jwt.DID as PolluxDID -import org.hyperledger.identus.pollux.vc.jwt.DidResolver +import org.hyperledger.identus.pollux.core.model.schema.CredentialSchema +import org.hyperledger.identus.pollux.core.service.{ + CredentialService, + OID4VCIIssuerMetadataService, + OID4VCIIssuerMetadataServiceError, + URIDereferencer +} +import org.hyperledger.identus.pollux.vc.jwt.{ + DID as PolluxDID, + DidResolver, + Issuer, + JWT, + JWTVerification, + JwtCredential, + W3cCredentialPayload +} import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} import zio.* @@ -67,6 +79,16 @@ object OIDCCredentialIssuerService { case class DIDResolutionError(message: String) extends Error + case class CredentialConfigurationNotFound(issuerId: UUID, credentialConfigurationId: String) extends Error { + override def message: String = + s"Credential configuration with id $credentialConfigurationId not found for issuer $issuerId" + } + + case class CredentialSchemaError(cause: org.hyperledger.identus.pollux.core.model.error.CredentialSchemaError) + extends Error { + override def message: String = cause.message + } + case class ServiceError(message: String) extends Error case class UnexpectedError(cause: Throwable) extends Error { @@ -78,8 +100,10 @@ object OIDCCredentialIssuerService { case class OIDCCredentialIssuerServiceImpl( didNonSecretStorage: DIDNonSecretStorage, credentialService: CredentialService, + issuerMetadataService: OID4VCIIssuerMetadataService, issuanceSessionStorage: IssuanceSessionStorage, - didResolver: DidResolver + didResolver: DidResolver, + uriDereferencer: URIDereferencer, ) extends OIDCCredentialIssuerService { import OIDCCredentialIssuerService.Error @@ -95,7 +119,6 @@ case class OIDCCredentialIssuerServiceImpl( ) .mapError(InvalidProof.apply) _ <- verifiedJwtSignature.toZIO.mapError(InvalidProof.apply) - _ <- ZIO.succeed(println(s"JWT proof is verified: ${jwt.value}")) } yield true } @@ -111,7 +134,7 @@ case class OIDCCredentialIssuerServiceImpl( claims: zio.json.ast.Json, credentialIdentifier: Option[String], credentialDefinition: CredentialDefinition - ): IO[OIDCCredentialIssuerService.Error, JWT] = { + ): IO[Error, JWT] = { for { wac <- didNonSecretStorage .getPrismDidWalletId(issuingDID) @@ -181,7 +204,7 @@ case class OIDCCredentialIssuerServiceImpl( override def getIssuanceSessionByIssuerState( issuerState: String - ): IO[OIDCCredentialIssuerService.Error, IssuanceSession] = + ): IO[Error, IssuanceSession] = issuanceSessionStorage .getByIssuerState(issuerState) .mapError(e => ServiceError(s"Failed to get issuance session: ${e.message}")) @@ -193,9 +216,17 @@ case class OIDCCredentialIssuerServiceImpl( credentialConfigurationId: String, issuingDID: PrismDID, claims: zio.json.ast.Json - ): ZIO[WalletAccessContext, OIDCCredentialIssuerService.Error, CredentialOffer] = - // TODO: validate claims with credential schema + ): ZIO[WalletAccessContext, Error, CredentialOffer] = for { + schemaId <- issuerMetadataService + .getCredentialConfigurationById(issuerId, credentialConfigurationId) + .mapError { case _: OID4VCIIssuerMetadataServiceError.CredentialConfigurationNotFound => + CredentialConfigurationNotFound(issuerId, credentialConfigurationId) + } + .map(_.schemaId) + _ <- CredentialSchema + .validateJWTCredentialSubject(schemaId.toString(), simpleZioToCirce(claims).noSpaces, uriDereferencer) + .mapError(e => CredentialSchemaError(e)) session <- buildNewIssuanceSession(issuerId, issuingDID, claims) _ <- issuanceSessionStorage .start(session) @@ -247,8 +278,9 @@ case class OIDCCredentialIssuerServiceImpl( object OIDCCredentialIssuerServiceImpl { val layer: URLayer[ - DIDNonSecretStorage & CredentialService & IssuanceSessionStorage & DidResolver, + DIDNonSecretStorage & CredentialService & IssuanceSessionStorage & DidResolver & URIDereferencer & + OID4VCIIssuerMetadataService, OIDCCredentialIssuerService ] = - ZLayer.fromFunction(OIDCCredentialIssuerServiceImpl(_, _, _, _)) + ZLayer.fromFunction(OIDCCredentialIssuerServiceImpl(_, _, _, _, _, _)) } diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/storage/NonceStorage.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/storage/NonceStorage.scala deleted file mode 100644 index 23137db6b7..0000000000 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/storage/NonceStorage.scala +++ /dev/null @@ -1,9 +0,0 @@ -package org.hyperledger.identus.oid4vci.storage - -trait NonceStorage { - def getNonce(nonceExpiresAt: Long): String - def storeNonce(nonce: String): Unit - def hasNonce(nonce: String): Boolean - def removeNonce(nonce: String): Unit - -} diff --git a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/oid4vci/domain/OIDCCredentialIssuerServiceSpec.scala b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/oid4vci/domain/OIDCCredentialIssuerServiceSpec.scala index 5b51457132..6f1f4aa90d 100644 --- a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/oid4vci/domain/OIDCCredentialIssuerServiceSpec.scala +++ b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/oid4vci/domain/OIDCCredentialIssuerServiceSpec.scala @@ -1,7 +1,6 @@ package org.hyperledger.identus.oid4vci.domain import com.nimbusds.jose.* -import com.nimbusds.jose.jwk.* import org.hyperledger.identus.agent.walletapi.memory.GenericSecretStorageInMemory import org.hyperledger.identus.agent.walletapi.service.{ManagedDIDService, MockManagedDIDService} import org.hyperledger.identus.agent.walletapi.storage.{DIDNonSecretStorage, MockDIDNonSecretStorage} @@ -10,6 +9,8 @@ import org.hyperledger.identus.castor.core.service.{DIDService, MockDIDService} import org.hyperledger.identus.oid4vci.http.{ClaimDescriptor, CredentialDefinition, Localization} import org.hyperledger.identus.oid4vci.service.{OIDCCredentialIssuerService, OIDCCredentialIssuerServiceImpl} import org.hyperledger.identus.oid4vci.storage.InMemoryIssuanceSessionService +import org.hyperledger.identus.pollux.core.model.oid4vci.CredentialConfiguration +import org.hyperledger.identus.pollux.core.model.CredentialFormat import org.hyperledger.identus.pollux.core.repository.{ CredentialRepository, CredentialRepositoryInMemory, @@ -17,7 +18,7 @@ import org.hyperledger.identus.pollux.core.repository.{ } import org.hyperledger.identus.pollux.core.service.* import org.hyperledger.identus.pollux.vc.jwt.PrismDidResolver -import org.hyperledger.identus.shared.models.WalletId +import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} import zio.{Clock, Random, URLayer, ZIO, ZLayer} import zio.json.* import zio.json.ast.Json @@ -25,6 +26,8 @@ import zio.mock.MockSpecDefault import zio.test.* import zio.test.Assertion.* +import java.net.URI +import java.time.Instant import java.util.UUID import scala.util.Try @@ -34,11 +37,11 @@ object OIDCCredentialIssuerServiceSpec with Openid4VCIProofJwtOps { val layers: URLayer[ - DIDService & ManagedDIDService & DIDNonSecretStorage, + DIDService & ManagedDIDService & DIDNonSecretStorage & OID4VCIIssuerMetadataService, CredentialService & CredentialDefinitionService & OIDCCredentialIssuerService ] = ZLayer.makeSome[ - DIDService & ManagedDIDService & DIDNonSecretStorage, + DIDService & ManagedDIDService & DIDNonSecretStorage & OID4VCIIssuerMetadataService, CredentialService & CredentialDefinitionService & OIDCCredentialIssuerService ]( InMemoryIssuanceSessionService.layer, @@ -54,11 +57,11 @@ object OIDCCredentialIssuerServiceSpec ) override def spec = suite("CredentialServiceImpl")( - OIDCCredentialIssuerServiceSpec, + oid4vciCredentialIssuerServiceSpec, validateProofSpec ) - private val (issuerOp, issuerKp, issuerDidMetadata, issuerDidData) = + private val (_, issuerKp, issuerDidMetadata, issuerDidData) = MockDIDService.createDID(VerificationRelationship.AssertionMethod) private val (holderOp, holderKp, holderDidMetadata, holderDidData) = @@ -67,27 +70,27 @@ object OIDCCredentialIssuerServiceSpec private val holderDidServiceExpectations = MockDIDService.resolveDIDExpectation(holderDidMetadata, holderDidData) - private val holderManagedDIDServiceExpectations = - MockManagedDIDService.javaKeyPairWithDIDExpectation(holderKp) - private val issuerDidServiceExpectations = MockDIDService.resolveDIDExpectation(issuerDidMetadata, issuerDidData) private val issuerManagedDIDServiceExpectations = MockManagedDIDService.javaKeyPairWithDIDExpectation(issuerKp) - private val getIssuerPrismDidWalletIdExpectation = + private val getIssuerPrismDidWalletIdExpectations = MockDIDNonSecretStorage.getPrismDidWalletIdExpectation(issuerDidData.id, WalletId.default) - private def buildJwtProof(nonce: String, aud: UUID, iat: Int) = { - import org.bouncycastle.util.encoders.Hex + private val getCredentialConfigurationExpectations = + MockOID4VCIIssuerMetadataService.getCredentialConfigurationByIdExpectations( + CredentialConfiguration( + configurationId = "DrivingLicense", + format = CredentialFormat.JWT, + schemaId = URI("resource:///vc-schema-example.json"), + createdAt = Instant.EPOCH + ) + ) + private def buildJwtProof(nonce: String, aud: UUID, iat: Int) = { val longFormDid = PrismDID.buildLongFormFromOperation(holderOp) - - val encodedKey = Hex.toHexString(holderKp.privateKey.getEncoded) - println(s"Private Key: $encodedKey") - println("Long Form DID: " + longFormDid.toString) - makeJwtProof(longFormDid, nonce, aud, iat, holderKp.privateKey) } @@ -101,15 +104,16 @@ object OIDCCredentialIssuerServiceSpec jwt = buildJwtProof(nonce, aud, iat) result <- credentialIssuer.verifyJwtProof(jwt) } yield assert(result)(equalTo(true)) - }.provideSomeLayer( - holderDidServiceExpectations.toLayer ++ - MockManagedDIDService.empty ++ - // holderManagedDIDServiceExpectations.toLayer ++ - MockDIDNonSecretStorage.empty >+> layers + }.provide( + holderDidServiceExpectations.toLayer, + MockManagedDIDService.empty, + MockDIDNonSecretStorage.empty, + MockOID4VCIIssuerMetadataService.empty, + layers ) ) - private val OIDCCredentialIssuerServiceSpec = + private val oid4vciCredentialIssuerServiceSpec = suite("Simple JWT credential issuance")( test("should issue a JWT credential") { for { @@ -143,10 +147,68 @@ object OIDCCredentialIssuerServiceSpec // assert(jwtObject.getHeader.getKeyID)(equalTo(issuerDidData.id.toString)) && //TODO: add key ID to the header assert(jwtObject.getHeader.getAlgorithm)(equalTo(JWSAlgorithm.ES256K)) && assert(name)(equalTo("Alice")) - }.provideSomeLayer( - issuerDidServiceExpectations.toLayer ++ - issuerManagedDIDServiceExpectations.toLayer ++ - getIssuerPrismDidWalletIdExpectation.toLayer >+> layers + }.provide( + issuerDidServiceExpectations.toLayer, + issuerManagedDIDServiceExpectations.toLayer, + getIssuerPrismDidWalletIdExpectations.toLayer, + MockOID4VCIIssuerMetadataService.empty, + layers + ), + test("create credential-offer with valid claims") { + val wac = ZLayer.succeed(WalletAccessContext(WalletId.random)) + val claims = Json( + "credentialSubject" -> Json.Obj( + "emailAddress" -> Json.Str("alice@example.com"), + "givenName" -> Json.Str("Alice"), + "familyName" -> Json.Str("Wonderland"), + "dateOfIssuance" -> Json.Str("2000-01-01T10:00:00Z"), + "drivingLicenseID" -> Json.Str("12345"), + "drivingClass" -> Json.Num(5), + ) + ) + for { + oidcCredentialIssuerService <- ZIO.service[OIDCCredentialIssuerService] + offer <- oidcCredentialIssuerService + .createCredentialOffer( + URI("http://example.com").toURL(), + UUID.randomUUID(), + "DrivingLicense", + issuerDidData.id, + claims, + ) + .provide(wac) + issuerState = offer.grants.get.authorization_code.issuer_state.get + session <- oidcCredentialIssuerService.getIssuanceSessionByIssuerState(issuerState) + } yield assert(session.claims)(equalTo(claims)) + }.provide( + MockDIDService.empty, + MockManagedDIDService.empty, + MockDIDNonSecretStorage.empty, + getCredentialConfigurationExpectations.toLayer, + layers + ), + test("reject credential-offer when created with invalid claims") { + val wac = ZLayer.succeed(WalletAccessContext(WalletId.random)) + val claims = Json("credentialSubject" -> Json.Obj("foo" -> Json.Str("bar"))) + for { + oidcCredentialIssuerService <- ZIO.service[OIDCCredentialIssuerService] + exit <- oidcCredentialIssuerService + .createCredentialOffer( + URI("http://example.com").toURL(), + UUID.randomUUID(), + "DrivingLicense", + issuerDidData.id, + claims, + ) + .provide(wac) + .exit + } yield assert(exit)(failsWithA[OIDCCredentialIssuerService.Errors.CredentialSchemaError]) + }.provide( + MockDIDService.empty, + MockManagedDIDService.empty, + MockDIDNonSecretStorage.empty, + getCredentialConfigurationExpectations.toLayer, + layers ) ) } diff --git a/examples/st-oid4vci/README.md b/examples/st-oid4vci/README.md index d12cac6eda..85b357d0a3 100644 --- a/examples/st-oid4vci/README.md +++ b/examples/st-oid4vci/README.md @@ -25,10 +25,9 @@ sbt docker:publishLocal ### 1. Spin up the agent stack with pre-configured Keycloak ```bash -docker-compose up --build +docker-compose up ``` -This builds a custom Keycloak image with OID4VCI plugin. The Keycloak UI is available at `http://localhost:9980` and the admin username is `admin` with password `admin`. ### 2. Run the issuance demo script diff --git a/examples/st-oid4vci/demo.py b/examples/st-oid4vci/demo.py index 760e7c6ebb..0a1b97121e 100755 --- a/examples/st-oid4vci/demo.py +++ b/examples/st-oid4vci/demo.py @@ -87,6 +87,7 @@ def prepare_issuer(): "type": "object", "properties": { "firstName": {"type": "string"}, + "degree": {"type": "string"}, "grade": {"type": "number"}, }, "required": ["firstName", "grade"], @@ -269,7 +270,7 @@ def holder_get_credential(credential_endpoint: str, token_response): # step 1: Issuer create CredentialOffer credential_offer_uri = issuer_create_credential_offer( - {"degree": "ChemicalEngineering", "gpa": "3.00"} + {"firstName": "Alice", "degree": "ChemicalEngineering", "grade": 3.2} ) # step 2: Issuer present QR code container CredentialOffer URI diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImpl.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImpl.scala index 8e53ba4982..7cff964e9a 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImpl.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImpl.scala @@ -6,12 +6,7 @@ import io.circe.Json import org.hyperledger.identus.agent.walletapi.model.{ManagedDIDState, PublicationState} import org.hyperledger.identus.agent.walletapi.service.ManagedDIDService import org.hyperledger.identus.agent.walletapi.storage.GenericSecretStorage -import org.hyperledger.identus.castor.core.model.did.{ - CanonicalPrismDID, - EllipticCurve, - PrismDID, - VerificationRelationship -} +import org.hyperledger.identus.castor.core.model.did.{CanonicalPrismDID, PrismDID, VerificationRelationship} import org.hyperledger.identus.castor.core.service.DIDService import org.hyperledger.identus.mercury.model.* import org.hyperledger.identus.mercury.protocol.issuecredential.* diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/MockOID4VCIIssuerMetadataService.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/MockOID4VCIIssuerMetadataService.scala new file mode 100644 index 0000000000..05e8fa9ce0 --- /dev/null +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/MockOID4VCIIssuerMetadataService.scala @@ -0,0 +1,79 @@ +package org.hyperledger.identus.pollux.core.service + +import org.hyperledger.identus.pollux.core.model.oid4vci.{CredentialConfiguration, CredentialIssuer} +import org.hyperledger.identus.pollux.core.model.CredentialFormat +import org.hyperledger.identus.shared.models.WalletAccessContext +import zio.* +import zio.mock.{Expectation, Mock, Proxy} +import zio.test.Assertion + +import java.net.URL +import java.util.UUID + +object MockOID4VCIIssuerMetadataService extends Mock[OID4VCIIssuerMetadataService] { + + import OID4VCIIssuerMetadataServiceError.* + + object GetCredentialConfigurationById + extends Effect[ + (UUID, String), + CredentialConfigurationNotFound, + CredentialConfiguration + ] + + override val compose: URLayer[mock.Proxy, OID4VCIIssuerMetadataService] = ZLayer { + ZIO.serviceWith[Proxy] { proxy => + new OID4VCIIssuerMetadataService { + override def getCredentialIssuer(issuerId: UUID): IO[IssuerIdNotFound, CredentialIssuer] = + ZIO.die(NotImplementedError()) + + override def createCredentialIssuer(issuer: CredentialIssuer): URIO[WalletAccessContext, CredentialIssuer] = + ZIO.die(NotImplementedError()) + + override def getCredentialIssuers: URIO[WalletAccessContext, Seq[CredentialIssuer]] = + ZIO.die(NotImplementedError()) + + override def updateCredentialIssuer( + issuerId: UUID, + authorizationServer: Option[URL] = None, + authorizationServerClientId: Option[String] = None, + authorizationServerClientSecret: Option[String] = None + ): ZIO[WalletAccessContext, IssuerIdNotFound, CredentialIssuer] = ZIO.die(NotImplementedError()) + + override def deleteCredentialIssuer(issuerId: UUID): ZIO[WalletAccessContext, IssuerIdNotFound, Unit] = + ZIO.die(NotImplementedError()) + + override def createCredentialConfiguration( + issuerId: UUID, + format: CredentialFormat, + configurationId: String, + schemaId: String + ): ZIO[WalletAccessContext, InvalidSchemaId | UnsupportedCredentialFormat, CredentialConfiguration] = + ZIO.die(NotImplementedError()) + + override def getCredentialConfigurations( + issuerId: UUID + ): IO[IssuerIdNotFound, Seq[CredentialConfiguration]] = ZIO.die(NotImplementedError()) + + override def getCredentialConfigurationById( + issuerId: UUID, + configurationId: String + ): ZIO[WalletAccessContext, CredentialConfigurationNotFound, CredentialConfiguration] = + proxy(GetCredentialConfigurationById, issuerId, configurationId) + + override def deleteCredentialConfiguration( + issuerId: UUID, + configurationId: String, + ): ZIO[WalletAccessContext, CredentialConfigurationNotFound, Unit] = ZIO.die(NotImplementedError()) + } + } + } + + def getCredentialConfigurationByIdExpectations( + configuration: CredentialConfiguration + ): Expectation[OID4VCIIssuerMetadataService] = + GetCredentialConfigurationById( + assertion = Assertion.anything, + result = Expectation.value(configuration) + ) +} diff --git a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/DidJWT.scala b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/DidJWT.scala index 731f56f4c0..d5d00d4eb8 100644 --- a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/DidJWT.scala +++ b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/DidJWT.scala @@ -1,18 +1,12 @@ package org.hyperledger.identus.pollux.vc.jwt import com.nimbusds.jose.{JOSEObjectType, JWSAlgorithm, JWSHeader} -import com.nimbusds.jose.crypto.{ECDSASigner, ECDSAVerifier, Ed25519Signer} +import com.nimbusds.jose.crypto.{ECDSASigner, Ed25519Signer} import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton import com.nimbusds.jose.jwk.{Curve, ECKey, OctetKeyPair} import com.nimbusds.jwt.{JWTClaimsSet, SignedJWT} import io.circe.* -import org.hyperledger.identus.shared.crypto.{ - Ed25519KeyPair, - Ed25519PrivateKey, - Ed25519PublicKey, - Secp256k1PrivateKey, - Secp256k1PublicKey -} +import org.hyperledger.identus.shared.crypto.{Ed25519KeyPair, Secp256k1PrivateKey} import zio.* import java.security.* diff --git a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerification.scala b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerification.scala index 9f4f5e1409..3e6fdb2a72 100644 --- a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerification.scala +++ b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerification.scala @@ -8,19 +8,14 @@ import com.nimbusds.jose.JWSVerifier import com.nimbusds.jwt.SignedJWT import io.circe import io.circe.generic.auto.* -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo -import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters -import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory -import org.hyperledger.identus.castor.core.model.did.PrismDID -import org.hyperledger.identus.castor.core.model.did.VerificationRelationship +import org.hyperledger.identus.castor.core.model.did.{PrismDID, VerificationRelationship} import org.hyperledger.identus.shared.crypto.Ed25519PublicKey import pdi.jwt.* import zio.* import zio.prelude.* -import java.security.{KeyFactory, PublicKey} import java.security.interfaces.{ECPublicKey, EdECPublicKey} -import java.security.spec.X509EncodedKeySpec +import java.security.PublicKey import scala.util.{Failure, Success, Try} object JWTVerification {