Ejemplo n.º 1
0
    async def _concurrent_create(backend, user):
        backend_user, backend_first_device = local_device_to_backend_user(
            user, alice)
        try:
            await backend.user.create_user(coolorg.organization_id,
                                           backend_user, backend_first_device)
            results.append(None)

        except Exception as exc:
            results.append(exc)
Ejemplo n.º 2
0
async def test_concurrency_bootstrap_organization(postgresql_url,
                                                  backend_factory, coolorg,
                                                  alice):
    results = []

    backend_user, backend_first_device = local_device_to_backend_user(
        alice, coolorg)

    async def _concurrent_boostrap(backend):
        try:
            await backend.organization.bootstrap(
                coolorg.organization_id,
                backend_user,
                backend_first_device,
                coolorg.bootstrap_token,
                coolorg.root_verify_key,
            )
            results.append(None)

        except Exception as exc:
            results.append(exc)

    async with backend_factory(config={
            "db_url": postgresql_url,
            "db_max_connections": 10
    },
                               populated=False) as backend:
        # Create the organization
        await backend.organization.create(coolorg.organization_id,
                                          coolorg.bootstrap_token)

        # Concurrent bootstrap
        with ensure_pg_transaction_concurrency_barrier(concurrency=10):
            async with trio.open_nursery() as nursery:
                for _ in range(10):
                    nursery.start_soon(_concurrent_boostrap, backend)

    assert len(results) == 10
    assert len([
        r for r in results
        if isinstance(r, OrganizationAlreadyBootstrappedError)
    ]) == 9

    async with triopg.connect(postgresql_url) as conn:
        res = await conn.fetchrow("SELECT count(*) FROM organization")
        assert res["count"] == 1
        res = await conn.fetchrow("SELECT count(*) FROM user_")
        assert res["count"] == 1
        res = await conn.fetchrow("SELECT count(*) FROM device")
        assert res["count"] == 1
Ejemplo n.º 3
0
async def test_organization_spontaneous_bootstrap(
    backend, organization_factory, local_device_factory, apiv1_backend_sock_factory, flavour
):
    neworg = organization_factory("NewOrg")
    # Spontaneous bootstrap must have empty token
    empty_token = ""

    # Step 1: organization creation (if needed)

    if flavour == "create_same_token":
        # Basically pretent we already tried the spontaneous
        # bootstrap but got interrupted
        step1_token = empty_token
    else:
        # Administration explicitly created an organization,
        # we shouldn't be able to overwrite it
        step1_token = "123"
    if flavour != "no_create":
        await backend.organization.create(id=neworg.organization_id, bootstrap_token=step1_token)

    # Step 2: organization bootstrap

    newalice = local_device_factory(org=neworg, profile=UserProfile.ADMIN)
    backend_newalice, backend_newalice_first_device = local_device_to_backend_user(newalice, neworg)
    async with apiv1_backend_sock_factory(backend, neworg.organization_id) as sock:
        rep = await organization_bootstrap(
            sock,
            empty_token,
            backend_newalice.user_certificate,
            backend_newalice_first_device.device_certificate,
            neworg.root_verify_key,
        )
        if flavour == "create_different_token":
            assert rep == {"status": "not_found"}
        else:
            assert rep == {"status": "ok"}

    # Check organization informations

    org = await backend.organization.get(id=neworg.organization_id)
    if flavour == "create_different_token":
        assert org.root_verify_key is None
        assert org.bootstrap_token == step1_token
    else:
        assert org.root_verify_key == neworg.root_verify_key
        assert org.bootstrap_token == empty_token
Ejemplo n.º 4
0
async def test_concurrency_create_user(postgresql_url, backend_factory,
                                       backend_data_binder_factory, coolorg,
                                       alice, bob):
    results = []

    backend_user, backend_first_device = local_device_to_backend_user(
        bob, alice)

    async def _concurrent_create(backend):
        try:
            await backend.user.create_user(coolorg.organization_id,
                                           backend_user, backend_first_device)
            results.append(None)

        except Exception as exc:
            results.append(exc)

    async with backend_factory(config={
            "db_url": postgresql_url,
            "db_max_connections": 10
    },
                               populated=False) as backend:
        # Create&bootstrap the organization
        binder = backend_data_binder_factory(backend)
        await binder.bind_organization(coolorg, alice)

        # Concurrent user creation
        with ensure_pg_transaction_concurrency_barrier(concurrency=10):
            async with trio.open_nursery() as nursery:
                for _ in range(10):
                    nursery.start_soon(_concurrent_create, backend)

    assert len(results) == 10
    assert len([r for r in results
                if isinstance(r, UserAlreadyExistsError)]) == 9

    async with triopg.connect(postgresql_url) as conn:
        res = await conn.fetchrow("SELECT count(*) FROM organization")
        assert res["count"] == 1
        res = await conn.fetchrow(
            "SELECT count(*) FROM user_ WHERE user_id = 'bob'")
        assert res["count"] == 1
        res = await conn.fetchrow(
            "SELECT count(*) FROM device WHERE user_ = (SELECT _id FROM user_ WHERE user_id = 'bob')"
        )
        assert res["count"] == 1
Ejemplo n.º 5
0
 async def _do_bootstrap(task_status=trio.TASK_STATUS_IGNORED):
     newalice = local_device_factory(
         org=neworg, profile=UserProfile.ADMIN, base_human_handle="alice <*****@*****.**>"
     )
     backend_newalice, backend_newalice_first_device = local_device_to_backend_user(
         newalice, neworg
     )
     async with apiv1_backend_sock_factory(backend, neworg.organization_id) as sock:
         task_status.started()
         await unleash_bootstraps.wait()
         rep = await organization_bootstrap(
             sock=sock,
             bootstrap_token=empty_token,
             user_certificate=backend_newalice.user_certificate,
             device_certificate=backend_newalice_first_device.device_certificate,
             redacted_user_certificate=backend_newalice.redacted_user_certificate,
             redacted_device_certificate=backend_newalice_first_device.redacted_device_certificate,
             root_verify_key=neworg.root_verify_key,
         )
         results[rep["status"]] += 1
Ejemplo n.º 6
0
async def test_create_organization_already_bootstrapped(
    aqtbot,
    running_backend,
    catch_create_org_widget,
    autoclose_dialog,
    gui,
    monkeypatch,
    organization_factory,
    local_device_factory,
    alice,
):
    org = organization_factory()
    backend_user, backend_first_device = local_device_to_backend_user(
        alice, org)
    bootstrap_token = "123456"
    await running_backend.backend.organization.create(org.organization_id,
                                                      bootstrap_token, None)
    await running_backend.backend.organization.bootstrap(
        org.organization_id,
        backend_user,
        backend_first_device,
        bootstrap_token,
        org.root_verify_key,
    )

    org_bs_addr = BackendOrganizationBootstrapAddr.build(
        running_backend.addr, org.organization_id, bootstrap_token)

    monkeypatch.setattr("parsec.core.gui.main_window.get_text_input",
                        lambda *args, **kwargs: (str(org_bs_addr)))

    # The org bootstrap window is usually opened using a sub-menu.
    # Sub-menus can be a bit challenging to open in tests so we cheat
    # using the keyboard shortcut Ctrl+O that has the same effect.
    aqtbot.key_click(gui, "o", QtCore.Qt.ControlModifier, 200)

    co_w = await catch_create_org_widget()
    await aqtbot.wait_until(
        lambda: isinstance(co_w.current_widget, CreateOrgUserInfoWidget))

    await aqtbot.key_clicks(co_w.current_widget.line_edit_user_full_name,
                            "Gordon Freeman")
    await aqtbot.key_clicks(co_w.current_widget.line_edit_user_email,
                            "*****@*****.**")
    await aqtbot.key_clicks(co_w.current_widget.line_edit_device, "HEV")

    def _user_widget_ready():
        assert co_w.current_widget.line_edit_org_name.text() == str(
            org.organization_id)
        assert co_w.current_widget.line_edit_org_name.isReadOnly() is True

    await aqtbot.wait_until(_user_widget_ready)

    aqtbot.mouse_click(co_w.current_widget.check_accept_contract,
                       QtCore.Qt.LeftButton)
    aqtbot.mouse_click(co_w.button_validate, QtCore.Qt.LeftButton)

    def _modal_shown():
        assert autoclose_dialog.dialogs == [
            ("Error", "This bootstrap link was already used.")
        ]

    await aqtbot.wait_until(_modal_shown)
Ejemplo n.º 7
0
async def test_organization_bootstrap(
    webhook_spy,
    backend,
    organization_factory,
    local_device_factory,
    alice,
    apiv1_backend_sock_factory,
    backend_sock_factory,
):
    neworg = organization_factory("NewOrg")
    await backend.organization.create(
        id=neworg.organization_id, bootstrap_token=neworg.bootstrap_token
    )

    # 1) Bootstrap organization

    # Use an existing user name to make sure they didn't mix together
    newalice = local_device_factory(alice.device_id, neworg, profile=UserProfile.ADMIN)
    backend_newalice, backend_newalice_first_device = local_device_to_backend_user(newalice, neworg)

    async with apiv1_backend_sock_factory(backend, neworg.organization_id) as sock:
        rep = await organization_bootstrap(
            sock,
            bootstrap_token=neworg.bootstrap_token,
            user_certificate=backend_newalice.user_certificate,
            device_certificate=backend_newalice_first_device.device_certificate,
            root_verify_key=neworg.root_verify_key,
            redacted_user_certificate=backend_newalice.redacted_user_certificate,
            redacted_device_certificate=backend_newalice_first_device.redacted_device_certificate,
        )
    assert rep == {"status": "ok"}

    # Ensure webhook has been triggered
    assert webhook_spy == [
        (
            "http://example.com:888888/webhook",
            {
                "device_id": "alice@dev1",
                "device_label": "My dev1 machine",
                "human_email": "*****@*****.**",
                "human_label": "Alicey McAliceFace",
                "organization_id": "NewOrg",
            },
        )
    ]

    # 2) Now our new device can connect the backend

    async with backend_sock_factory(backend, newalice) as sock:
        await ping(sock)

    # 3) Make sure alice from the other organization is still working

    async with backend_sock_factory(backend, alice) as sock:
        await ping(sock)

    # 4) Finally, check the resulting data in the backend
    backend_user, backend_device = await backend.user.get_user_with_device(
        newalice.organization_id, newalice.device_id
    )
    assert backend_user == backend_newalice
    assert backend_device == backend_newalice_first_device
Ejemplo n.º 8
0
async def test_concurrency_pki_enrollment_accept(postgresql_url,
                                                 backend_factory,
                                                 backend_data_binder_factory,
                                                 coolorg, alice, bob):
    results = []
    enrollment_id = uuid4()

    backend_user, backend_first_device = local_device_to_backend_user(
        bob, alice)

    async def _concurrent_enrollment_accept(backend):
        try:
            await backend.pki.accept(
                organization_id=coolorg.organization_id,
                enrollment_id=enrollment_id,
                accepter_der_x509_certificate=b"whatever",
                accept_payload_signature=b"whatever",
                accept_payload=b"whatever",
                accepted_on=pendulum_now(),
                user=backend_user,
                first_device=backend_first_device,
            )
            results.append(None)

        except AssertionError:
            # Improve pytest --pdb behavior
            raise

        except Exception as exc:
            results.append(exc)

    async with backend_factory(config={
            "db_url": postgresql_url,
            "db_max_connections": 10
    },
                               populated=False) as backend:
        # Create&bootstrap the organization
        binder = backend_data_binder_factory(backend)
        await binder.bind_organization(coolorg, alice)

        # Create the PKI enrollment
        await backend.pki.submit(
            organization_id=coolorg.organization_id,
            enrollment_id=enrollment_id,
            force=False,
            submitter_der_x509_certificate=b"whatever",
            submitter_der_x509_certificate_email="whatever",
            submit_payload_signature=b"whatever",
            submit_payload=b"whatever",
            submitted_on=pendulum_now(),
        )

        # Concurrent PKI enrollement accept
        with ensure_pg_transaction_concurrency_barrier(concurrency=10):
            async with trio.open_nursery() as nursery:
                for _ in range(10):
                    nursery.start_soon(_concurrent_enrollment_accept, backend)

    assert len(results) == 10
    assert len([
        r for r in results
        if isinstance(r, PkiEnrollmentNoLongerAvailableError)
    ]) == 9

    async with triopg.connect(postgresql_url) as conn:
        res = await conn.fetchrow("SELECT count(*) FROM organization")
        assert res["count"] == 1
        res = await conn.fetchrow(
            "SELECT count(*) FROM user_ WHERE user_id = 'bob'")
        assert res["count"] == 1
        res = await conn.fetchrow(
            "SELECT count(*) FROM device WHERE user_ = (SELECT _id FROM user_ WHERE user_id = 'bob')"
        )
        assert res["count"] == 1
        res = await conn.fetchrow("SELECT count(*) FROM pki_enrollment")
        assert res["count"] == 1
        res = await conn.fetchrow("SELECT enrollment_state FROM pki_enrollment"
                                  )
        res["enrollment_state"] == "ACCEPTED"