diff --git a/prism-agent/service/api/http/castor/parameters.yaml b/prism-agent/service/api/http/castor/parameters.yaml index 7394b4e22a..67d467c03e 100644 --- a/prism-agent/service/api/http/castor/parameters.yaml +++ b/prism-agent/service/api/http/castor/parameters.yaml @@ -9,3 +9,21 @@ components: schema: type: string example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff + resolutionAcceptOption: + in: header + name: Accept + require: false + description: | + Represents [accept resolution option](https://www.w3.org/TR/did-core/#did-resolution-options). + + For [DID resolution result](https://w3c-ccg.github.io/did-resolution/#did-resolution-result), `application/ld+json;profile="https://w3id.org/did-resolution"` can be used. + + For [DID document representation](https://www.w3.org/TR/did-core/#representations), `application/` can be used. + + Default to `application/ld+json;profile="https://w3id.org/did-resolution"` if not specified. + schema: + type: string + enum: + - application/did+ld+json + - application/ld+json;profile="https://w3id.org/did-resolution" + example: application/ld+json;profile="https://w3id.org/did-resolution" diff --git a/prism-agent/service/api/http/castor/schemas.yaml b/prism-agent/service/api/http/castor/schemas.yaml index e4086b5f4d..a1f5d65776 100644 --- a/prism-agent/service/api/http/castor/schemas.yaml +++ b/prism-agent/service/api/http/castor/schemas.yaml @@ -1,16 +1,5 @@ components: schemas: - DIDResponse: - type: object - required: - - did - - metadata - properties: - did: - $ref: "#/components/schemas/DID" - metadata: - $ref: "#/components/schemas/DIDDocumentMetadata" - DIDOperationResponse: type: object required: @@ -19,13 +8,35 @@ components: scheduledOperation: $ref: "#/components/schemas/DidOperationSubmission" - DID: + DIDResolutionResult: type: object - description: | - A Prism DID document data model capable of being transformed into W3C compliant representation. required: + - "@context" + - didDocumentMetadata + - didResolutionMetadata + properties: + "@context": + type: string + example: "https://w3id.org/did-resolution/v1" + didDocument: + $ref: "#/components/schemas/DIDDocument" + didDocumentMetadata: + $ref: "#/components/schemas/DIDDocumentMetadata" + didResolutionMetadata: + $ref: "#/components/schemas/DIDResolutionMetadata" + + DIDDocument: + type: object + description: A W3C compliant Prism DID document representation. + required: + - "@context" - id properties: + "@context": + type: array + items: + type: string + example: "https://www.w3.org/ns/did/v1" id: type: string description: | @@ -44,23 +55,23 @@ components: authentication: type: array items: - $ref: "#/components/schemas/VerificationMethodOrRef" + $ref: "#/components/schemas/VerificationMethodRef" assertionMethod: type: array items: - $ref: "#/components/schemas/VerificationMethodOrRef" + $ref: "#/components/schemas/VerificationMethodRef" keyAgreement: type: array items: - $ref: "#/components/schemas/VerificationMethodOrRef" + $ref: "#/components/schemas/VerificationMethodRef" capabilityInvocation: type: array items: - $ref: "#/components/schemas/VerificationMethodOrRef" + $ref: "#/components/schemas/VerificationMethodRef" capabilityDelegation: type: array items: - $ref: "#/components/schemas/VerificationMethodOrRef" + $ref: "#/components/schemas/VerificationMethodRef" service: type: array items: @@ -70,8 +81,6 @@ components: type: object description: | [DID document metadata](https://www.w3.org/TR/did-core/#did-document-metadata) - required: - - deactivated properties: deactivated: type: boolean @@ -85,6 +94,20 @@ components: If a DID in short form or has not been published, DID document metadata MUST NOT contain a `canonicalId` property. + DIDResolutionMetadata: + type: object + description: | + [DID resolution metadata](https://www.w3.org/TR/did-core/#did-resolution-metadata) + properties: + error: + type: string + description: Resolution error constant according to [DID spec registries](https://www.w3.org/TR/did-spec-registries/#error) + example: invalidDid + contentType: + type: string + description: The media type of the returned DID document + example: application/did+ld+json + VerificationMethod: type: object description: | @@ -108,28 +131,10 @@ components: publicKeyJwk: $ref: "#/components/schemas/PublicKeyJwk" - VerificationMethodOrRef: - type: object - description: | - An embedded verificationMethod as JSON or a referenced key as a URI. - Referenced key and embedded key are mutually exclusive. - If the type is EMBEDDED, `uri` field must be present. - Otherwise `verificationMethod` field must be present. - - required: - - type - properties: - type: - type: string - example: EMBEDDED - enum: - - EMBEDDED - - REFERENCED - uri: - type: string - example: did:prism:c7bd808e8e135236d7262ecf5e639b8f9d22bd886f59a4e6c909486846ca8319#key-1 - verificationMethod: - $ref: "#/components/schemas/VerificationMethod" + VerificationMethodRef: + type: string + description: A reference to a `verificationMethod` + example: did:prism:c7bd808e8e135236d7262ecf5e639b8f9d22bd886f59a4e6c909486846ca8319#key-1 CreateManagedDidRequest: type: object diff --git a/prism-agent/service/api/http/prism-agent-openapi-spec.yaml b/prism-agent/service/api/http/prism-agent-openapi-spec.yaml index bccb82ebf9..d64be073f9 100644 --- a/prism-agent/service/api/http/prism-agent-openapi-spec.yaml +++ b/prism-agent/service/api/http/prism-agent-openapi-spec.yaml @@ -43,26 +43,61 @@ paths: get: operationId: getDid tags: ["DID"] - summary: Resolve Prism DID + summary: Resolve Prism DID to a W3C representation description: | - Resolve Prism DID to a DID document data model. - The returned DID document is not the W3C DID document representation, but a DID document data model. - However, this data model is capable of being transformed into the W3C compliant representation. + Resolve Prism DID to a W3C DID document representation. + The response can be the [DID resolution result](https://w3c-ccg.github.io/did-resolution/#did-resolution-result) + or [DID document representation](https://www.w3.org/TR/did-core/#representations) depending on the `Accept` request header. + The response is implemented according to [resolver HTTP binding](https://w3c-ccg.github.io/did-resolution/#bindings-https) in the DID resolution spec. parameters: - $ref: "./castor/parameters.yaml#/components/parameters/didRefInPath" + - $ref: "./castor/parameters.yaml#/components/parameters/resolutionAcceptOption" responses: "200": - description: The DID document data model + description: The resolution result or W3C DID document representation content: - application/json: + application/ld+json;profile="https://w3id.org/did-resolution": + schema: + $ref: "./castor/schemas.yaml#/components/schemas/DIDResolutionResult" + application/did+ld+json: + schema: + $ref: "./castor/schemas.yaml#/components/schemas/DIDDocument" + "400": + description: Invalid input + content: + application/ld+json;profile="https://w3id.org/did-resolution": schema: - $ref: "./castor/schemas.yaml#/components/schemas/DIDResponse" + $ref: "./castor/schemas.yaml#/components/schemas/DIDResolutionResult" "404": - $ref: "./shared/responses.yaml#/components/responses/NotFound" - "422": - $ref: "./shared/responses.yaml#/components/responses/UnprocessableEntity" + description: Not found + content: + application/ld+json;profile="https://w3id.org/did-resolution": + schema: + $ref: "./castor/schemas.yaml#/components/schemas/DIDResolutionResult" + "406": + description: Representation not supported + content: + application/ld+json;profile="https://w3id.org/did-resolution": + schema: + $ref: "./castor/schemas.yaml#/components/schemas/DIDResolutionResult" + "410": + description: DID Deactivated + content: + application/ld+json;profile="https://w3id.org/did-resolution": + schema: + $ref: "./castor/schemas.yaml#/components/schemas/DIDResolutionResult" "500": - $ref: "./shared/responses.yaml#/components/responses/InternalServerError" + description: Internal error + content: + application/ld+json;profile="https://w3id.org/did-resolution": + schema: + $ref: "./castor/schemas.yaml#/components/schemas/DIDResolutionResult" + "501": + description: Method not supported + content: + application/ld+json;profile="https://w3id.org/did-resolution": + schema: + $ref: "./castor/schemas.yaml#/components/schemas/DIDResolutionResult" /did-registrar/dids: get: diff --git a/prism-agent/service/build.sbt b/prism-agent/service/build.sbt index e43e945b4d..0a9edc0cbe 100644 --- a/prism-agent/service/build.sbt +++ b/prism-agent/service/build.sbt @@ -48,8 +48,8 @@ lazy val server = project openApiGeneratorSpec := apiBaseDirectory.value / "http/prism-agent-openapi-spec.yaml", openApiGeneratorConfig := baseDirectory.value / "openapi/generator-config/config.yaml", openApiGeneratorImportMapping := Seq( - "DidOperationType", - "DidOperationStatus" + "DIDDocument", + "DIDResolutionResult" ) .map(model => (model, s"io.iohk.atala.agent.server.http.model.OASModelPatches.$model") diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/DIDApiMarshallerImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/DIDApiMarshallerImpl.scala index 9c4fc561c0..632b91df43 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/DIDApiMarshallerImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/DIDApiMarshallerImpl.scala @@ -3,18 +3,17 @@ package io.iohk.atala.agent.server.http.marshaller import akka.http.scaladsl.marshalling.ToEntityMarshaller import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller import io.iohk.atala.agent.openapi.api.DIDApiMarshaller -import io.iohk.atala.agent.openapi.model.{DIDOperationResponse, DIDResponse, ErrorResponse} +import io.iohk.atala.agent.openapi.model.{DIDOperationResponse, ErrorResponse} import spray.json.RootJsonFormat import zio.* +import io.iohk.atala.agent.server.http.model.OASModelPatches object DIDApiMarshallerImpl extends JsonSupport { val layer: ULayer[DIDApiMarshaller] = ZLayer.succeed { new DIDApiMarshaller { - implicit def toEntityMarshallerDIDResponse: ToEntityMarshaller[DIDResponse] = summon[RootJsonFormat[DIDResponse]] - - implicit def toEntityMarshallerErrorResponse: ToEntityMarshaller[ErrorResponse] = - summon[RootJsonFormat[ErrorResponse]] + implicit def toEntityMarshallerDIDResolutionResult: ToEntityMarshaller[OASModelPatches.DIDResolutionResult] = + summon[RootJsonFormat[OASModelPatches.DIDResolutionResult]] } } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/JsonSupport.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/JsonSupport.scala index 3afed1c0c0..5e43dc3a21 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/JsonSupport.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/JsonSupport.scala @@ -15,6 +15,9 @@ import spray.json.{ import java.util.UUID import java.time.OffsetDateTime +import io.iohk.atala.agent.server.http.model.OASModelPatches + +object JsonSupport extends JsonSupport trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol { @@ -24,11 +27,10 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol { CreateManagedDidRequestDocumentTemplate.apply ) given RootJsonFormat[CreateManagedDIDResponse] = jsonFormat1(CreateManagedDIDResponse.apply) - given RootJsonFormat[DID] = jsonFormat9(DID.apply) given RootJsonFormat[DIDDocumentMetadata] = jsonFormat2(DIDDocumentMetadata.apply) given RootJsonFormat[DIDOperationResponse] = jsonFormat1(DIDOperationResponse.apply) given RootJsonFormat[DidOperationSubmission] = jsonFormat2(DidOperationSubmission.apply) - given RootJsonFormat[DIDResponse] = jsonFormat2(DIDResponse.apply) + given RootJsonFormat[DIDResolutionMetadata] = jsonFormat2(DIDResolutionMetadata.apply) given RootJsonFormat[ErrorResponse] = jsonFormat5(ErrorResponse.apply) given RootJsonFormat[ManagedDID] = jsonFormat3(ManagedDID.apply) given RootJsonFormat[ManagedDIDPage] = jsonFormat6(ManagedDIDPage.apply) @@ -47,7 +49,6 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol { UpdateManagedDIDRequestActionsInnerUpdateService.apply ) given RootJsonFormat[VerificationMethod] = jsonFormat4(VerificationMethod.apply) - given RootJsonFormat[VerificationMethodOrRef] = jsonFormat3(VerificationMethodOrRef.apply) // Issue Credential Protocol implicit object UUIDFormat extends JsonFormat[UUID] { @@ -90,4 +91,8 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol { given RootJsonFormat[Connection] = jsonFormat11(Connection.apply) given RootJsonFormat[ConnectionInvitation] = jsonFormat4(ConnectionInvitation.apply) + // Manual model patches + given RootJsonFormat[OASModelPatches.DIDDocument] = jsonFormat10(OASModelPatches.DIDDocument.apply) + given RootJsonFormat[OASModelPatches.DIDResolutionResult] = jsonFormat4(OASModelPatches.DIDResolutionResult.apply) + } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/CustomMediaTypes.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/CustomMediaTypes.scala new file mode 100644 index 0000000000..722f2a17eb --- /dev/null +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/CustomMediaTypes.scala @@ -0,0 +1,18 @@ +package io.iohk.atala.agent.server.http.model + +import akka.http.scaladsl.model.MediaType +import akka.http.scaladsl.model.HttpCharsets + +object CustomMediaTypes { + + val `application/did+ld+json`: MediaType.WithFixedCharset = + MediaType.customWithFixedCharset("application", "did+ld+json", HttpCharsets.`UTF-8`) + + val `application/ld+json;did-resolution`: MediaType.WithFixedCharset = MediaType.customWithFixedCharset( + "application", + "ld+json", + HttpCharsets.`UTF-8`, + params = Map("profile" -> "https://w3id.org/did-resolution") + ) + +} diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASDomainModelHelper.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASDomainModelHelper.scala index 1fc808c7af..58e376347b 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASDomainModelHelper.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASDomainModelHelper.scala @@ -224,23 +224,43 @@ trait OASDomainModelHelper { } extension (resolution: (castorDomain.w3c.DIDDocumentMetadataRepr, castorDomain.w3c.DIDDocumentRepr)) { - def toOAS: DIDResponse = { + def toOAS: OASModelPatches.DIDResolutionResult = { val (metadata, didDoc) = resolution - DIDResponse( - did = DID( - id = didDoc.id, - controller = Some(didDoc.controller), - verificationMethod = Some(didDoc.verificationMethod.map(_.toOAS)), - authentication = Some(didDoc.authentication.map(_.toOAS)), - assertionMethod = Some(didDoc.assertionMethod.map(_.toOAS)), - keyAgreement = Some(didDoc.keyAgreement.map(_.toOAS)), - capabilityInvocation = Some(didDoc.capabilityInvocation.map(_.toOAS)), - service = Some(didDoc.service.map(_.toOAS)) - ), - metadata = DIDDocumentMetadata( - deactivated = metadata.deactivated, + val isDeactivated = metadata.deactivated + OASModelPatches.DIDResolutionResult( + `@context` = "https://w3id.org/did-resolution/v1", + didDocument = + if (isDeactivated) None + else + Some( + OASModelPatches.DIDDocument( + `@context` = Seq("https://www.w3.org/ns/did/v1"), + id = didDoc.id, + controller = Some(didDoc.controller), + verificationMethod = Some(didDoc.verificationMethod.map(_.toOAS)), + authentication = Some(didDoc.authentication.map(_.toOAS)), + assertionMethod = Some(didDoc.assertionMethod.map(_.toOAS)), + keyAgreement = Some(didDoc.keyAgreement.map(_.toOAS)), + capabilityInvocation = Some(didDoc.capabilityInvocation.map(_.toOAS)), + service = Some(didDoc.service.map(_.toOAS)) + ) + ), + didDocumentMetadata = DIDDocumentMetadata( + deactivated = Some(metadata.deactivated), canonicalId = Some(metadata.canonicalId) - ) + ), + didResolutionMetadata = DIDResolutionMetadata() + ) + } + } + + extension (resolutionError: castorDomain.w3c.DIDResolutionErrorRepr) { + def toOAS: OASModelPatches.DIDResolutionResult = { + OASModelPatches.DIDResolutionResult( + `@context` = "https://w3id.org/did-resolution/v1", + didDocument = None, + didDocumentMetadata = DIDDocumentMetadata(), + didResolutionMetadata = DIDResolutionMetadata(error = Some(resolutionError.value)) ) } } @@ -257,10 +277,10 @@ trait OASDomainModelHelper { } extension (publicKeyReprOrRef: castorDomain.w3c.PublicKeyReprOrRef) { - def toOAS: VerificationMethodOrRef = { + def toOAS: String = { publicKeyReprOrRef match { - case s: String => VerificationMethodOrRef(`type` = "REFERENCED", uri = Some(s)) - case pk: PublicKeyRepr => VerificationMethodOrRef(`type` = "EMBEDDED", verificationMethod = Some(pk.toOAS)) + case s: String => s + case pk: PublicKeyRepr => throw Exception("Embedded public key is not yet supported in W3C representation") } } } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASModelPatches.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASModelPatches.scala index 7938db7677..9a498f777f 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASModelPatches.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASModelPatches.scala @@ -1,6 +1,31 @@ package io.iohk.atala.agent.server.http.model +import io.iohk.atala.agent.openapi.model.{Service, VerificationMethod, DIDDocumentMetadata, DIDResolutionMetadata} + +// Use for overriding models when OpenAPI generator cannot correctly generate models +// The config to patch the generated models is in build.sbt object OASModelPatches { - type DidOperationType = String - type DidOperationStatus = String + + // Need this because the OAS generator cannot generate a case class with a field named '@context' + final case class DIDDocument( + `@context`: Seq[String], + id: String, + controller: Option[String] = None, + verificationMethod: Option[Seq[VerificationMethod]] = None, + authentication: Option[Seq[String]] = None, + assertionMethod: Option[Seq[String]] = None, + keyAgreement: Option[Seq[String]] = None, + capabilityInvocation: Option[Seq[String]] = None, + capabilityDelegation: Option[Seq[String]] = None, + service: Option[Seq[Service]] = None + ) + + // Need this because the OAS generator cannot generate a case class with a field named '@context' + final case class DIDResolutionResult( + `@context`: String, + didDocument: Option[DIDDocument] = None, + didDocumentMetadata: DIDDocumentMetadata, + didResolutionMetadata: DIDResolutionMetadata + ) + } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/DIDApiServiceImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/DIDApiServiceImpl.scala index baec4de6aa..a68afdd19c 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/DIDApiServiceImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/DIDApiServiceImpl.scala @@ -12,6 +12,10 @@ import io.iohk.atala.agent.openapi.model.* import io.iohk.atala.agent.server.http.model.{HttpServiceError, OASDomainModelHelper, OASErrorModelHelper} import io.iohk.atala.castor.core.model.error.DIDOperationError import zio.* +import io.iohk.atala.agent.server.http.model.{OASModelPatches, CustomMediaTypes} +import io.iohk.atala.castor.core.model.did.w3c.DIDResolutionErrorRepr +import spray.json.{CompactPrinter, JsonWriter, RootJsonFormat} +import akka.http.scaladsl.marshalling.Marshaller class DIDApiServiceImpl(service: DIDService)(using runtime: Runtime[Any]) extends DIDApiService, @@ -19,17 +23,61 @@ class DIDApiServiceImpl(service: DIDService)(using runtime: Runtime[Any]) OASDomainModelHelper, OASErrorModelHelper { - override def getDid(didRef: String)(implicit - toEntityMarshallerDIDResponse: ToEntityMarshaller[DIDResponse], - toEntityMarshallerErrorResponse: ToEntityMarshaller[ErrorResponse] + override def getDid(didRef: String, accept: Option[String])(implicit + toEntityMarshallerDIDResolutionResult: ToEntityMarshaller[OASModelPatches.DIDResolutionResult] ): Route = { - val result = makeW3CResolver(service)(didRef).mapError(HttpServiceError.DomainError.apply) - onZioSuccess(result.mapBoth(_.toOAS, _.toOAS).either) { - case Left(error) => complete(error.status -> error) - case Right(response) => getDid200(response) - } + val result = for { + result <- makeW3CResolver(service)(didRef).either + resolutionResult = result.fold(_.toOAS, _.toOAS) + resolutionError = result.swap.toOption + } yield buildHttpBindingResponse(resolutionResult, resolutionError) + + onZioSuccess(result)(identity) } + // Return response dynamically based on "Content-Type" negotiation + // according to https://w3c-ccg.github.io/did-resolution/#bindings-https + private def buildHttpBindingResponse( + resolutionResult: OASModelPatches.DIDResolutionResult, + resolutionError: Option[DIDResolutionErrorRepr] + ): Route = { + import io.iohk.atala.agent.server.http.marshaller.JsonSupport.{optionFormat, given} + import DIDResolutionErrorRepr.* + + val jsonLdMarshaller: ToEntityMarshaller[OASModelPatches.DIDResolutionResult] = { + val writer = optionFormat[OASModelPatches.DIDDocument] + Marshaller.StringMarshaller + .wrap(CustomMediaTypes.`application/did+ld+json`)(CompactPrinter) + .compose(writer.write) + .compose(_.didDocument) + } + val resolutionResultMarshaller: ToEntityMarshaller[OASModelPatches.DIDResolutionResult] = { + val writer = summon[RootJsonFormat[OASModelPatches.DIDResolutionResult]] + Marshaller.StringMarshaller + .wrap(CustomMediaTypes.`application/ld+json;did-resolution`)(CompactPrinter) + .compose(writer.write) + .compose { result => + result.copy(didResolutionMetadata = + result.didResolutionMetadata.copy(contentType = Some(CustomMediaTypes.`application/did+ld+json`.value)) + ) + } + } + + given ToEntityMarshaller[OASModelPatches.DIDResolutionResult] = + Marshaller.oneOf(resolutionResultMarshaller, jsonLdMarshaller) + + val isDeactivated = resolutionResult.didDocumentMetadata.deactivated.getOrElse(false) + resolutionError match { + case None if !isDeactivated => complete(200 -> resolutionResult) + case None => complete(410 -> resolutionResult) + case Some(InvalidDID) => complete(400 -> resolutionResult) + case Some(InvalidDIDUrl) => complete(400 -> resolutionResult) + case Some(NotFound) => complete(404 -> resolutionResult) + case Some(RepresentationNotSupported) => complete(406 -> resolutionResult) + case Some(InternalError) => complete(500 -> resolutionResult) + case Some(_) => complete(500 -> resolutionResult) + } + } } object DIDApiServiceImpl { diff --git a/tests/e2e-tests/src/main/kotlin/api_models/DidDocument.kt b/tests/e2e-tests/src/main/kotlin/api_models/DidResolutionResult.kt similarity index 56% rename from tests/e2e-tests/src/main/kotlin/api_models/DidDocument.kt rename to tests/e2e-tests/src/main/kotlin/api_models/DidResolutionResult.kt index e9f462b026..f7dd2182d2 100644 --- a/tests/e2e-tests/src/main/kotlin/api_models/DidDocument.kt +++ b/tests/e2e-tests/src/main/kotlin/api_models/DidResolutionResult.kt @@ -1,29 +1,33 @@ package api_models -data class DidDocument( - var did: W3cCompatibleDid? = null, - var metadata: DidDocumentMetadata? = null, +data class DidResolutionResult( + var `@context`: String? = null, + var didDocument: DidDocument? = null, + var didDocumentMetadata: DidDocumentMetadata? = null, + var didResolutionMetadata: DidResolutionMetadata? = null, ) -data class W3cCompatibleDid( - var assertionMethod: List? = null, - var authentication: List? = null, +data class DidDocument( + var `@context`: List? = null, + var assertionMethod: List? = null, + var authentication: List? = null, var capabilityInvocation: List? = null, var controller: String? = null, var id: String? = null, var keyAgreement: List? = null, var service: List? = null, - var verificationMethod: List? = null, + var verificationMethod: List? = null, ) -data class DidDocumentAuthentication( +data class VerificationMethod( var controller: String? = null, var id: String? = null, var publicKeyJwk: PublicKeyJwk? = null, var type: String? = null, - var uri: String? = null, ) +typealias VerificationMethodRef = String + data class PublicKeyJwk( var crv: String? = null, var kty: String? = null, @@ -41,3 +45,7 @@ data class DidDocumentService( var serviceEndpoint: List? = null, var type: String? = null, ) + +data class DidResolutionMetadata( + var contentType: String? = null, +) diff --git a/tests/e2e-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt b/tests/e2e-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt index 02d668b025..e2865a3ea9 100644 --- a/tests/e2e-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt +++ b/tests/e2e-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt @@ -35,7 +35,7 @@ class DeactivateDidSteps { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) - lastResponseObject("metadata.deactivated", String::class) == "true" + lastResponseObject("didDocumentMetadata.deactivated", String::class) == "true" }, "ERROR: DID deactivate operation did not succeed on the ledger!", timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, diff --git a/tests/e2e-tests/src/test/kotlin/features/did/PublishDidSteps.kt b/tests/e2e-tests/src/test/kotlin/features/did/PublishDidSteps.kt index 629bb44fa5..450aed7104 100644 --- a/tests/e2e-tests/src/test/kotlin/features/did/PublishDidSteps.kt +++ b/tests/e2e-tests/src/test/kotlin/features/did/PublishDidSteps.kt @@ -36,7 +36,7 @@ class PublishDidSteps { actor.attemptsTo( Get.resource("/dids/${it.did}"), ) - lastResponseObject("metadata.deactivated", String::class) == "false" + lastResponseObject("didDocumentMetadata.deactivated", String::class) == "false" } if (did == null) { createsUnpublishedDid(actor) @@ -112,14 +112,14 @@ class PublishDidSteps { actor.should( ResponseConsequence.seeThatResponse { it.statusCode(SC_OK) - it.body("did.id", equalTo(actor.recall("shortFormDid"))) + it.body("didDocument.id", equalTo(actor.recall("shortFormDid"))) }, ) } @Then("{actor} resolves DID document corresponds to W3C standard") fun heSeesDidDocumentCorrespondsToW3cStandard(actor: Actor) { - val didDocument = lastResponseObject("", DidDocument::class).did!! + val didDocument = lastResponseObject("", DidResolutionResult::class).didDocument!! assertThat(didDocument) .hasFieldOrProperty("assertionMethod") .hasFieldOrProperty("authentication") @@ -135,15 +135,14 @@ class PublishDidSteps { assertThat(didDocument.id == shortFormDid) assertThat(didDocument.authentication!![0]) - .hasFieldOrPropertyWithValue("type", "REFERENCED") - .hasFieldOrPropertyWithValue("uri", "$shortFormDid#${TestConstants.PRISM_DID_AUTH_KEY.id}") + .isEqualTo("$shortFormDid#${TestConstants.PRISM_DID_AUTH_KEY.id}") assertThat(didDocument.verificationMethod!![0]) .hasFieldOrPropertyWithValue("controller", shortFormDid) .hasFieldOrPropertyWithValue("id", "$shortFormDid#${TestConstants.PRISM_DID_ASSERTION_KEY.id}") .hasFieldOrProperty("publicKeyJwk") - assertThat(lastResponseObject("", DidDocument::class).metadata!!) + assertThat(lastResponseObject("", DidResolutionResult::class).didDocumentMetadata!!) .hasFieldOrPropertyWithValue("deactivated", false) .hasFieldOrProperty("canonicalId") } diff --git a/tests/e2e-tests/src/test/kotlin/features/did/UpdateDidSteps.kt b/tests/e2e-tests/src/test/kotlin/features/did/UpdateDidSteps.kt index d06e51f2de..aada98bf8c 100644 --- a/tests/e2e-tests/src/test/kotlin/features/did/UpdateDidSteps.kt +++ b/tests/e2e-tests/src/test/kotlin/features/did/UpdateDidSteps.kt @@ -92,8 +92,8 @@ class UpdateDidSteps { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) - val authUris = lastResponseList("did.authentication.uri", String::class) - val verificationMethods = lastResponseList("did.verificationMethod.id", String::class) + val authUris = lastResponseList("didDocument.authentication", String::class) + val verificationMethods = lastResponseList("didDocument.verificationMethod.id", String::class) authUris.any { it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_AUTH_KEY.id}" } && verificationMethods.any { @@ -112,8 +112,8 @@ class UpdateDidSteps { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) - val authUris = lastResponseList("did.authentication.uri", String::class) - val verificationMethods = lastResponseList("did.verificationMethod.id", String::class) + val authUris = lastResponseList("didDocument.authentication", String::class) + val verificationMethods = lastResponseList("didDocument.verificationMethod.id", String::class) authUris.none { it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" } && verificationMethods.none { @@ -132,7 +132,7 @@ class UpdateDidSteps { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) - val serviceIds = lastResponseList("did.service.id", String::class) + val serviceIds = lastResponseList("didDocument.service.id", String::class) serviceIds.any { it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" } @@ -149,7 +149,7 @@ class UpdateDidSteps { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) - val serviceIds = lastResponseList("did.service.id", String::class) + val serviceIds = lastResponseList("didDocument.service.id", String::class) serviceIds.none { it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" } @@ -166,7 +166,7 @@ class UpdateDidSteps { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) - val service = lastResponseList("did.service", Service::class) + val service = lastResponseList("didDocument.service", Service::class) service.any { it.serviceEndpoint.contains(TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL) } }, "ERROR: DID UPDATE operation did not succeed on the ledger!",