Group/space multi-recipient encryption via per-group Keycloak identities #93
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/multi-recipient"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #18
Approved by Manuel's review (2026-07-31, relayed by Nikola; single-recipient confirmed staying for personal files, 2026-08-03).
Design: unique key per group, mirroring the per-user model exactly. Every shared space gets its own age X25519 identity stored in the Keycloak group's attributes (same attribute name as users, lazily provisioned on the space's first encrypted operation). Content under
/spaces/<name>/encrypts to the group recipient (+ recovery); any member's read resolves the same group identity. Authorization stays with scope + the IdP — the group key provides confidentiality against the storage backend, so membership changes take effect instantly with zero re-encryption: joining grants the space's whole history, leaving revokes it.Key-scope plumbing: the scope travels in the request context (
WithGroup/GroupFrom), derived from the path by the storage decorators, and forwarded over the crypto-role wire asX-Cairn-Groupalongside the existingX-Cairn-User— theContentCrypterinterface and both role deployments are untouched. (One wrinkle:Server.handle'sencrypt boolparameter shadows the package name, hence theencscopeimport alias.)Cross-boundary moves re-encrypt. Rename/Copy across the personal↔space (or space↔space) boundary decrypts with the source scope and encrypts to the destination scope, so a file moved into a space becomes member-readable and a copy taken out becomes private to the taker. Same-scope renames stay pure metadata moves (test-pinned: ciphertext byte-identical). This also makes trash coherent: deleting a space file re-keys it to the deleting user; restore re-keys it back to the space. Documented limitation: directory renames across the boundary pass through un-re-encrypted — move files, not folders, across scopes.
Tests: member-can-read/non-member-cannot, cross-scope rename+copy re-encryption, same-scope no-rewrite, and Keycloak group custody (lazy provision into group attributes + member decrypt roundtrip) against a fake Admin API.
Deployment note: the
cairn-keycustodyservice account needs group read/manage in realm-management (manage-usersnormally covers it; addquery-groups/view-usersif group lookups 403 on the dogfood).