예제 #1
0
async def test_create_certif_too_old(alice, alice_backend_sock):
    now = pendulum.now()

    # Generate a certificate

    realm_id = RealmID.from_hex("C0000000000000000000000000000000")
    certif = RealmRoleCertificateContent.build_realm_root_certif(
        author=alice.device_id, timestamp=now,
        realm_id=realm_id).dump_and_sign(alice.signing_key)

    # Create a realm a tiny bit too late

    later = now.add(seconds=BALLPARK_CLIENT_LATE_OFFSET)
    with freeze_time(later):
        rep = await realm_create(alice_backend_sock, certif)
    assert rep == {
        "status": "bad_timestamp",
        "backend_timestamp": later,
        "ballpark_client_early_offset": BALLPARK_CLIENT_EARLY_OFFSET,
        "ballpark_client_late_offset": BALLPARK_CLIENT_LATE_OFFSET,
        "client_timestamp": now,
    }

    #  Create a realm late but right before the deadline

    later = now.add(seconds=BALLPARK_CLIENT_LATE_OFFSET, microseconds=-1)
    with freeze_time(later):
        rep = await realm_create(alice_backend_sock, certif)
    assert rep["status"] == "ok"

    # Generate a new certificate

    realm_id = RealmID.from_hex("C0000000000000000000000000000001")
    certif = RealmRoleCertificateContent.build_realm_root_certif(
        author=alice.device_id, timestamp=now,
        realm_id=realm_id).dump_and_sign(alice.signing_key)

    # Create a realm a tiny bit too soon

    sooner = now.subtract(seconds=BALLPARK_CLIENT_EARLY_OFFSET)
    with freeze_time(sooner):
        rep = await realm_create(alice_backend_sock, certif)
    assert rep == {
        "status": "bad_timestamp",
        "backend_timestamp": sooner,
        "ballpark_client_early_offset": BALLPARK_CLIENT_EARLY_OFFSET,
        "ballpark_client_late_offset": BALLPARK_CLIENT_LATE_OFFSET,
        "client_timestamp": now,
    }

    # Create a realm soon but after the limit

    sooner = now.subtract(seconds=BALLPARK_CLIENT_EARLY_OFFSET,
                          microseconds=-1)
    with freeze_time(sooner):
        rep = await realm_create(alice_backend_sock, certif)
    assert rep["status"] == "ok"
예제 #2
0
async def test_realm_create_not_allowed_for_outsider(backend, alice, alice_backend_sock):
    realm_id = UUID("C0000000000000000000000000000000")
    certif = RealmRoleCertificateContent.build_realm_root_certif(
        author=alice.device_id, timestamp=pendulum.now(), realm_id=realm_id
    ).dump_and_sign(alice.signing_key)
    rep = await realm_create(alice_backend_sock, certif, check_rep=False)
    assert rep == {"status": "not_allowed", "reason": "Outsider user cannot create realm"}
예제 #3
0
async def test_create_invalid_certif(backend, alice, bob, alice_backend_sock):
    realm_id = UUID("C0000000000000000000000000000000")
    certif = RealmRoleCertificateContent.build_realm_root_certif(
        author=bob.device_id, timestamp=pendulum.now(), realm_id=realm_id
    ).dump_and_sign(bob.signing_key)
    rep = await realm_create(alice_backend_sock, certif)
    assert rep == {
        "status": "invalid_certification",
        "reason": "Invalid certification data (Signature was forged or corrupt).",
    }
예제 #4
0
async def test_realm_create(backend, alice, alice_backend_sock):
    await events_subscribe(alice_backend_sock)

    realm_id = UUID("C0000000000000000000000000000000")
    certif = RealmRoleCertificateContent.build_realm_root_certif(
        author=alice.device_id, timestamp=pendulum.now(), realm_id=realm_id
    ).dump_and_sign(alice.signing_key)
    with backend.event_bus.listen() as spy:
        await realm_create(alice_backend_sock, certif)
        await spy.wait_with_timeout("realm.roles_updated")
예제 #5
0
async def _test_create_ok(backend, device, device_backend_sock):
    await events_subscribe(device_backend_sock)

    realm_id = RealmID.from_hex("C0000000000000000000000000000000")
    certif = RealmRoleCertificateContent.build_realm_root_certif(
        author=device.device_id, timestamp=pendulum.now(),
        realm_id=realm_id).dump_and_sign(device.signing_key)
    with backend.event_bus.listen() as spy:
        rep = await realm_create(device_backend_sock, certif)
        assert rep == {"status": "ok"}
        await spy.wait_with_timeout(BackendEvent.REALM_ROLES_UPDATED)
예제 #6
0
async def test_create_certif_too_old(alice, alice_backend_sock):
    realm_id = UUID("C0000000000000000000000000000000")
    now = pendulum.now()
    certif = RealmRoleCertificateContent.build_realm_root_certif(
        author=alice.device_id, timestamp=now,
        realm_id=realm_id).dump_and_sign(alice.signing_key)
    with freeze_time(now.add(seconds=TIMESTAMP_MAX_DT)):
        rep = await realm_create(alice_backend_sock, certif)
    assert rep == {
        "status": "invalid_certification",
        "reason": "Invalid timestamp in certification.",
    }
예제 #7
0
    async def create_realm(self, realm_id: EntryID):
        """
        Raises:
            FSError
            FSBackendOfflineError
        """
        certif = RealmRoleCertificateContent.build_realm_root_certif(
            author=self.device.device_id,
            timestamp=pendulum_now(),
            realm_id=realm_id).dump_and_sign(self.device.signing_key)

        rep = await self._backend_cmds("realm_create", certif)
        if rep["status"] == "already_exists":
            # It's possible a previous attempt to create this realm
            # succeeded but we didn't receive the confirmation, hence
            # we play idempotent here.
            return
        elif rep["status"] != "ok":
            raise FSError(f"Cannot create realm {realm_id}: `{rep['status']}`")
예제 #8
0
 async def _realm_factory(backend, author, realm_id=None, now=None):
     realm_id = realm_id or uuid4()
     now = now or pendulum_now()
     certif = RealmRoleCertificateContent.build_realm_root_certif(
         author=author.device_id, timestamp=now, realm_id=realm_id
     ).dump_and_sign(author.signing_key)
     with backend.event_bus.listen() as spy:
         await backend.realm.create(
             organization_id=author.organization_id,
             self_granted_role=RealmGrantedRole(
                 realm_id=realm_id,
                 user_id=author.user_id,
                 certificate=certif,
                 role=RealmRole.OWNER,
                 granted_by=author.device_id,
                 granted_on=now,
             ),
         )
         await spy.wait_with_timeout("realm.roles_updated")
     return realm_id
예제 #9
0
    async def create_realm(self, realm_id: EntryID) -> None:
        """
        Raises:
            FSError
            FSRemoteOperationError
            FSBackendOfflineError
        """
        timestamp = self.device.timestamp()
        certif = RealmRoleCertificateContent.build_realm_root_certif(
            author=self.device.device_id,
            timestamp=timestamp,
            realm_id=RealmID(realm_id.uuid)).dump_and_sign(
                self.device.signing_key)

        with translate_backend_cmds_errors():
            rep = await self.backend_cmds.realm_create(certif)

        if rep["status"] == "already_exists":
            # It's possible a previous attempt to create this realm
            # succeeded but we didn't receive the confirmation, hence
            # we play idempotent here.
            return
        elif rep["status"] != "ok":
            raise FSError(f"Cannot create realm {realm_id}: `{rep['status']}`")
예제 #10
0
    async def _outbound_sync_inner(self) -> bool:
        base_um = self.get_user_manifest()
        if not base_um.need_sync:
            return True

        # Make sure the corresponding realm has been created in the backend
        if base_um.is_placeholder:
            certif = RealmRoleCertificateContent.build_realm_root_certif(
                author=self.device.device_id,
                timestamp=pendulum_now(),
                realm_id=self.device.user_manifest_id,
            ).dump_and_sign(self.device.signing_key)

            try:
                rep = await self.backend_cmds.realm_create(certif)

            except BackendNotAvailable as exc:
                raise FSBackendOfflineError(str(exc)) from exc

            except BackendConnectionError as exc:
                raise FSError(f"Cannot create user manifest's realm in backend: {exc}") from exc

            if rep["status"] == "already_exists":
                # It's possible a previous attempt to create this realm
                # succeeded but we didn't receive the confirmation, hence
                # we play idempotent here.
                pass
            elif rep["status"] != "ok":
                raise FSError(f"Cannot create user manifest's realm in backend: {rep}")

        # Sync placeholders
        for w in base_um.workspaces:
            await self._workspace_minimal_sync(w)

        # Build vlob
        now = pendulum_now()
        to_sync_um = base_um.to_remote(author=self.device.device_id, timestamp=now)
        ciphered = to_sync_um.dump_sign_and_encrypt(
            author_signkey=self.device.signing_key, key=self.device.user_manifest_key
        )

        # Sync the vlob with backend
        try:
            # Note encryption_revision is always 1 given we never reencrypt
            # the user manifest's realm
            if to_sync_um.version == 1:
                rep = await self.backend_cmds.vlob_create(
                    self.user_manifest_id, 1, self.user_manifest_id, now, ciphered
                )
            else:
                rep = await self.backend_cmds.vlob_update(
                    1, self.user_manifest_id, to_sync_um.version, now, ciphered
                )

        except BackendNotAvailable as exc:
            raise FSBackendOfflineError(str(exc)) from exc

        except BackendConnectionError as exc:
            raise FSError(f"Cannot sync user manifest: {exc}") from exc

        if rep["status"] in ("already_exists", "bad_version"):
            # Concurrency error (handled by the caller)
            return False
        elif rep["status"] == "in_maintenance":
            raise FSWorkspaceInMaintenance(
                f"Cannot modify workspace data while it is in maintenance: {rep}"
            )
        elif rep["status"] != "ok":
            raise FSError(f"Cannot sync user manifest: {rep}")

        # Merge back the manifest in local
        async with self._update_user_manifest_lock:
            diverged_um = self.get_user_manifest()
            # Final merge could have been achieved by a concurrent operation
            if to_sync_um.version > diverged_um.base_version:
                merged_um = merge_local_user_manifests(diverged_um, to_sync_um)
                await self.set_user_manifest(merged_um)
            self.event_bus.send("fs.entry.synced", id=self.user_manifest_id)

        return True
예제 #11
0
async def test_create_realm_already_exists(alice, alice_backend_sock, realm):
    certif = RealmRoleCertificateContent.build_realm_root_certif(
        author=alice.device_id, timestamp=pendulum.now(),
        realm_id=realm).dump_and_sign(alice.signing_key)
    rep = await realm_create(alice_backend_sock, certif)
    assert rep == {"status": "already_exists"}