Пример #1
0
def test_raises_claims_missing(client: Client, entity: Entity) -> None:
    """Raise TyepError if no claims are provided for endorsement."""
    with pytest.raises(TypeError) as excinfo:
        client.put(entity, endorse=True)
    assert (str(
        excinfo.value
    ) == "missing required keyword argument needed for endorsement: 'claims'")
Пример #2
0
def test_create_request_with_content_claims(
    client: Client,
    endorser: PrivateIdentity,
    mocked_requests_200: respx.MockTransport,
    entity: Entity,
) -> None:
    """Create endorsement request provided by a 3rd party endorser."""
    claims = [b"claim-1", b"claim-2"]

    # Create endorsement request with authorisation of endorser
    content, authorisation = endorser.endorse(entity, claims)

    # This will also add the subject holders authorisation
    client.put(
        entity,
        claims=claims,
        content=content,
        authorisations=[authorisation],
        create_claims=True
        # endorse=True # TODO - provide test that this does not have any effect
    )
    http_request, _ = mocked_requests_200["create_entity"].calls[0]

    claims_header = json.loads(
        iov42_decode(http_request.headers["x-iov42-claims"]))
    assert claims_header == {hashed_claim(c): c.decode() for c in claims}
Пример #3
0
def test_raise_identity_already_exists_2(client: Client) -> None:
    """Raise exception when an identity (with an other key) already exists."""
    client.identity = PrivateIdentity(
        CryptoProtocol.SHA256WithECDSA.generate_private_key(), "test-1234")
    with respx.mock(base_url=PLATFORM_URL) as respx_mock:
        respx_mock.put(
            re.compile("/api/v1/requests/.*$"),
            status_code=400,
            content=
            ('{"errors":[{"errorCode":2503,"errorType":"Authorisation",'
             '"message":"Signature L-IjTeba3wvJn4hHR40GPCG-H7iIeDWOzBo3hCK7x1mLZgif'
             "SdgR-YVxOZtvPzHaI86WdhIL3y-sNOwYUf2c0j7OfT31dAX71W9le-Cp2Mx1PgjjqI09f"
             "i0Nku-h5lgipQ07VKAm3gUx0foeG9GdDQe_I85QuCqtJsaAXWDVc8r0NeWpa3dnQEflIm"
             "W0-gecjO6pYDeyXPALcvp9h8Q_TxkuGVvreqpWvgKzdPMlXHMbN3wYoLNNLM3gpqrqAp"
             "Eze1aTqtlK6gCQUuhsJlKe4Bb2Nj8MRxXXXNpxIJqjJHM0IRps5J0U8gsnEEcny8Zf0tB"
             'h7NGkTteNv554QUbNVA cannot be verified with public credentials of identity test-1234."},'
             '{"errorCode":2503,"errorType":"Authorisation","message":"Signature '
             "L2PIREIx1MZsjV-j0fSMoN3u1eHP2wyqUpAs1mOWdp8k8yrnoBTbyH2Uxw8_9zYTzDHrz"
             "rI16fNKeRFuLlHosWqzoUf41M0Nip5zbW6gmPYiL05AWPdH1pg9qS-cgQa9IFXiMUkZh9"
             "EZltT7HHl9aRn35kcwoJYAoPm96Up1YPI0JWISx1iXXEAcxVOA1N_k-l0tT5Tb7lWNOI4"
             "5eh6flW_vVEeBQDjQhkl94rlP3qDFlDYZ9HZS2A3lTkiIo6MsU57pxeTD9FqwZ8uofJ3O"
             "Yx05TJKl106GPsscf2mnpnQGEzgS20QsJyqUs_u7dpZbAcjfBsaHucVz8gwkz_PoNg "
             'cannot be verified with public credentials of identity test-1234."},'
             '{"errorCode":2602,"errorType":"AssetExistence",'
             '"message":"Another identity with address test-1234 already exists"}],'
             '"requestId":"23343439","proof":"/api/v1/proofs/23343439"}'),
        )
        with pytest.raises(EntityAlreadyExists) as excinfo:
            client.put(client.identity.public_identity, request_id="1234567")
        assert str(excinfo.value) == "identity 'test-1234' already exists"
        assert excinfo.value.request_id == "1234567"
Пример #4
0
def test_create_request_with_content(
    client: Client,
    endorser: PrivateIdentity,
    mocked_requests_200: respx.MockTransport,
    entity: Entity,
) -> None:
    """Create endorsement request provided by a 3rd party endorser."""
    claims = [b"claim-1", b"claim-2"]

    # Create endorsement request with authorisation of endorser
    content, authorisation = endorser.endorse(entity, claims)

    # This will also add the subject holders authorisation
    client.put(
        entity,
        claims=claims,
        content=content,
        authorisations=[authorisation],
        # endorse=True # TODO - provide test that this does not have any effect
    )
    http_request, _ = mocked_requests_200["create_entity"].calls[0]

    request_id = json.loads(content.decode())["requestId"]
    assert http_request.url.path.rsplit("/", 1)[1] == request_id

    claims_header = json.loads(
        iov42_decode(http_request.headers["x-iov42-claims"]))
    assert claims_header == {}

    authorisations = json.loads(
        iov42_decode(http_request.headers["x-iov42-authorisations"].encode()))
    expected_identities = [a["identityId"] for a in authorisations]
    assert client.identity.identity_id in expected_identities
    assert endorser.identity_id in expected_identities
Пример #5
0
def existing_asset_claims(alice_client: Client,
                          existing_asset: Asset) -> List[bytes]:
    """Return a list of claims endorsed against an asset owned by Alice."""
    claims = [b"asset-claim-1", b"asset-claim-2"]
    alice_client.put(existing_asset,
                     claims=claims,
                     endorse=True,
                     create_claims=True)
    return claims
Пример #6
0
def register_product(client: Client, tag_type: AssetType,
                     product: Tuple[str, str]) -> None:
    """Register product on iov42 platform and add product information as claim."""
    tag_id, claim = product
    tag = Asset(asset_id=tag_id, asset_type_id=tag_type.asset_type_id)
    client.put(tag)
    print(f"Created tag: {tag_id}")
    client.put(tag, claims=[claim.encode()], endorse=True)
    print(f"Tag [{tag_id}]: added enrosement on claim '{claim}'")
Пример #7
0
def test_invalid_request_id(client: Client, entity: Entity,
                            invalid_request_id: str) -> None:
    """Raise exception if the provided request ID contains invalid charatcers."""
    with pytest.raises(ValueError) as excinfo:
        client.put(entity, request_id=invalid_request_id)
    # No request is sent
    assert not respx.calls
    assert (
        str(excinfo.value) ==
        f"invalid identifier '{invalid_request_id}' - valid characters are [a-zA-Z0-9._\\-+]"
    )
Пример #8
0
def test_raise_on_request_error(client: Client) -> None:
    """If raise exception on a request error."""
    respx.put(
        re.compile(PLATFORM_URL + "/api/v1/requests/.*$"),
        content=httpcore.ConnectError(),
    )

    # TODO: do we really want to leak httpx to our clients?
    # We could catch all exception thrown by httpx, wrap it in a few library
    # exceptions and rethrow those.
    with pytest.raises(httpx.ConnectError):
        client.put(client.identity.public_identity)
Пример #9
0
def test_raise_duplicate_request_id(client: Client) -> None:
    """Raise exception when the request_id already exists."""
    with respx.mock(base_url=PLATFORM_URL) as respx_mock:
        respx_mock.put(
            re.compile("/api/v1/requests/.*$"),
            status_code=409,
            content=
            ('{"errors":[{"errorCode":2701,"errorType":"RequestId",'
             '"message":"Found duplicate request id"}],"requestId":"1234567"}'
             ),
        )
        with pytest.raises(DuplicateRequestId) as excinfo:
            client.put(client.identity.public_identity, request_id="1234567")
        assert str(excinfo.value) == "request ID already exists"
        assert excinfo.value.request_id == "1234567"
Пример #10
0
def test_header_content_type(client: Client,
                             mocked_requests_200: respx.MockTransport,
                             entity: Entity) -> None:
    """PUT request content-type is JSON."""
    _ = client.put(entity)
    http_request, _ = mocked_requests_200["create_entity"].calls[0]
    assert http_request.headers["content-type"] == "application/json"
Пример #11
0
def test_create_asset_claims_with_endorsement(alice_client: Client,
                                              existing_asset: Asset) -> None:
    """Create asset claims and (self-) endorsements on an unique asset all at once."""
    claims = [b"claim-1", b"claim-2"]

    response = alice_client.put(existing_asset,
                                claims=claims,
                                endorse=True,
                                create_claims=True)

    prefix = "/".join((
        "/api/v1/asset-types",
        existing_asset.asset_type_id,
        "assets",
        existing_asset.asset_id,
        "claims",
    ))
    # Affected resources: for each endorsements we also created the claim.
    assert len(
        response.resources) == 2 * len(claims)  # type: ignore[union-attr]
    for c in [hashed_claim(c) for c in claims]:
        assert "/".join(
            (prefix, c)) in response.resources  # type: ignore[union-attr]
        assert ("/".join(
            (prefix, c, "endorsements", alice_client.identity.identity_id))
                in response.resources  # type: ignore[union-attr]
                )
Пример #12
0
def test_response(client: Client, mocked_requests_200: respx.MockTransport,
                  entity: Entity) -> None:
    """Platform response to the create an entity request."""
    request_id = str(uuid.uuid4())
    response = client.put(entity, request_id=request_id)
    assert response.proof == "/api/v1/proofs/" + request_id
    assert len(response.resources) == 1  # type: ignore[union-attr]
Пример #13
0
def test_create_asset_type(alice_client: Client,
                           asset_type: AssetType) -> None:
    """Create an asset types on an iov42 platform."""
    response = alice_client.put(asset_type)

    assert ("/".join(("/api/v1/asset-types", asset_type.asset_type_id
                      )) == response.resources[0]  # type: ignore[union-attr]
            )
Пример #14
0
def test_call_to_put_endpoint(client: Client,
                              mocked_requests_200: respx.MockTransport,
                              entity: Entity) -> None:
    """Corret endpoint is called once."""
    request_id = str(uuid.uuid4())
    _ = client.put(entity, request_id=request_id)
    http_request, _ = mocked_requests_200["create_entity"].calls[0]
    assert str(http_request.url).rsplit("/", 1)[1] == request_id
Пример #15
0
def create_asset_type(ctx: click.core.Context, identity: str,
                      asset_type_id: str, scale: int) -> None:
    """Create an asset type."""
    asset_type = AssetType(asset_type_id)
    id = _load_identity(identity)
    client = Client(ctx.obj["url"], id)
    _ = client.put(asset_type, request_id=ctx.obj["request_id"])
    print(f"asset_type_id: {asset_type_id}")
Пример #16
0
def test_raise_identity_already_exists(client: Client) -> None:
    """Raise exception when an identity already exists."""
    client.identity = PrivateIdentity(
        CryptoProtocol.SHA256WithECDSA.generate_private_key(), "test-1234")
    with respx.mock(base_url=PLATFORM_URL) as respx_mock:
        respx_mock.put(
            re.compile("/api/v1/requests/.*$"),
            status_code=400,
            content=
            ('{"errors":[{"errorCode":2602,"errorType":"AssetExistence",'
             '"message":"Another identity with address test-1234 already exists"}],'
             '"requestId":"1234567","proof":"/api/v1/proofs/23343456"}'),
        )
        with pytest.raises(EntityAlreadyExists) as excinfo:
            client.put(client.identity.public_identity, request_id="1234567")
        assert str(excinfo.value) == "identity 'test-1234' already exists"
        assert excinfo.value.request_id == "1234567"
Пример #17
0
def create_asset(ctx: click.core.Context, identity: str, asset_type_id: str,
                 asset_id: str) -> None:
    """Create an asset."""
    asset = Asset(asset_type_id=asset_type_id, asset_id=asset_id)
    id = _load_identity(identity)
    client = Client(ctx.obj["url"], id)
    _ = client.put(asset, request_id=ctx.obj["request_id"])
    print(f"asset_id: {asset}")
Пример #18
0
def test_iov42_headers(client: Client,
                       mocked_requests_200: respx.MockTransport,
                       entity: Entity) -> None:
    """Authentication and authorisations are created with the request."""
    _ = client.put(entity)

    http_request, _ = mocked_requests_200["create_entity"].calls[0]
    assert "x-iov42-authorisations" in [*http_request.headers]
    assert "x-iov42-authentication" in [*http_request.headers]
Пример #19
0
def test_response_identity(
    client: Client,
    mocked_requests_200: respx.MockTransport,
) -> None:
    """Platform response to the request to create an identity."""
    response = client.put(client.identity.public_identity)
    assert response.resources == [  # type: ignore[union-attr]
        "/api/v1/identities/" + client.identity.identity_id
    ]
Пример #20
0
def test_response_asset_type(
    client: Client,
    mocked_requests_200: respx.MockTransport,
) -> None:
    """Platform response to the request to create an asset type."""
    entity = AssetType()
    response = client.put(entity)
    assert response.resources == [
        "/api/v1/asset-types/" + entity.asset_type_id
    ]  # type: ignore[union-attr]
Пример #21
0
def create_identity(ctx: click.core.Context, identity_id: str,
                    crypto_protocol: str) -> None:
    """Create an identity."""
    private_key = generate_private_key(crypto_protocol)
    identity = PrivateIdentity(private_key, identity_id)
    client = Client(ctx.obj["url"], identity)

    _ = client.put(identity.public_identity, request_id=ctx.obj["request_id"])

    print(_identity_json(identity))
Пример #22
0
def test_generated_request_id(client: Client,
                              mocked_requests_200: respx.MockTransport,
                              entity: Entity) -> None:
    """If no request ID is provided a UUID is generated."""
    _ = client.put(entity)
    http_request, _ = mocked_requests_200["create_entity"].calls[0]
    # We have to call read(), otherwise we get an httpx.RequestNoRead reading
    # the content (see https://github.com/lundberg/respx/issues/83).
    content = json.loads(http_request.read())
    assert uuid.UUID(content["requestId"])
Пример #23
0
def test_create_asset(alice_client: Client,
                      existing_asset_type_id: str) -> None:
    """Create an unique asset on an iov42 platform."""
    asset = Asset(asset_type_id=existing_asset_type_id)

    response = alice_client.put(asset)

    assert ("/".join(
        ("/api/v1/asset-types", asset.asset_type_id, "assets",
         asset.asset_id)) == response.resources[0]  # type: ignore[union-attr]
            )
Пример #24
0
def test_response_asset(
    client: Client,
    mocked_requests_200: respx.MockTransport,
) -> None:
    """Platform response to the request to create an asset type."""
    entity = Asset(asset_type_id=str(uuid.uuid4()))
    response = client.put(entity)
    assert response.resources == [  # type: ignore[union-attr]
        "/".join(("/api/v1/asset-types", entity.asset_type_id, "assets",
                  entity.asset_id))
    ]
Пример #25
0
def test_create_account(alice_client: Client,
                        existing_quantifiable_asset_type_id: str) -> None:
    """Create an account on an iov42 platform."""
    account = Asset(asset_type_id=existing_quantifiable_asset_type_id,
                    quantity=0)  # type: ignore[arg-type]

    response = alice_client.put(account)

    assert ("/".join((
        "/api/v1/asset-types", account.asset_type_id, "assets",
        account.asset_id)) == response.resources[0]  # type: ignore[union-attr]
            )
Пример #26
0
def test_authentication_header(client: Client,
                               mocked_requests_200: respx.MockTransport,
                               entity: Entity) -> None:
    """x-iov42-authentication header is signed by the client's identity."""
    _ = client.put(entity)

    http_request, _ = mocked_requests_200["create_entity"].calls[0]
    authentication = json.loads(
        iov42_decode(http_request.headers["x-iov42-authentication"].encode()))
    assert authentication["identityId"] == client.identity.identity_id
    assert authentication[
        "protocolId"] == client.identity.private_key.protocol.name
Пример #27
0
def test_empty_claims_header(
    client: Client,
    mocked_requests_200: respx.MockTransport,
    entity: Entity,
) -> None:
    """Request to create endorsements against an entity contains empty 'x-iov42-claims' header."""
    claims = [b"claim-1"]
    _ = client.put(entity, claims=claims, endorse=True)
    http_request, _ = mocked_requests_200["create_entity"].calls[0]
    claims_header = json.loads(
        iov42_decode(http_request.headers["x-iov42-claims"]))
    assert claims_header == {}
Пример #28
0
def test_3rd_party_endorsements_on_asset(
    bob_client: Client,
    existing_asset: Asset,
    existing_asset_claims: List[bytes],
) -> None:
    """Bob endorrses claims on Alice's unique asset."""
    response = bob_client.put(existing_asset,
                              claims=existing_asset_claims,
                              endorse=True)

    for r in response.resources:  # type: ignore[union-attr]
        if "endorsements/" in r:
            assert "endorsements/" + bob_client.identity.identity_id in r
Пример #29
0
def test_create_identity_claims_and_endorsements(alice_client: Client) -> None:
    """Create claims and endorsements against its own identity."""
    claims = [b"alice-claim-27", b"alice-claim-28"]

    response = alice_client.put(
        alice_client.identity.public_identity,
        claims=claims,
        endorse=True,
        create_claims=True,
    )

    # Affected resources: for each endorsements we also created the claim.
    assert len(
        response.resources) == 2 * len(claims)  # type: ignore[union-attr]
Пример #30
0
def test_authorisations_signature(client: Client,
                                  mocked_requests_200: respx.MockTransport,
                                  entity: Entity) -> None:
    """Signature of x-iov42-authorisations header is the signed request content."""
    _ = client.put(entity)

    http_request, _ = mocked_requests_200["create_entity"].calls[0]
    authorisations = json.loads(
        iov42_decode(http_request.headers["x-iov42-authorisations"].encode()))
    try:
        content = http_request.read()
        client.identity.verify_signature(authorisations[0]["signature"],
                                         content)
    except InvalidSignature:
        pytest.fail("Signature verification failed")