Exemple #1
0
async def test_link_file_unknown_org(core_config, gui_factory,
                                     autoclose_dialog, running_backend, alice):
    password = "******"
    save_device_with_password(core_config.config_dir, alice, password)

    # Cheating a bit but it does not matter, we just want a link that appears valid with
    # an unknown organization
    org_addr = BackendOrganizationAddr.build(
        running_backend.addr, "UnknownOrg",
        alice.organization_addr.root_verify_key)

    file_link = BackendOrganizationFileLinkAddr.build(
        org_addr, EntryID(), FsPath("/doesntmattereither"))

    gui = await gui_factory(core_config=core_config,
                            start_arg=file_link.to_url())
    lw = gui.test_get_login_widget()

    assert len(autoclose_dialog.dialogs) == 1
    assert autoclose_dialog.dialogs[0][0] == "Error"
    assert autoclose_dialog.dialogs[0][1] == translate(
        "TEXT_FILE_LINK_NOT_IN_ORG_organization").format(
            organization="UnknownOrg")

    accounts_w = lw.widget.layout().itemAt(0).widget()
    assert accounts_w

    assert isinstance(accounts_w, LoginPasswordInputWidget)
Exemple #2
0
async def test_link_file_unknown_org(
    aqtbot, core_config, gui_factory, autoclose_dialog, running_backend, alice
):
    password = "******"
    save_device_with_password_in_config(core_config.config_dir, alice, password)

    # Cheating a bit but it does not matter, we just want a link that appears valid with
    # an unknown organization
    org_addr = BackendOrganizationAddr.build(
        running_backend.addr, OrganizationID("UnknownOrg"), alice.organization_addr.root_verify_key
    )

    file_link = BackendOrganizationFileLinkAddr.build(
        organization_addr=org_addr, workspace_id=EntryID.new(), encrypted_path=b"<whatever>"
    )

    gui = await gui_factory(core_config=core_config, start_arg=file_link.to_url())
    lw = gui.test_get_login_widget()

    assert len(autoclose_dialog.dialogs) == 1
    assert autoclose_dialog.dialogs[0][0] == "Error"
    assert autoclose_dialog.dialogs[0][1] == translate(
        "TEXT_FILE_LINK_NOT_IN_ORG_organization"
    ).format(organization="UnknownOrg")

    def _devices_listed():
        assert lw.widget.layout().count() > 0

    await aqtbot.wait_until(_devices_listed)

    accounts_w = lw.widget.layout().itemAt(0).widget()
    assert accounts_w

    assert isinstance(accounts_w, LoginPasswordInputWidget)
Exemple #3
0
    async def finalize(self) -> "PkiEnrollmentFinalizedCtx":
        """
        Raises:
            PkiEnrollmentCertificateNotFoundError
            PkiEnrollmentCertificateCryptoError
            PkiEnrollmentCertificateError
            PkiEnrollmentCertificatePinCodeUnavailableError
            PkiEnrollmentLocalPendingCryptoError
        """
        signing_key, private_key = await pki_enrollment_load_local_pending_secret_part(
            config_dir=self.config_dir, enrollment_id=self.enrollment_id)

        # Create the local device
        organization_addr = BackendOrganizationAddr.build(
            backend_addr=BackendAddr(self.addr.hostname, self.addr.port,
                                     self.addr.use_ssl),
            organization_id=self.addr.organization_id,
            root_verify_key=self.accept_payload.root_verify_key,
        )
        new_device = generate_new_device(
            organization_addr=organization_addr,
            device_id=self.accept_payload.device_id,
            profile=self.accept_payload.profile,
            human_handle=self.accept_payload.human_handle,
            device_label=self.accept_payload.device_label,
            signing_key=signing_key,
            private_key=private_key,
        )

        return PkiEnrollmentFinalizedCtx(
            config_dir=self.config_dir,
            enrollment_id=self.enrollment_id,
            new_device=new_device,
            x509_certificate=self.x509_certificate,
        )
async def bootstrap_organization(
    cmds: APIV1_BackendAnonymousCmds,
    human_handle: Optional[HumanHandle],
    device_label: Optional[str],
) -> LocalDevice:
    root_signing_key = SigningKey.generate()
    root_verify_key = root_signing_key.verify_key

    organization_addr = BackendOrganizationAddr.build(
        backend_addr=cmds.addr,
        organization_id=cmds.addr.organization_id,
        root_verify_key=root_verify_key,
    )

    device = generate_new_device(
        organization_addr=organization_addr,
        profile=UserProfile.ADMIN,
        human_handle=human_handle,
        device_label=device_label,
    )

    now = pendulum_now()
    user_certificate = UserCertificateContent(
        author=None,
        timestamp=now,
        user_id=device.user_id,
        human_handle=device.human_handle,
        public_key=device.public_key,
        profile=device.profile,
    )
    redacted_user_certificate = user_certificate.evolve(human_handle=None)
    device_certificate = DeviceCertificateContent(
        author=None,
        timestamp=now,
        device_id=device.device_id,
        device_label=device.device_label,
        verify_key=device.verify_key,
    )
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    user_certificate = user_certificate.dump_and_sign(root_signing_key)
    redacted_user_certificate = redacted_user_certificate.dump_and_sign(
        root_signing_key)
    device_certificate = device_certificate.dump_and_sign(root_signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        root_signing_key)

    rep = await cmds.organization_bootstrap(
        organization_id=cmds.addr.organization_id,
        bootstrap_token=cmds.addr.token,
        root_verify_key=root_verify_key,
        user_certificate=user_certificate,
        device_certificate=device_certificate,
        redacted_user_certificate=redacted_user_certificate,
        redacted_device_certificate=redacted_device_certificate,
    )
    _check_rep(rep, step_name="organization bootstrap")

    return device
Exemple #5
0
async def test_handshake_unknown_organization(running_backend, coolorg):
    unknown_org_addr = BackendOrganizationAddr.build(
        backend_addr=coolorg.addr, organization_id="dummy", root_verify_key=coolorg.root_verify_key
    )
    with pytest.raises(BackendConnectionRefused) as exc:
        async with apiv1_backend_anonymous_cmds_factory(unknown_org_addr) as cmds:
            await cmds.ping()
    assert str(exc.value) == "Invalid handshake information"
Exemple #6
0
    async def do_claim_user(
        self,
        requested_device_label: Optional[DeviceLabel],
        requested_human_handle: Optional[HumanHandle],
    ) -> LocalDevice:
        # User&device keys are generated here and kept in memory until the end of
        # the enrollment process. This mean we can lost it if something goes wrong.
        # This has no impact until step 4 (somewhere between data exchange and
        # confirmation exchange steps) where greeter upload our certificates in
        # the server.
        # This is considered acceptable given 1) the error window is small and
        # 2) if this occurs the inviter can revoke the user and retry the
        # enrollment process to fix this
        private_key = PrivateKey.generate()
        signing_key = SigningKey.generate()

        try:
            payload = InviteUserData(
                requested_device_label=requested_device_label,
                requested_human_handle=requested_human_handle,
                public_key=private_key.public_key,
                verify_key=signing_key.verify_key,
            ).dump_and_encrypt(key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Cannot generate InviteUserData payload") from exc

        rep = await self._cmds.invite_4_claimer_communicate(payload=payload)
        _check_rep(rep, step_name="step 4 (data exchange)")

        rep = await self._cmds.invite_4_claimer_communicate(payload=b"")
        _check_rep(rep, step_name="step 4 (confirmation exchange)")

        try:
            confirmation = InviteUserConfirmation.decrypt_and_load(
                rep["payload"], key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Invalid InviteUserConfirmation payload provided by peer"
            ) from exc

        organization_addr = BackendOrganizationAddr.build(
            backend_addr=self._cmds.addr.get_backend_addr(),
            organization_id=self._cmds.addr.organization_id,
            root_verify_key=confirmation.root_verify_key,
        )

        new_device = generate_new_device(
            organization_addr=organization_addr,
            device_id=confirmation.device_id,
            device_label=confirmation.device_label,
            human_handle=confirmation.human_handle,
            profile=confirmation.profile,
            private_key=private_key,
            signing_key=signing_key,
        )

        return new_device
Exemple #7
0
async def bootstrap_organization(
    addr: BackendOrganizationBootstrapAddr,
    human_handle: Optional[HumanHandle],
    device_label: Optional[DeviceLabel],
) -> LocalDevice:
    root_signing_key = SigningKey.generate()
    root_verify_key = root_signing_key.verify_key

    organization_addr = BackendOrganizationAddr.build(
        backend_addr=addr.get_backend_addr(),
        organization_id=addr.organization_id,
        root_verify_key=root_verify_key,
    )

    device = generate_new_device(
        organization_addr=organization_addr,
        profile=UserProfile.ADMIN,
        human_handle=human_handle,
        device_label=device_label,
    )

    timestamp = device.timestamp()
    user_certificate = UserCertificateContent(
        author=None,
        timestamp=timestamp,
        user_id=device.user_id,
        human_handle=device.human_handle,
        public_key=device.public_key,
        profile=device.profile,
    )
    redacted_user_certificate = user_certificate.evolve(human_handle=None)
    device_certificate = DeviceCertificateContent(
        author=None,
        timestamp=timestamp,
        device_id=device.device_id,
        device_label=device.device_label,
        verify_key=device.verify_key,
    )
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    user_certificate = user_certificate.dump_and_sign(root_signing_key)
    redacted_user_certificate = redacted_user_certificate.dump_and_sign(root_signing_key)
    device_certificate = device_certificate.dump_and_sign(root_signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(root_signing_key)

    rep = await failsafe_organization_bootstrap(
        addr=addr,
        root_verify_key=root_verify_key,
        user_certificate=user_certificate,
        device_certificate=device_certificate,
        redacted_user_certificate=redacted_user_certificate,
        redacted_device_certificate=redacted_device_certificate,
    )
    _check_rep(rep, step_name="organization bootstrap")

    return device
Exemple #8
0
    async def do_claim_user(
            self, requested_device_label: Optional[str],
            requested_human_handle: Optional[HumanHandle]) -> LocalDevice:
        private_key = PrivateKey.generate()
        signing_key = SigningKey.generate()

        try:
            payload = InviteUserData(
                requested_device_label=requested_device_label,
                requested_human_handle=requested_human_handle,
                public_key=private_key.public_key,
                verify_key=signing_key.verify_key,
            ).dump_and_encrypt(key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Cannot generate InviteUserData payload") from exc

        rep = await self._cmds.invite_4_claimer_communicate(payload=payload)
        if rep["status"] == "invalid_state":
            raise InvitePeerResetError()
        elif rep["status"] != "ok":
            raise InviteError(
                f"Backend error during step 4 (data exchange): {rep}")

        rep = await self._cmds.invite_4_claimer_communicate(payload=b"")
        if rep["status"] == "invalid_state":
            raise InvitePeerResetError()
        elif rep["status"] != "ok":
            raise InviteError(
                f"Backend error during step 4 (confirmation exchange): {rep}")

        try:
            confirmation = InviteUserConfirmation.decrypt_and_load(
                rep["payload"], key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Invalid InviteUserConfirmation payload provided by peer"
            ) from exc

        organization_addr = BackendOrganizationAddr.build(
            backend_addr=self._cmds.addr,
            organization_id=self._cmds.addr.organization_id,
            root_verify_key=confirmation.root_verify_key,
        )

        new_device = generate_new_device(
            organization_addr=organization_addr,
            device_id=confirmation.device_id,
            device_label=confirmation.device_label,
            human_handle=confirmation.human_handle,
            profile=confirmation.profile,
            private_key=private_key,
            signing_key=signing_key,
        )

        return new_device
Exemple #9
0
async def test_handshake_rvk_mismatch(running_backend, coolorg, otherorg):
    bad_rvk_org_addr = BackendOrganizationAddr.build(
        backend_addr=coolorg.addr,
        organization_id=coolorg.organization_id,
        root_verify_key=otherorg.root_verify_key,
    )
    with pytest.raises(BackendConnectionRefused) as exc:
        async with apiv1_backend_anonymous_cmds_factory(bad_rvk_org_addr) as cmds:
            await cmds.ping()
    assert str(exc.value) == "Root verify key for organization differs between client and server"
Exemple #10
0
async def test_handshake_unknown_organization(running_backend, alice):
    unknown_org_addr = BackendOrganizationAddr.build(
        backend_addr=alice.organization_addr.get_backend_addr(),
        organization_id=OrganizationID("dummy"),
        root_verify_key=alice.organization_addr.root_verify_key,
    )
    with pytest.raises(BackendConnectionRefused) as exc:
        async with backend_authenticated_cmds_factory(
                unknown_org_addr, alice.device_id, alice.signing_key) as cmds:
            await cmds.ping()
    assert str(exc.value) == "Invalid handshake information"
async def test_handshake_rvk_mismatch(running_backend, alice, otherorg):
    bad_rvk_org_addr = BackendOrganizationAddr.build(
        backend_addr=alice.organization_addr,
        organization_id=alice.organization_id,
        root_verify_key=otherorg.root_verify_key,
    )
    with pytest.raises(BackendConnectionRefused) as exc:
        async with backend_authenticated_cmds_factory(
            bad_rvk_org_addr, alice.device_id, alice.signing_key
        ) as cmds:
            await cmds.ping()
    assert str(exc.value) == "Root verify key for organization differs between client and server"
Exemple #12
0
def test_backend_organization_addr_good(base_url, expected, verify_key):
    org = OrganizationID("org")
    backend_addr = BackendAddr.from_url(base_url)
    addr = BackendOrganizationAddr.build(backend_addr,
                                         organization_id=org,
                                         root_verify_key=verify_key)
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]
    assert addr.organization_id == org
    assert addr.root_verify_key == verify_key

    addr2 = BackendOrganizationAddr.from_url(addr.to_url())
    assert addr == addr2
def test_build_addrs():
    backend_addr = BackendAddr.from_url(BackendAddrTestbed.url)
    assert backend_addr.hostname == "parsec.cloud.com"
    assert backend_addr.port == 443
    assert backend_addr.use_ssl is True

    organization_id = OrganizationID("MyOrg")
    root_verify_key = SigningKey.generate().verify_key

    organization_addr = BackendOrganizationAddr.build(
        backend_addr=backend_addr, organization_id=organization_id, root_verify_key=root_verify_key
    )
    assert organization_addr.organization_id == organization_id
    assert organization_addr.root_verify_key == root_verify_key

    organization_bootstrap_addr = BackendOrganizationBootstrapAddr.build(
        backend_addr=backend_addr,
        organization_id=organization_id,
        token="a0000000000000000000000000000001",
    )
    assert organization_bootstrap_addr.token == "a0000000000000000000000000000001"
    assert organization_bootstrap_addr.organization_id == organization_id

    organization_bootstrap_addr2 = BackendOrganizationBootstrapAddr.build(
        backend_addr=backend_addr, organization_id=organization_id, token=None
    )
    assert organization_bootstrap_addr2.organization_id == organization_id
    assert organization_bootstrap_addr2.token == ""

    organization_file_link_addr = BackendOrganizationFileLinkAddr.build(
        organization_addr=organization_addr,
        workspace_id=EntryID.from_hex("2d4ded12-7406-4608-833b-7f57f01156e2"),
        encrypted_path=b"<encrypted_payload>",
    )
    assert organization_file_link_addr.workspace_id == EntryID.from_hex(
        "2d4ded12-7406-4608-833b-7f57f01156e2"
    )
    assert organization_file_link_addr.encrypted_path == b"<encrypted_payload>"

    invitation_addr = BackendInvitationAddr.build(
        backend_addr=backend_addr,
        organization_id=organization_id,
        invitation_type=InvitationType.USER,
        token=InvitationToken.from_hex("a0000000000000000000000000000001"),
    )
    assert invitation_addr.organization_id == organization_id
    assert invitation_addr.token == InvitationToken.from_hex("a0000000000000000000000000000001")
    assert invitation_addr.invitation_type == InvitationType.USER
Exemple #14
0
    async def do_claim_device(
            self, requested_device_label: Optional[str]) -> LocalDevice:
        signing_key = SigningKey.generate()

        try:
            payload = InviteDeviceData(
                requested_device_label=requested_device_label,
                verify_key=signing_key.verify_key).dump_and_encrypt(
                    key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Cannot generate InviteDeviceData payload") from exc

        rep = await self._cmds.invite_4_claimer_communicate(payload=payload)
        _check_rep(rep, step_name="step 4 (data exchange)")

        rep = await self._cmds.invite_4_claimer_communicate(payload=b"")
        _check_rep(rep, step_name="step 4 (confirmation exchange)")

        try:
            confirmation = InviteDeviceConfirmation.decrypt_and_load(
                rep["payload"], key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Invalid InviteDeviceConfirmation payload provided by peer"
            ) from exc

        organization_addr = BackendOrganizationAddr.build(
            backend_addr=self._cmds.addr,
            organization_id=self._cmds.addr.organization_id,
            root_verify_key=confirmation.root_verify_key,
        )

        return LocalDevice(
            organization_addr=organization_addr,
            device_id=confirmation.device_id,
            device_label=confirmation.device_label,
            human_handle=confirmation.human_handle,
            profile=confirmation.profile,
            private_key=confirmation.private_key,
            signing_key=signing_key,
            user_manifest_id=confirmation.user_manifest_id,
            user_manifest_key=confirmation.user_manifest_key,
            local_symkey=SecretKey.generate(),
        )
Exemple #15
0
 def _correct_local_device_backend_addr(device):
     organization_addr = BackendOrganizationAddr.build(
         backend_addr,
         organization_id=device.organization_addr.organization_id,
         root_verify_key=device.organization_addr.root_verify_key,
     )
     return LocalDevice(
         organization_addr=organization_addr,
         device_id=device.device_id,
         device_label=device.device_label,
         human_handle=device.human_handle,
         signing_key=device.signing_key,
         private_key=device.private_key,
         profile=device.profile,
         user_manifest_id=device.user_manifest_id,
         user_manifest_key=device.user_manifest_key,
         local_symkey=device.local_symkey,
     )