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 step1_expiration_date = None else: # Administration explicitly created an organization, # we shouldn't be able to overwrite it step1_token = "123" step1_expiration_date = pendulum.now().add(days=1) if flavour != "no_create": await backend.organization.create( id=neworg.organization_id, bootstrap_token=step1_token, expiration_date=step1_expiration_date, ) # 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 assert org.expiration_date == step1_expiration_date else: assert org.root_verify_key == neworg.root_verify_key assert org.bootstrap_token == empty_token assert org.expiration_date is None
async def test_organization_create_and_bootstrap( webhook_spy, backend, organization_factory, local_device_factory, alice, administration_backend_sock, apiv1_backend_sock_factory, ): neworg = organization_factory("NewOrg") # 1) Create organization, note this means `neworg.bootstrap_token` # will contain an invalid token rep = await organization_create(administration_backend_sock, neworg.organization_id) assert rep == {"status": "ok", "bootstrap_token": ANY} bootstrap_token = rep["bootstrap_token"] # 2) Bootstrap organization # Use an existing user name to make sure they didn't mix together newalice = local_device_factory("alice@dev1", 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=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", }, )]
async def test_organization_create_and_bootstrap( backend, organization_factory, local_device_factory, alice, administration_backend_sock, apiv1_backend_sock_factory, ): neworg = organization_factory("NewOrg") # 1) Create organization, note this means `neworg.bootstrap_token` # will contain an invalid token rep = await organization_create(administration_backend_sock, neworg.organization_id) assert rep == {"status": "ok", "bootstrap_token": ANY} bootstrap_token = rep["bootstrap_token"] # 2) Bootstrap organization # Use an existing user name to make sure they didn't mix together newalice = local_device_factory("alice@dev1", 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=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"} # 3) Now our new device can connect the backend async with apiv1_backend_sock_factory(backend, newalice) as sock: await ping(sock) # 4) Make sure alice from the other organization is still working async with apiv1_backend_sock_factory(backend, alice) as sock: await ping(sock)
async def test_organization_recreate_and_bootstrap( backend, organization_factory, local_device_factory, administration_backend_sock, apiv1_backend_sock_factory, ): neworg = organization_factory("NewOrg") rep = await organization_create(administration_backend_sock, neworg.organization_id) assert rep == {"status": "ok", "bootstrap_token": ANY} bootstrap_token1 = rep["bootstrap_token"] # Can recreate the organization as long as it hasn't been bootstrapped yet rep = await organization_create(administration_backend_sock, neworg.organization_id) assert rep == {"status": "ok", "bootstrap_token": ANY} bootstrap_token2 = rep["bootstrap_token"] assert bootstrap_token1 != bootstrap_token2 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: # Old token is now invalid rep = await organization_bootstrap( sock, bootstrap_token1, backend_newalice.user_certificate, backend_newalice_first_device.device_certificate, neworg.root_verify_key, ) assert rep == {"status": "not_found"} rep = await organization_bootstrap( sock, bootstrap_token2, backend_newalice.user_certificate, backend_newalice_first_device.device_certificate, neworg.root_verify_key, ) assert rep == {"status": "ok"} # Now we are no longer allowed to re-create the organization rep = await organization_create(administration_backend_sock, neworg.organization_id) assert rep == {"status": "already_exists"}
async def test_organization_with_expiration_date_create_and_bootstrap( backend, organization_factory, local_device_factory, alice, administration_backend_sock, apiv1_backend_sock_factory, ): neworg = organization_factory("NewOrg") # 1) Create organization, note this means `neworg.bootstrap_token` # will contain an invalid token with freeze_time("2000-01-01"): expiration_date = pendulum.datetime(2000, 1, 2) rep = await organization_create(administration_backend_sock, neworg.organization_id, expiration_date=expiration_date) assert rep == { "status": "ok", "bootstrap_token": ANY, "expiration_date": expiration_date } bootstrap_token = rep["bootstrap_token"] # 2) Bootstrap organization # Use an existing user name to make sure they didn't mix together newalice = local_device_factory("alice@dev1", 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, backend_newalice.user_certificate, backend_newalice_first_device.device_certificate, neworg.root_verify_key, ) assert rep == {"status": "ok"}
async def test_organization_with_expiration_date_create_and_bootstrap( backend, organization_factory, local_device_factory, alice, administration_backend_sock, apiv1_backend_sock_factory, ): neworg = organization_factory("NewOrg") # 1) Create organization, note this means `neworg.bootstrap_token` # will contain an invalid token with freeze_time("2000-01-01"): expiration_date = pendulum.Pendulum(2000, 1, 2) rep = await organization_create(administration_backend_sock, neworg.organization_id, expiration_date=expiration_date) assert rep == { "status": "ok", "bootstrap_token": ANY, "expiration_date": expiration_date } bootstrap_token = rep["bootstrap_token"] # 2) Bootstrap organization # Use an existing user name to make sure they didn't mix together newalice = local_device_factory("alice@dev1", 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, backend_newalice.user_certificate, backend_newalice_first_device.device_certificate, neworg.root_verify_key, ) assert rep == {"status": "ok"} # 3) Now our new device can connect the backend async with apiv1_backend_sock_factory(backend, newalice) as sock: await ping(sock) # 4) Make sure alice from the other organization is still working async with apiv1_backend_sock_factory(backend, alice) as sock: await ping(sock) # 5) Now advance after the expiration with freeze_time("2000-01-02"): # Both anonymous and authenticated connections are refused with pytest.raises(HandshakeOrganizationExpired): async with apiv1_backend_sock_factory(backend, newalice): pass with pytest.raises(HandshakeOrganizationExpired): async with apiv1_backend_sock_factory(backend, neworg.organization_id): pass
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. await aqtbot.key_click(gui, "o", QtCore.Qt.ControlModifier, 200) co_w = await catch_create_org_widget() await aqtbot.wait_until(co_w.user_widget.isVisible) await aqtbot.key_clicks(co_w.user_widget.line_edit_user_full_name, "Gordon Freeman") await aqtbot.key_clicks(co_w.user_widget.line_edit_user_email, "*****@*****.**") def _user_widget_ready(): assert co_w.user_widget.line_edit_org_name.text( ) == org.organization_id assert co_w.user_widget.line_edit_org_name.isReadOnly() is True await aqtbot.wait_until(_user_widget_ready) await aqtbot.mouse_click(co_w.user_widget.check_accept_contract, QtCore.Qt.LeftButton) await aqtbot.mouse_click(co_w.button_validate, QtCore.Qt.LeftButton) await aqtbot.wait_until(co_w.device_widget.isVisible) await aqtbot.key_clicks(co_w.device_widget.line_edit_device, "HEV") await aqtbot.key_clicks( co_w.device_widget.widget_password.line_edit_password, "nihilanth") await aqtbot.key_clicks( co_w.device_widget.widget_password.line_edit_password_check, "nihilanth") await 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)