From 9b83bbf0ba23a441de3fc52fb40957358f9d052a Mon Sep 17 00:00:00 2001 From: Allain Magyar Date: Wed, 26 Jun 2024 01:33:01 -0300 Subject: [PATCH] test: refactor DIDs Signed-off-by: Allain Magyar --- .../src/test/kotlin/common/DidPurpose.kt | 25 +++ .../src/test/kotlin/common/TestConstants.kt | 12 -- .../test/kotlin/steps/common/CommonSteps.kt | 45 ++---- .../kotlin/steps/common/ParameterSteps.kt | 29 ++++ .../test/kotlin/steps/did/ManageDidSteps.kt | 6 +- .../test/kotlin/steps/did/PublishDidSteps.kt | 90 +++++------ .../test/kotlin/steps/did/UpdateDidSteps.kt | 142 ++++++++++-------- .../issue_anoncred_with_published_did.feature | 15 ++ ...e => issue_jwt_with_published_did.feature} | 6 +- ...=> issue_jwt_with_unpublished_did.feature} | 6 +- .../resources/features/did/create_did.feature | 46 +++--- .../resources/features/did/update_did.feature | 40 ++--- .../features/proofs/present_proof.feature | 6 +- .../proofs/present_proof_anoncred.feature | 4 +- .../revocation/revoke_jwt_credential.feature | 2 +- .../schemas/credential_schemas.feature | 2 +- .../verificationapi/vc_verification.feature | 23 ++- 17 files changed, 277 insertions(+), 222 deletions(-) create mode 100644 tests/integration-tests/src/test/kotlin/common/DidPurpose.kt create mode 100644 tests/integration-tests/src/test/kotlin/steps/common/ParameterSteps.kt create mode 100644 tests/integration-tests/src/test/resources/features/credentials/issue_anoncred_with_published_did.feature rename tests/integration-tests/src/test/resources/features/credentials/{issue_published_did.feature => issue_jwt_with_published_did.feature} (90%) rename tests/integration-tests/src/test/resources/features/credentials/{issue_unpublished_did.feature => issue_jwt_with_unpublished_did.feature} (73%) diff --git a/tests/integration-tests/src/test/kotlin/common/DidPurpose.kt b/tests/integration-tests/src/test/kotlin/common/DidPurpose.kt new file mode 100644 index 0000000000..0d343dbc37 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/DidPurpose.kt @@ -0,0 +1,25 @@ +package common + +import org.hyperledger.identus.client.models.* + +enum class DidPurpose { + EMPTY { + override val publicKeys = emptyList() + override val services = emptyList() + }, + JWT { + override val publicKeys = listOf( + ManagedDIDKeyTemplate("auth-1", Purpose.AUTHENTICATION, Curve.SECP256K1), + ManagedDIDKeyTemplate("auth-2", Purpose.AUTHENTICATION, Curve.ED25519), + ManagedDIDKeyTemplate("assertion-1", Purpose.ASSERTION_METHOD, Curve.SECP256K1), + ) + override val services = emptyList() + }, + ANONCRED { + override val publicKeys = emptyList() + override val services = emptyList() + }; + + abstract val publicKeys: List + abstract val services: List +} diff --git a/tests/integration-tests/src/test/kotlin/common/TestConstants.kt b/tests/integration-tests/src/test/kotlin/common/TestConstants.kt index 56a81a0a73..15fed21943 100644 --- a/tests/integration-tests/src/test/kotlin/common/TestConstants.kt +++ b/tests/integration-tests/src/test/kotlin/common/TestConstants.kt @@ -18,18 +18,6 @@ object TestConstants { ), ) - val PRISM_DID_AUTH_KEY = ManagedDIDKeyTemplate("auth-1", Purpose.AUTHENTICATION) - val PRISM_DID_SERVICE_FOR_UPDATE = Service( - "https://update.com", - listOf("LinkedDomains"), - Json("https://update.com/"), - ) - val PRISM_DID_UPDATE_NEW_SERVICE_URL = "https://bar.foo.com/" - val PRISM_DID_UPDATE_NEW_SERVICE = Service( - "https://new.service.com", - listOf("LinkedDomains"), - Json("https://new.service.com/"), - ) val EVENT_TYPE_CONNECTION_UPDATED = "ConnectionUpdated" val EVENT_TYPE_ISSUE_CREDENTIAL_RECORD_UPDATED = "IssueCredentialRecordUpdated" val EVENT_TYPE_PRESENTATION_UPDATED = "PresentationUpdated" diff --git a/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt b/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt index aa7a327911..327fc8757f 100644 --- a/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt @@ -1,50 +1,29 @@ package steps.common import common.CredentialSchema +import common.DidPurpose import interactions.Get -import io.cucumber.java.DataTableType -import io.cucumber.java.ParameterType import io.cucumber.java.en.Given import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import net.serenitybdd.screenplay.actors.OnStage import org.apache.http.HttpStatus -import org.hyperledger.identus.client.models.* +import org.hyperledger.identus.client.models.Connection +import org.hyperledger.identus.client.models.ConnectionsPage import steps.connection.ConnectionSteps import steps.credentials.IssueCredentialsSteps import steps.did.PublishDidSteps import steps.schemas.CredentialSchemasSteps class CommonSteps { - @ParameterType(".*") - fun actor(actorName: String): Actor { - return OnStage.theActorCalled(actorName) - } - - @ParameterType(".*") - fun curve(value: String): Curve { - return Curve.decode(value) ?: throw IllegalArgumentException("$value is not a valid Curve value") - } - - @ParameterType(".*") - fun purpose(value: String): Purpose { - return Purpose.decode(value) ?: throw IllegalArgumentException("$value is not a valid Purpose value") - } - - @DataTableType - fun vcVerification(cell: String): VcVerification { - return VcVerification.valueOf(cell) - } - - @Given("{actor} has an issued credential from {actor}") + @Given("{actor} has a jwt issued credential from {actor}") fun holderHasIssuedCredentialFromIssuer(holder: Actor, issuer: Actor) { actorsHaveExistingConnection(issuer, holder) val publishDidSteps = PublishDidSteps() - publishDidSteps.createsUnpublishedDid(holder) - publishDidSteps.agentHasAPublishedDID(issuer) + publishDidSteps.agentHasAnUnpublishedDID(holder, DidPurpose.JWT) + publishDidSteps.agentHasAPublishedDID(issuer, DidPurpose.JWT) val issueSteps = IssueCredentialsSteps() issueSteps.issuerOffersACredential(issuer, holder, "short") @@ -54,13 +33,17 @@ class CommonSteps { issueSteps.bobHasTheCredentialIssued(holder) } - @Given("{actor} has an issued credential with {} schema from {actor}") - fun holderHasIssuedCredentialFromIssuerWithSchema(holder: Actor, schema: CredentialSchema, issuer: Actor) { + @Given("{actor} has a jwt issued credential with {} schema from {actor}") + fun holderHasIssuedCredentialFromIssuerWithSchema( + holder: Actor, + schema: CredentialSchema, + issuer: Actor + ) { actorsHaveExistingConnection(issuer, holder) val publishDidSteps = PublishDidSteps() - publishDidSteps.createsUnpublishedDid(holder) - publishDidSteps.agentHasAPublishedDID(issuer) + publishDidSteps.agentHasAnUnpublishedDID(holder, DidPurpose.JWT) + publishDidSteps.agentHasAPublishedDID(issuer, DidPurpose.JWT) val schemaSteps = CredentialSchemasSteps() schemaSteps.agentHasAPublishedSchema(issuer, schema) diff --git a/tests/integration-tests/src/test/kotlin/steps/common/ParameterSteps.kt b/tests/integration-tests/src/test/kotlin/steps/common/ParameterSteps.kt new file mode 100644 index 0000000000..d580395788 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/steps/common/ParameterSteps.kt @@ -0,0 +1,29 @@ +package steps.common + +import io.cucumber.java.DataTableType +import io.cucumber.java.ParameterType +import net.serenitybdd.screenplay.Actor +import net.serenitybdd.screenplay.actors.OnStage +import org.hyperledger.identus.client.models.* + +class ParameterSteps { + @ParameterType(".*") + fun actor(actorName: String): Actor { + return OnStage.theActorCalled(actorName) + } + + @ParameterType(".*") + fun curve(value: String): Curve { + return Curve.decode(value) ?: throw IllegalArgumentException("$value is not a valid Curve value") + } + + @ParameterType(".*") + fun purpose(value: String): Purpose { + return Purpose.decode(value) ?: throw IllegalArgumentException("$value is not a valid Purpose value") + } + + @DataTableType + fun vcVerification(cell: String): VcVerification { + return VcVerification.valueOf(cell) + } +} diff --git a/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt index b77cf8fe74..bd9702383e 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt @@ -1,5 +1,6 @@ package steps.did +import common.body import interactions.Get import interactions.Post import io.cucumber.java.en.* @@ -31,10 +32,7 @@ class ManageDidSteps { val createDidRequest = createPrismDidRequest(curve, purpose) actor.attemptsTo( - Post.to("/did-registrar/dids") - .with { - it.body(createDidRequest) - }, + Post.to("/did-registrar/dids").body(createDidRequest) ) if (SerenityRest.lastResponse().statusCode() == SC_CREATED) { diff --git a/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt index 9a02b62b1a..878a36e8ea 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt @@ -1,7 +1,8 @@ package steps.did import abilities.ListenToEvents -import common.TestConstants +import common.DidPurpose +import common.body import interactions.Get import interactions.Post import io.cucumber.java.en.* @@ -17,28 +18,44 @@ import org.hyperledger.identus.client.models.* import kotlin.time.Duration.Companion.seconds class PublishDidSteps { + + @Given("{actor} has a published DID for {}") + fun agentHasAPublishedDID(agent: Actor, didPurpose: DidPurpose) { + if (agent.recallAll().containsKey("hasPublishedDid") && actualDidHasSamePurpose(agent, didPurpose)) { + return + } + agentHasAnUnpublishedDID(agent, didPurpose) + hePublishesDidToLedger(agent) + } + + @Given("{actor} has an unpublished DID for {}") + fun agentHasAnUnpublishedDID(agent: Actor, didPurpose: DidPurpose) { + if (agent.recallAll().containsKey("shortFormDid") || agent.recallAll().containsKey("longFormDid")) { + // is not published and has the same purpose + if (!agent.recallAll().containsKey("hasPublishedDid") && actualDidHasSamePurpose(agent, didPurpose)) { + return + } + } + agentCreatesUnpublishedDid(agent, didPurpose) + } + + private fun actualDidHasSamePurpose(agent: Actor, didPurpose: DidPurpose): Boolean { + val actualPurpose: DidPurpose = agent.recall("didPurpose") ?: return false + return actualPurpose == didPurpose + } + @Given("{actor} creates unpublished DID") - fun createsUnpublishedDid(actor: Actor) { + fun agentCreatesEmptyUnpublishedDid(actor: Actor) { + agentCreatesUnpublishedDid(actor, DidPurpose.EMPTY) + } + + @Given("{actor} creates unpublished DID for {}") + fun agentCreatesUnpublishedDid(actor: Actor, didPurpose: DidPurpose) { val createDidRequest = CreateManagedDidRequest( - CreateManagedDidRequestDocumentTemplate( - publicKeys = listOf( - ManagedDIDKeyTemplate("auth-1", Purpose.AUTHENTICATION, Curve.SECP256K1), - ManagedDIDKeyTemplate("auth-2", Purpose.AUTHENTICATION, Curve.ED25519), - ManagedDIDKeyTemplate("assertion-1", Purpose.ASSERTION_METHOD, Curve.SECP256K1), - ManagedDIDKeyTemplate("comm-1", Purpose.KEY_AGREEMENT, Curve.X25519), - ), - services = listOf( - Service("https://foo.bar.com", listOf("LinkedDomains"), Json("https://foo.bar.com/")), - Service("https://update.com", listOf("LinkedDomains"), Json("https://update.com/")), - Service("https://remove.com", listOf("LinkedDomains"), Json("https://remove.com/")), - ), - ), + CreateManagedDidRequestDocumentTemplate(didPurpose.publicKeys, services = didPurpose.services), ) actor.attemptsTo( - Post.to("/did-registrar/dids") - .with { - it.body(createDidRequest) - }, + Post.to("/did-registrar/dids").body(createDidRequest), Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), ) @@ -54,42 +71,18 @@ class PublishDidSteps { actor.remember("longFormDid", managedDid.longFormDid) actor.remember("shortFormDid", did.did) + actor.remember("didPurpose", didPurpose) actor.forget("hasPublishedDid") } - @Given("{actor} has a published DID") - fun agentHasAPublishedDID(agent: Actor) { - if (agent.recallAll().containsKey("hasPublishedDid")) { - return - } - if (!agent.recallAll().containsKey("shortFormDid") && - !agent.recallAll().containsKey("longFormDid") - ) { - createsUnpublishedDid(agent) - } - hePublishesDidToLedger(agent) - } - - @Given("{actor} has an unpublished DID") - fun agentHasAnUnpublishedDID(agent: Actor) { - if (agent.recallAll().containsKey("shortFormDid") || - agent.recallAll().containsKey("longFormDid") - ) { - // is not published - if (!agent.recallAll().containsKey("hasPublishedDid")) { - return - } - } - createsUnpublishedDid(agent) - } - @When("{actor} publishes DID to ledger") fun hePublishesDidToLedger(actor: Actor) { + val shortFormDid = actor.recall("shortFormDid") actor.attemptsTo( - Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/publications"), + Post.to("/did-registrar/dids/$shortFormDid/publications"), ) - val didOperationResponse = SerenityRest.lastResponse().get() + val didOperationResponse = SerenityRest.lastResponse().get() actor.attemptsTo( Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), @@ -126,9 +119,6 @@ class PublishDidSteps { val shortFormDid = actor.recall("shortFormDid") actor.attemptsTo( Ensure.that(didDocument.id).isEqualTo(shortFormDid), - Ensure.that(didDocument.authentication!![0]) - .isEqualTo("$shortFormDid#${TestConstants.PRISM_DID_AUTH_KEY.id}"), - Ensure.that(didDocument.verificationMethod!![0].controller).isEqualTo(shortFormDid), Ensure.that(didResolutionResult.didDocumentMetadata.deactivated!!).isFalse(), ) } diff --git a/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt index eedf729c77..a10d9982e3 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt @@ -1,6 +1,6 @@ package steps.did -import common.TestConstants +import common.body import interactions.Get import interactions.Post import io.cucumber.java.en.Then @@ -19,85 +19,75 @@ class UpdateDidSteps { @When("{actor} updates PRISM DID by adding new key with {curve} curve and {purpose} purpose") fun actorUpdatesPrismDidByAddingNewKeys(actor: Actor, curve: Curve, purpose: Purpose) { val newDidKeyId = UUID.randomUUID().toString() - val didKey = ManagedDIDKeyTemplate( - id = newDidKeyId, - purpose = purpose, - curve = curve, - ) val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.ADD_KEY, - addKey = didKey, + addKey = ManagedDIDKeyTemplate( + id = newDidKeyId, + purpose = purpose, + curve = curve, + ), ) actor.remember("newDidKeyId", newDidKeyId) - actor.remember("updatePrismDidAction", updatePrismDidAction) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @When("{actor} updates PRISM DID by removing keys") fun actorUpdatesPrismDidByRemovingKeys(actor: Actor) { + val didKeyId = actor.recall("newDidKeyId") val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.REMOVE_KEY, - removeKey = RemoveEntryById(TestConstants.PRISM_DID_AUTH_KEY.id), + removeKey = RemoveEntryById(didKeyId), ) - actor.remember("updatePrismDidAction", updatePrismDidAction) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @When("{actor} updates PRISM DID with new services") fun actorUpdatesPrismDidWithNewServices(actor: Actor) { + val serviceId = UUID.randomUUID().toString() val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.ADD_SERVICE, - addService = TestConstants.PRISM_DID_UPDATE_NEW_SERVICE, + addService = Service( + id = serviceId, + type = listOf("LinkedDomains"), + serviceEndpoint = Json("https://service.com/"), + ), ) - actor.remember("updatePrismDidAction", updatePrismDidAction) + actor.remember("newServiceId", serviceId) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @When("{actor} updates PRISM DID by removing services") fun actorUpdatesPrismDidByRemovingServices(actor: Actor) { + val serviceId = actor.recall("newServiceId") val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.REMOVE_SERVICE, - removeService = RemoveEntryById(TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id), + removeService = RemoveEntryById(serviceId), ) - actor.remember("updatePrismDidAction", updatePrismDidAction) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @When("{actor} updates PRISM DID by updating services") fun actorUpdatesPrismDidByUpdatingServices(actor: Actor) { - val newService = UpdateManagedDIDServiceAction( - id = TestConstants.PRISM_DID_SERVICE_FOR_UPDATE.id, - type = TestConstants.PRISM_DID_SERVICE_FOR_UPDATE.type, - serviceEndpoint = Json( - TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL, - ), - ) + val serviceId = actor.recall("newServiceId") + val newServiceUrl = "https://update.com" val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.UPDATE_SERVICE, - updateService = newService, + updateService = UpdateManagedDIDServiceAction( + id = serviceId, + type = listOf("LinkedDomains"), + serviceEndpoint = Json(newServiceUrl), + ), ) - actor.remember("updatePrismDidAction", updatePrismDidAction) - } - @When("{actor} submits PRISM DID update operation") - fun actorSubmitsPrismDidUpdateOperation(actor: Actor) { - actor.attemptsTo( - Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/updates") - .with { - it.body(UpdateManagedDIDRequest(listOf(actor.recall("updatePrismDidAction")))) - }, - ) - val didOperationResponse = SerenityRest.lastResponse().get() - actor.attemptsTo( - Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), - Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), - Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty(), - ) + actor.remember("newServiceUrl", newServiceUrl) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @Then("{actor} sees PRISM DID was successfully updated with new keys of {purpose} purpose") fun actorSeesDidSuccessfullyUpdatedWithNewKeys(actor: Actor, purpose: Purpose) { val newDidKeyId = actor.recall("newDidKeyId") - Wait.until( - errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", - ) { + Wait.until(errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!") { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) @@ -115,27 +105,30 @@ class UpdateDidSteps { } } - @Then("{actor} sees PRISM DID was successfully updated and keys removed") - fun actorSeesDidSuccessfullyUpdatedAndKeysRemoved(actor: Actor) { - Wait.until( - errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", - ) { + @Then("{actor} sees PRISM DID was successfully updated and keys removed with {purpose} purpose") + fun actorSeesDidSuccessfullyUpdatedAndKeysRemoved(actor: Actor, purpose: Purpose) { + val newDidKeyId = actor.recall("newDidKeyId") + Wait.until(errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!") { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) - val authUris = SerenityRest.lastResponse().get().didDocument!!.authentication!! - val verificationMethods = SerenityRest.lastResponse() - .get().didDocument!!.verificationMethod!!.map { it.id } - authUris.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" - } && verificationMethods.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" + val didKey = "${actor.recall("shortFormDid")}#$newDidKeyId" + val didDocument = SerenityRest.lastResponse().get().didDocument!! + val verificationMethodNotPresent = didDocument.verificationMethod!!.map { it.id }.none { it == didKey } + + verificationMethodNotPresent && when (purpose) { + Purpose.ASSERTION_METHOD -> didDocument.assertionMethod!!.none { it == didKey } + Purpose.AUTHENTICATION -> didDocument.authentication!!.none { it == didKey } + Purpose.CAPABILITY_DELEGATION -> didDocument.capabilityDelegation!!.none { it == didKey } + Purpose.CAPABILITY_INVOCATION -> didDocument.capabilityInvocation!!.none { it == didKey } + Purpose.KEY_AGREEMENT -> didDocument.keyAgreement!!.none { it == didKey } } } } - @Then("{actor} sees PRISM DID was successfully updated with new services") + @Then("{actor} sees that PRISM DID should have the new service") fun actorSeesDidSuccessfullyUpdatedWithNewServices(actor: Actor) { + val serviceId = actor.recall("newServiceId") Wait.until( errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", ) { @@ -145,13 +138,14 @@ class UpdateDidSteps { val serviceIds = SerenityRest.lastResponse().get().didDocument!!.service!!.map { it.id } serviceIds.any { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" + it == "${actor.recall("shortFormDid")}#$serviceId" } } } - @Then("{actor} sees PRISM DID was successfully updated by removing services") + @Then("{actor} sees the PRISM DID should have the service removed") fun actorSeesDidSuccessfullyUpdatedByRemovingServices(actor: Actor) { + val serviceId = actor.recall("newServiceId") Wait.until( errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", ) { @@ -161,13 +155,14 @@ class UpdateDidSteps { val serviceIds = SerenityRest.lastResponse().get().didDocument!!.service!!.map { it.id } serviceIds.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" + it == "${actor.recall("shortFormDid")}#$serviceId" } } } - @Then("{actor} sees PRISM DID was successfully updated by updating services") + @Then("{actor} sees the PRISM DID should have the service updated") fun actorSeesDidSuccessfullyUpdatedByUpdatingServices(actor: Actor) { + val serviceUrl = actor.recall("newServiceUrl") Wait.until( errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", ) { @@ -175,7 +170,36 @@ class UpdateDidSteps { Get.resource("/dids/${actor.recall("shortFormDid")}"), ) val service = SerenityRest.lastResponse().get().didDocument!!.service!! - service.any { it.serviceEndpoint.value.contains(TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL) } + service.any { it.serviceEndpoint.value.contains(serviceUrl) } } } + + private fun actorSubmitsPrismDidUpdateOperation(actor: Actor, updatePrismDidAction: UpdateManagedDIDRequestAction) { + actor.attemptsTo( + Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/updates") + .body(UpdateManagedDIDRequest(listOf(updatePrismDidAction))), + ) + } + + @Then("{actor} sees the PRISM DID should have been updated successfully") + fun checkIfUpdateWasSuccessful(actor: Actor) { + val didOperationResponse = SerenityRest.lastResponse().get() + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), + Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), + Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty(), + ) + } + + @Then("{actor} sees the PRISM DID was not successfully updated") + fun checkIfUpdateWasNotSuccessful(actor: Actor) { + val detail: String = SerenityRest.lastResponse().get("detail") + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_BAD_REQUEST), + Ensure.that(detail) + .contains( + "Ed25519 must be used in [Authentication, AssertionMethod]. X25519 must be used in [KeyAgreement]" + ) + ) + } } diff --git a/tests/integration-tests/src/test/resources/features/credentials/issue_anoncred_with_published_did.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_anoncred_with_published_did.feature new file mode 100644 index 0000000000..051e8df412 --- /dev/null +++ b/tests/integration-tests/src/test/resources/features/credentials/issue_anoncred_with_published_did.feature @@ -0,0 +1,15 @@ +@RFC0453 @AIP20 @credentials +Feature: Issue Anoncred with published DID + + Background: + Given Issuer and Holder have an existing connection + And Issuer has a published DID for ANONCRED + And Holder has an unpublished DID for ANONCRED + + Scenario: Issuing anoncred with published PRISM DID + Given Issuer has an anoncred schema definition + When Issuer offers anoncred to Holder + And Holder receives the credential offer + And Holder accepts credential offer for anoncred + And Issuer issues the credential + Then Holder receives the issued credential diff --git a/tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_published_did.feature similarity index 90% rename from tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature rename to tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_published_did.feature index c44fa3c948..e54fd17c2d 100644 --- a/tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature +++ b/tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_published_did.feature @@ -1,11 +1,11 @@ @RFC0453 @AIP20 @credentials -Feature: Issue Credentials Protocol with published DID +Feature: Issue JWT Credentials with published DID Background: Given Issuer and Holder have an existing connection - And Issuer has a published DID + And Issuer has a published DID for JWT And Issuer has published STUDENT_SCHEMA schema - And Holder has an unpublished DID + And Holder has an unpublished DID for JWT Scenario: Issuing credential with published PRISM DID When Issuer offers a credential to Holder with "short" form DID diff --git a/tests/integration-tests/src/test/resources/features/credentials/issue_unpublished_did.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_unpublished_did.feature similarity index 73% rename from tests/integration-tests/src/test/resources/features/credentials/issue_unpublished_did.feature rename to tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_unpublished_did.feature index e9ac6e44f0..a658a0c453 100644 --- a/tests/integration-tests/src/test/resources/features/credentials/issue_unpublished_did.feature +++ b/tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_unpublished_did.feature @@ -1,10 +1,10 @@ @RFC0453 @AIP20 @credentials -Feature: Issue Credentials Protocol with unpublished DID +Feature: Issue JWT Credentials with unpublished DID Background: Given Issuer and Holder have an existing connection - And Issuer has an unpublished DID - And Holder has an unpublished DID + And Issuer has an unpublished DID for JWT + And Holder has an unpublished DID for JWT Scenario: Issuing credential with unpublished PRISM DID And Issuer offers a credential to Holder with "long" form DID diff --git a/tests/integration-tests/src/test/resources/features/did/create_did.feature b/tests/integration-tests/src/test/resources/features/did/create_did.feature index 3879305102..55ebe81a21 100644 --- a/tests/integration-tests/src/test/resources/features/did/create_did.feature +++ b/tests/integration-tests/src/test/resources/features/did/create_did.feature @@ -1,28 +1,28 @@ @DLT @did @create Feature: Create and publish DID -Scenario Outline: Create PRISM DID - When Issuer creates PRISM DID with key having purpose - Then He sees PRISM DID was created successfully - And He sees PRISM DID data was stored correctly with and -Examples: - | curve | purpose | - | secp256k1 | authentication | - | secp256k1 | assertionMethod | - | Ed25519 | authentication | - | Ed25519 | assertionMethod | - | X25519 | keyAgreement | + Scenario Outline: Create PRISM DID + When Issuer creates PRISM DID with key having purpose + Then He sees PRISM DID was created successfully + And He sees PRISM DID data was stored correctly with and + Examples: + | curve | purpose | + | secp256k1 | authentication | + | secp256k1 | assertionMethod | + | Ed25519 | authentication | + | Ed25519 | assertionMethod | + | X25519 | keyAgreement | -Scenario Outline: Create PRISM DID with disallowed key purpose - When Issuer creates PRISM DID with key having purpose - Then He sees PRISM DID was not successfully created - Examples: - | curve | purpose | - | Ed25519 | keyAgreement | - | X25519 | authentication | - | X25519 | assertionMethod | + Scenario Outline: Create PRISM DID with disallowed key purpose + When Issuer creates PRISM DID with key having purpose + Then He sees PRISM DID was not successfully created + Examples: + | curve | purpose | + | Ed25519 | keyAgreement | + | X25519 | authentication | + | X25519 | assertionMethod | -Scenario: Successfully publish DID to ledger - When Issuer creates unpublished DID - And He publishes DID to ledger - Then He resolves DID document corresponds to W3C standard + Scenario: Successfully publish DID to ledger + Given Issuer creates unpublished DID + When He publishes DID to ledger + Then He resolves DID document corresponds to W3C standard diff --git a/tests/integration-tests/src/test/resources/features/did/update_did.feature b/tests/integration-tests/src/test/resources/features/did/update_did.feature index 67760dc1b6..9aeb2e122f 100644 --- a/tests/integration-tests/src/test/resources/features/did/update_did.feature +++ b/tests/integration-tests/src/test/resources/features/did/update_did.feature @@ -2,27 +2,27 @@ Feature: Update DID Background: Published DID is created - Given Issuer has a published DID + Given Issuer has a published DID for JWT - Scenario: Update PRISM DID by adding new services + Scenario: Update PRISM DID services When Issuer updates PRISM DID with new services - And He submits PRISM DID update operation - Then He sees PRISM DID was successfully updated with new services + Then He sees the PRISM DID should have been updated successfully + And He sees that PRISM DID should have the new service - Scenario: Update PRISM DID by removing services - When Issuer updates PRISM DID by removing services - And He submits PRISM DID update operation - Then He sees PRISM DID was successfully updated by removing services - - Scenario: Update PRISM DID by updating services When Issuer updates PRISM DID by updating services - And He submits PRISM DID update operation - Then He sees PRISM DID was successfully updated by updating services + Then He sees the PRISM DID should have been updated successfully + And He sees the PRISM DID should have the service updated - Scenario Outline: Update PRISM DID by adding new keys + When Issuer updates PRISM DID by removing services + Then He sees the PRISM DID should have been updated successfully + And He sees the PRISM DID should have the service removed + + Scenario Outline: Update PRISM DID keys When Issuer updates PRISM DID by adding new key with curve and purpose - And He submits PRISM DID update operation Then He sees PRISM DID was successfully updated with new keys of purpose + + When Issuer updates PRISM DID by removing keys + Then He sees PRISM DID was successfully updated and keys removed with purpose Examples: | curve | purpose | | secp256k1 | authentication | @@ -31,7 +31,11 @@ Feature: Update DID | Ed25519 | assertionMethod | | X25519 | keyAgreement | - Scenario: Update PRISM DID by removing keys - When Issuer updates PRISM DID by removing keys - And He submits PRISM DID update operation - Then He sees PRISM DID was successfully updated and keys removed + Scenario Outline: Update PRISM DID with disallowed key purpose + When Issuer updates PRISM DID by adding new key with curve and purpose + Then He sees the PRISM DID was not successfully updated + Examples: + | curve | purpose | + | Ed25519 | keyAgreement | + | X25519 | authentication | + | X25519 | assertionMethod | diff --git a/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature b/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature index f19b73090d..f73c15c829 100644 --- a/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature +++ b/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature @@ -3,7 +3,7 @@ Feature: Present Proof Protocol Scenario: Holder presents credential proof to verifier Given Verifier and Holder have an existing connection - And Holder has an issued credential from Issuer + And Holder has a jwt issued credential from Issuer When Verifier sends a request for proof presentation to Holder And Holder receives the request And Holder makes the presentation of the proof to Verifier @@ -11,7 +11,7 @@ Feature: Present Proof Protocol Scenario: Verifier rejects holder proof Given Verifier and Holder have an existing connection - And Holder has an issued credential from Issuer + And Holder has a jwt issued credential from Issuer When Verifier sends a request for proof presentation to Holder And Holder receives the request And Holder rejects the proof @@ -19,7 +19,7 @@ Feature: Present Proof Protocol Scenario: Holder presents proof to verifier which is the issuer itself Given Issuer and Holder have an existing connection - And Holder has an issued credential from Issuer + And Holder has a jwt issued credential from Issuer When Issuer sends a request for proof presentation to Holder And Holder receives the request And Holder makes the presentation of the proof to Issuer diff --git a/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature b/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature index 102140b1fa..77c52dc572 100644 --- a/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature +++ b/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature @@ -4,8 +4,8 @@ Feature: Present Proof Protocol Scenario: Holder presents anoncreds credential proof to verifier Given Issuer and Holder have an existing connection And Verifier and Holder have an existing connection - And Issuer has a published DID - And Holder has an unpublished DID + And Issuer has a published DID for ANONCRED + And Holder has an unpublished DID for ANONCRED And Issuer has an anoncred schema definition And Issuer offers anoncred to Holder And Holder receives the credential offer diff --git a/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature b/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature index 2ac02f447b..4c07ff2fe3 100644 --- a/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature +++ b/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature @@ -2,7 +2,7 @@ Feature: Credential revocation - JWT Background: - Given Holder has an issued credential from Issuer + Given Holder has a jwt issued credential from Issuer Scenario: Revoke issued credential When Issuer revokes the credential issued to Holder diff --git a/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature b/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature index fb65e1682d..fdbbbc911f 100644 --- a/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature +++ b/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature @@ -2,7 +2,7 @@ Feature: Credential schemas Background: - When Issuer creates unpublished DID + Given Issuer creates unpublished DID Scenario: Successful schema creation When Issuer creates a new credential STUDENT_SCHEMA schema diff --git a/tests/integration-tests/src/test/resources/features/verificationapi/vc_verification.feature b/tests/integration-tests/src/test/resources/features/verificationapi/vc_verification.feature index 92b393936b..3db147f66d 100644 --- a/tests/integration-tests/src/test/resources/features/verificationapi/vc_verification.feature +++ b/tests/integration-tests/src/test/resources/features/verificationapi/vc_verification.feature @@ -1,9 +1,8 @@ @verification @api Feature: Vc Verification schemas - @flaky Scenario: Receive a jwt vc from cloud-agent and verify it - Given Holder has an issued credential with STUDENT_SCHEMA schema from Issuer + Given Holder has a jwt issued credential with STUDENT_SCHEMA schema from Issuer And Holder uses that JWT VC issued from Issuer for Verification API And Holder sends the JWT Credential to Issuer Verification API | ALGORITHM_VERIFICATION | true | @@ -30,24 +29,24 @@ Feature: Vc Verification schemas Scenario Outline: Expected failures Given Holder has a problem in the Verifiable Credential When Holder sends the JWT Credential to Issuer Verification API - | | false | + | | false | Then Holder should see that verification has failed with problem Examples: - | problem | - | ALGORITHM_VERIFICATION | - | AUDIENCE_CHECK | - | EXPIRATION_CHECK | - | ISSUER_IDENTIFICATION | - | NOT_BEFORE_CHECK | - | SIGNATURE_VERIFICATION | - | SEMANTIC_CHECK_OF_CLAIMS | + | problem | + | ALGORITHM_VERIFICATION | + | AUDIENCE_CHECK | + | EXPIRATION_CHECK | + | ISSUER_IDENTIFICATION | + | NOT_BEFORE_CHECK | + | SIGNATURE_VERIFICATION | + | SEMANTIC_CHECK_OF_CLAIMS | Scenario Outline: Unsupported verification check should fail Given Holder has a JWT VC for Verification API When Holder sends the JWT Credential to Issuer Verification API | | false | Then Holder should see the check has failed - Examples: + Examples: | verification | | COMPLIANCE_WITH_STANDARDS | | INTEGRITY_OF_CLAIMS |