Beispiel #1
0
async def alice_bob_connect_multi(
    bob_member_client: AsyncClient,
    alice_member_client: AsyncClient,
    bob_multi_use_invitation: MultiInvite,
) -> BobAliceConnect:
    invitation = bob_multi_use_invitation["multi_use_invitation"]["invitation"]

    # accept invitation on alice side
    invitation_response = (await alice_member_client.post(
        "/generic/connections/accept-invitation",
        json={"invitation": invitation},
    )).json()

    assert check_webhook_state(
        client=alice_member_client,
        filter_map={"state": "request-sent"},
        topic="connections",
        max_duration=30,
    )

    bob_connection_id = bob_multi_use_invitation["multi_use_invitation"][
        "connection_id"]
    alice_connection_id = invitation_response["connection_id"]

    # fetch and validate
    # both connections should be active - we have waited long enough for events to be exchanged
    bob_connection_records = (
        await bob_member_client.get("/generic/connections")).json()
    print(json.dumps(bob_connection_records, indent=2))

    bob_connection_id = bob_connection_records[0]["connection_id"]

    assert check_webhook_state(
        client=alice_member_client,
        filter_map={"state": "completed"},
        topic="connections",
        max_duration=30,
    )
    assert check_webhook_state(
        client=bob_member_client,
        filter_map={"state": "completed"},
        topic="connections",
        max_duration=30,
    )

    return {
        "alice_connection_id": alice_connection_id,
        "bob_connection_id": bob_connection_id,
    }
async def test_oob_connect_via_public_did(
    bob_member_client: AsyncClient,
    alice_member_client: AsyncClient,
    bob_and_alice_public_did: BobAlicePublicDid,
):
    time.sleep(5)
    connect_response = await bob_member_client.post(
        "/generic/connections/oob/connect-public-did",
        json={"public_did": bob_and_alice_public_did["alice_public_did"]},
    )
    bob_connection_record = connect_response.json()

    assert check_webhook_state(
        client=bob_member_client,
        topic="connections",
        filter_map={
            "state": "request-sent",
            "connection_id": bob_connection_record["connection_id"],
        },
    )

    public_did_response = await alice_member_client.get("/wallet/dids/public")
    alice_public_did = public_did_response.json()

    assert_that(bob_connection_record).has_their_public_did(
        alice_public_did["did"])
async def test_accept_invitation(
    bob_member_client: AsyncClient,
    alice_member_client: AsyncClient,
):
    invitation_response = await bob_member_client.post(
        "/generic/connections/create-invitation")
    invitation = invitation_response.json()

    accept_response = await alice_member_client.post(
        "/generic/connections/accept-invitation",
        json={"invitation": invitation["invitation"]},
    )
    connection_record = accept_response.json()

    assert check_webhook_state(
        client=alice_member_client,
        topic="connections",
        filter_map={
            "state": "completed",
            "connection_id": connection_record["connection_id"],
        },
    )

    assert_that(connection_record).contains("connection_id", "state",
                                            "created_at", "updated_at",
                                            "invitation_key")
    assert_that(connection_record).has_state("request-sent")
async def test_bob_and_alice_connect(
    bob_member_client: AsyncClient,
    alice_member_client: AsyncClient,
):
    time.sleep(1)
    invitation_response = await bob_member_client.post(
        "/generic/connections/create-invitation", )
    invitation = invitation_response.json()

    accept_response = await alice_member_client.post(
        "/generic/connections/accept-invitation",
        json={"invitation": invitation["invitation"]},
    )
    connection_record = accept_response.json()

    assert check_webhook_state(
        client=alice_member_client,
        topic="connections",
        filter_map={
            "state": "completed",
            "connection_id": connection_record["connection_id"],
        },
    )

    alice_connection_id = connection_record["connection_id"]
    bob_connection_id = invitation["connection_id"]

    bob_connection = (await bob_member_client.get(
        f"/generic/connections/{bob_connection_id}")).json()
    alice_connection = (await alice_member_client.get(
        f"/generic/connections/{alice_connection_id}")).json()

    assert "completed" in alice_connection["state"]
    assert "completed" in bob_connection["state"]
Beispiel #5
0
async def bob_and_alice_connection(
    bob_member_client: AsyncClient,
    alice_member_client: AsyncClient,
) -> BobAliceConnect:
    # create invitation on bob side
    invitation = (await bob_member_client.post(
        "/generic/connections/create-invitation")).json()

    # accept invitation on alice side
    invitation_response = (await alice_member_client.post(
        "/generic/connections/accept-invitation",
        json={"invitation": invitation["invitation"]},
    )).json()

    assert check_webhook_state(alice_member_client,
                               topic="connections",
                               filter_map={"state": "completed"})

    bob_connection_id = invitation["connection_id"]
    alice_connection_id = invitation_response["connection_id"]

    # fetch and validate
    # both connections should be active - we have waited long enough for events to be exchanged
    assert check_webhook_state(
        alice_member_client,
        topic="connections",
        filter_map={"state": "completed"},
    )
    assert check_webhook_state(
        bob_member_client,
        topic="connections",
        filter_map={"state": "completed"},
    )

    return {
        "alice_connection_id": alice_connection_id,
        "bob_connection_id": bob_connection_id,
    }
async def test_send_credential_request(
    alice_member_client: AsyncClient,
    faber_client: AsyncClient,
    faber_and_alice_connection: FaberAliceConnect,
    credential_definition_id: str,
):
    credential = {
        "protocol_version": "v1",
        "credential_definition_id": credential_definition_id,
        "connection_id": faber_and_alice_connection["faber_connection_id"],
        "attributes": {"speed": "10"},
    }

    response = await faber_client.post(
        BASE_PATH,
        json=credential,
    )
    credential_exchange = response.json()
    assert credential_exchange["protocol_version"] == "v1"

    assert check_webhook_state(
        client=faber_client,
        filter_map={
            "state": "offer-sent",
            "credential_id": credential_exchange["credential_id"],
        },
        topic="credentials",
    )

    response = await alice_member_client.get(
        BASE_PATH,
        params={"connection_id": faber_and_alice_connection["alice_connection_id"]},
    )
    assert check_webhook_state(
        client=alice_member_client,
        filter_map={"state": "offer-received"},
        topic="credentials",
    )
Beispiel #7
0
async def credential_exchange_id(
    faber_client: AsyncClient,
    credential_definition_id: str,
    faber_and_alice_connection: FaberAliceConnect,
    alice_member_client: AsyncClient,
):
    """this fixture produces the CRED_X_ID but if the test that produces the CRED_X_ID has already run
    then this fixture just returns it..."""
    credential = {
        "protocol_version": "v1",
        "connection_id": faber_and_alice_connection["faber_connection_id"],
        "credential_definition_id": credential_definition_id,
        "attributes": {"speed": "average"},
    }

    response = await faber_client.post(
        BASE_PATH,
        json=credential,
    )
    response.raise_for_status()
    credential_exchange = response.json()
    credential_exchange_id = credential_exchange["credential_id"]
    assert credential_exchange["protocol_version"] == "v1"

    assert check_webhook_state(
        client=faber_client,
        filter_map={
            "state": "offer-sent",
            "credential_id": credential_exchange["credential_id"],
        },
        topic="credentials",
    )

    response = await alice_member_client.get(
        BASE_PATH,
        params={"connection_id": faber_and_alice_connection["alice_connection_id"]},
    )
    response.raise_for_status()
    records = response.json()
    assert len(records) > 0

    return credential_exchange_id
async def test_create_tenant_ecosystem_issuer(
    ecosystem_admin_client: AsyncClient,
    ecosystem_admin_acapy_client: AcaPyClient,
    governance_acapy_client: AcaPyClient,
):
    name = uuid4().hex
    response = await ecosystem_admin_client.post(
        BASE_PATH,
        json={
            "image_url": "https://image.ca",
            "name": name,
            "roles": ["issuer"],
        },
    )
    assert response.status_code == 200

    tenant = response.json()
    tenant_id = tenant["tenant_id"]

    wallet = await ecosystem_admin_acapy_client.multitenancy.get_wallet(
        wallet_id=tenant_id)

    acapy_token: str = tenant["access_token"].split(".", 1)[1]
    actor = await trust_registry.actor_by_id(tenant_id)

    endorser_did = await acapy_wallet.get_public_did(governance_acapy_client)

    async with get_tenant_controller(Role.ECOSYSTEM,
                                     acapy_token) as tenant_controller:
        public_did = await acapy_wallet.get_public_did(tenant_controller)

        connections = await tenant_controller.connection.get_connections()

        connections = [
            connection for connection in connections.results
            if connection.their_public_did == endorser_did.did
        ]

    if not actor:
        raise Exception("Missing actor")

    connection = connections[0]

    async with ecosystem_client(token=tenant["access_token"]) as client:
        # Wait for connection to be completed
        assert check_webhook_state(
            client,
            "connections",
            {
                "state": "completed",
                "connection_id": connection.connection_id,
            },
        )

    # Actor
    assert_that(actor).has_name(tenant["tenant_name"])
    assert_that(actor).has_did(f"did:sov:{public_did.did}")
    assert_that(actor).has_roles(["issuer"])

    # Connection with endorser
    assert_that(connection).has_their_public_did(endorser_did.did)

    # Tenant
    assert_that(tenant).has_tenant_id(wallet.wallet_id)
    assert_that(tenant).has_tenant_name(name)
    assert_that(tenant).has_created_at(wallet.created_at)
    assert_that(tenant).has_updated_at(wallet.updated_at)
    assert wallet.settings["wallet.name"].startswith("ecosystem.")
async def test_update_tenant_ecosystem_verifier_to_issuer(
    ecosystem_admin_client: AsyncClient,
    ecosystem_admin_acapy_client: AcaPyClient,
    governance_acapy_client: AcaPyClient,
):
    name = uuid4().hex
    response = await ecosystem_admin_client.post(
        BASE_PATH,
        json={
            "image_url": "https://image.ca",
            "name": name,
            "roles": ["verifier"],
        },
    )
    assert response.status_code == 200

    tenant = response.json()
    tenant_id = tenant["tenant_id"]
    actor = await trust_registry.actor_by_id(tenant_id)

    wallet = await ecosystem_admin_acapy_client.multitenancy.get_wallet(
        wallet_id=tenant_id)

    acapy_token: str = tenant["access_token"].split(".", 1)[1]

    async with get_tenant_controller(Role.ECOSYSTEM,
                                     acapy_token) as tenant_controller:
        connections = await tenant_controller.connection.get_connections(
            alias=f"Trust Registry {name}")

    connection = connections.results[0]

    # Connection invitation
    assert_that(connection).has_state("invitation")

    assert actor
    assert_that(actor).has_name(name)
    assert_that(actor).has_did(
        ed25519_verkey_to_did_key(connection.invitation_key))
    assert_that(actor).has_roles(["verifier"])

    # Tenant
    assert_that(tenant).has_tenant_id(wallet.wallet_id)
    assert_that(tenant).has_image_url("https://image.ca")
    assert_that(tenant).has_tenant_name(name)
    assert_that(tenant).has_created_at(wallet.created_at)
    assert_that(tenant).has_updated_at(wallet.updated_at)
    assert wallet.settings["wallet.name"].startswith("ecosystem.")

    new_name = uuid4().hex
    new_image_url = "https://some-ssi-site.org/image.png"
    new_roles = ["issuer", "verifier"]

    response = await ecosystem_admin_client.put(
        f"{BASE_PATH}/{tenant_id}",
        json={
            "image_url": new_image_url,
            "name": new_name,
            "roles": new_roles,
        },
    )

    assert response.status_code == 200
    new_tenant = response.json()
    new_actor = await trust_registry.actor_by_id(tenant_id)

    endorser_did = await acapy_wallet.get_public_did(governance_acapy_client)

    async with get_tenant_controller(Role.ECOSYSTEM,
                                     acapy_token) as tenant_controller:
        public_did = await acapy_wallet.get_public_did(tenant_controller)

        _connections = (await
                        tenant_controller.connection.get_connections()).results

        connections = [
            connection for connection in _connections
            if connection.their_public_did == endorser_did.did
        ]

    endorser_connection = connections[0]

    async with ecosystem_client(token=tenant["access_token"]) as client:
        # Wait for connection to be completed
        assert check_webhook_state(
            client,
            "connections",
            {
                "state": "completed",
                "connection_id": endorser_connection.connection_id,
            },
        )

    # Connection invitation
    assert_that(endorser_connection).has_their_public_did(endorser_did.did)

    assert new_actor
    assert_that(new_actor).has_name(new_name)
    assert_that(new_actor).has_did(f"did:sov:{public_did.did}")
    assert_that(new_actor["roles"]).contains_only("issuer", "verifier")

    assert new_actor["didcomm_invitation"] is None

    # Tenant
    assert_that(new_tenant).has_tenant_id(wallet.wallet_id)
    assert_that(new_tenant).has_image_url(new_image_url)
    assert_that(new_tenant).has_tenant_name(new_name)
    assert_that(new_tenant).has_created_at(wallet.created_at)
    assert wallet.settings["wallet.name"].startswith("ecosystem.")
Beispiel #10
0
async def test_accept_proof_request_v1(
    issue_credential_to_alice: CredentialExchange,
    alice_member_client: AsyncClient,
    acme_client: AsyncClient,
    acme_and_alice_connection: AcmeAliceConnect,
):
    response = await acme_client.post(
        BASE_PATH + "/send-request",
        json={
            "connection_id": acme_and_alice_connection["acme_connection_id"],
            "protocol_version": "v1",
            "proof_request": indy_proof_request.dict(),
        },
    )
    response.raise_for_status()
    acme_exchange = response.json()
    acme_proof_id = acme_exchange["proof_id"]

    assert check_webhook_state(
        client=alice_member_client,
        filter_map={"state": "request-received"},
        topic="proofs",
        max_duration=120,
    )
    proof_records_alice = await alice_member_client.get(BASE_PATH + "/proofs")
    alice_proof_id = proof_records_alice.json()[0]["proof_id"]

    requested_credentials = await alice_member_client.get(
        f"/generic/verifier/proofs/{alice_proof_id}/credentials")

    referent = requested_credentials.json()[0]["cred_info"]["referent"]
    indy_request_attrs = IndyRequestedCredsRequestedAttr(cred_id=referent,
                                                         revealed=True)
    proof_accept = AcceptProofRequest(
        proof_id=alice_proof_id,
        presentation_spec=IndyPresSpec(
            requested_attributes={"0_speed_uuid": indy_request_attrs},
            requested_predicates={},
            self_attested_attributes={},
        ),
    )

    response = await alice_member_client.post(
        BASE_PATH + "/accept-request",
        json=proof_accept.dict(),
    )
    assert check_webhook_state(
        client=alice_member_client,
        filter_map={
            "state": "done",
            "proof_id": alice_proof_id
        },
        topic="proofs",
        max_duration=120,
    )
    assert check_webhook_state(
        client=acme_client,
        filter_map={
            "state": "done",
            "proof_id": acme_proof_id
        },
        topic="proofs",
        max_duration=120,
    )

    result = response.json()

    pres_exchange_result = PresentationExchange(**result)
    assert isinstance(pres_exchange_result, PresentationExchange)
    assert response.status_code == 200
async def test_store_credential(
    alice_member_client: AsyncClient,
    faber_client: AsyncClient,
    credential_definition_id: str,
    faber_and_alice_connection: FaberAliceConnect,
):
    credential = {
        "protocol_version": "v1",
        "credential_definition_id": credential_definition_id,
        "connection_id": faber_and_alice_connection["faber_connection_id"],
        "attributes": {"speed": "10"},
    }

    response = await faber_client.post(
        BASE_PATH,
        json=credential,
    )
    credential_exchange = response.json()
    assert credential_exchange["protocol_version"] == "v1"

    assert check_webhook_state(
        client=faber_client,
        filter_map={
            "state": "offer-sent",
            "credential_id": credential_exchange["credential_id"],
        },
        topic="credentials",
    )

    response = await alice_member_client.get(
        BASE_PATH,
        params={"connection_id": faber_and_alice_connection["alice_connection_id"]},
    )
    assert check_webhook_state(
        client=alice_member_client,
        filter_map={"state": "offer-received"},
        topic="credentials",
    )

    cred_hooks = get_hooks_per_topic_per_wallet(
        client=alice_member_client, topic="credentials"
    )

    cred_hook = [h for h in cred_hooks if h["payload"]["state"] == "offer-received"][0]
    credential_id = cred_hook["payload"]["credential_id"]

    # alice send request for that credential
    response = await alice_member_client.post(f"{BASE_PATH}/{credential_id}/request")
    response.raise_for_status()

    # Bob check he received the request; Credential is send because of using
    # 'automating the entire flow' send credential earlier.
    # See also: app/generic/issuer/issuer.py::send_credential
    assert check_webhook_state(
        client=faber_client,
        filter_map={"state": "request-received"},
        topic="credentials",
    )

    # Check alice has received the credential
    assert check_webhook_state(
        client=alice_member_client,
        filter_map={"state": "credential-received"},
        topic="credentials",
    )

    # Alice stores credential
    response = await alice_member_client.post(f"{BASE_PATH}/{credential_id}/store")

    # Check alice has received the credential
    assert check_webhook_state(
        client=alice_member_client, filter_map={"state": "done"}, topic="credentials"
    )
async def test_send_credential(
    faber_client: AsyncClient,
    schema_definition: CredentialSchema,
    credential_definition_id: str,
    faber_and_alice_connection: FaberAliceConnect,
    alice_member_client: AsyncClient,
):
    credential = {
        "protocol_version": "v1",
        "connection_id": faber_and_alice_connection["faber_connection_id"],
        "credential_definition_id": credential_definition_id,
        "attributes": {"speed": "10"},
    }

    response = await alice_member_client.get(
        BASE_PATH,
        params={"connection_id": faber_and_alice_connection["alice_connection_id"]},
    )
    records = response.json()

    # nothing currently in alice's records
    assert len(records) == 0

    response = await faber_client.post(
        BASE_PATH,
        json=credential,
    )
    response.raise_for_status()

    data = response.json()
    assert_that(data).contains("credential_id")
    assert_that(data).has_state("offer-sent")
    assert_that(data).has_protocol_version("v1")
    assert_that(data).has_attributes({"speed": "10"})
    assert_that(data).has_schema_id(schema_definition.id)

    credential["protocol_version"] = "v2"
    response = await faber_client.post(
        BASE_PATH,
        json=credential,
    )
    response.raise_for_status()

    data = response.json()
    assert_that(data).has_state("offer-sent")
    assert_that(data).has_protocol_version("v2")
    assert_that(data).has_attributes({"speed": "10"})
    assert_that(data).has_schema_id(schema_definition.id)

    assert check_webhook_state(
        client=faber_client,
        filter_map={
            "state": "offer-sent",
            "credential_id": data["credential_id"],
        },
        topic="credentials",
    )
    response = await alice_member_client.get(
        BASE_PATH,
        params={"connection_id": faber_and_alice_connection["alice_connection_id"]},
    )
    records = response.json()

    assert check_webhook_state(
        client=alice_member_client,
        filter_map={
            "state": "offer-received",
            "credential_id": records[-1]["credential_id"],
        },
        topic="credentials",
    )
    assert len(records) == 2

    # Expect one v1 record, one v2 record
    assert_that(records).extracting("protocol_version").contains("v1", "v2")