aboutsummaryrefslogtreecommitdiffstats
path: root/src/access
Commit message (Collapse)AuthorAgeFilesLines
* rules: protocol maps judged by what is done to themtv3 days1-2/+46
| | | | | | | | | | | | | Review finding 7, first part: the protocol-map rules looked at paths, not actions. Any member could delete _continuum/members, /votes or /remakes whole, or rewrite another remake's proposal (its coordinator) and then write its decision. What holds the members' entries, votes and remake records, and a remake's record itself, are now made by a member only where there is none; a proposal is written only where there is none. Replacing or removing any of them is left to a user who may write there (the protocol writers). An abort asked for stays any member's.
* screen: a signature vouches for its change and what it builds ontv3 days1-8/+84
| | | | | | | | | | | | | | | Review finding 5: vouching by (actor, seq) isn't bound to a hash. A member can make a change under another member's actor at a seq that member's signature covers. The change is then taken as vouched, and if it breaks a rule, the honest member is refused as a whole and logged as the one whose own change broke the rules. A signature now vouches for its change and the changes of its actor it builds on: in the document, as before; among received changes, those it reaches through the batch's dependencies. A received change under an actor at a seq whose change the document holds (a signature verified up to it) is a fork: refused as forged, never as its actor's node's, not told back in REFUSALS, and logged with the peer that brought it.
* sync: a member refused as a whole, synced with again once it changed documenttv3 days1-0/+8
| | | | | | | | | | | | A node refusing a member as a whole sent it nothing, and lifted that only when a change of the member's was taken again. But a member that dropped what was refused (REFUSALS) starts its sync sessions over, and a fresh session sends no changes until the other side answers: the two waited for each other, and the member stayed refused. The refusal now notes the member's run and epoch_seq when it began; a member with another document since (it dropped what was refused, or rejoined) is synced with again.
* access: a node judges its own changes before they leavetv3 days1-0/+53
| | | | | | | | | | | | | | | | | | | | The API checks the path a request asks for; the rules judge everything the change does. Where they disagreed, the honest node's change was refused by every other node, and with signatures required the node was refused as a whole. The plan had both gates run the same judgement. Under a policy, each change a node makes (its own writes and those through the API) is now judged by rules::judge as receivers will judge it, before it is signed or sent; one every node would refuse is rolled back (the document forked at the heads before it, same actor: the change never left) and the request refused with 403 (StoreError:: Refused). rules::judge_held, judging a change the document holds, moves from swarm::refusals to access::rules for both. The simulations that play a member past its own checks write with a helper that bypasses them (forge). Review finding 3 (the same judgement at both gates).
* access: forgetting and revoking as the API letstv3 days1-4/+46
| | | | | | | | | | | | | | Two writes the API lets a user make were refused by the rules: * DELETE /peers/{pk}, with write on _continuum/forgotten alone, writes the forget record and removes the member's entry in one change; the rules wanted write on the entry. Removing an entry is now also taken in a change forgetting that member, from a user who may forget it. * DELETE /admin/users/{name}/tokens by a user who manages users writes _continuum/logouts/<name>; the rules wanted write there. One who may write _continuum/users may now write anyone's logouts entry. Review finding 3 (DELETE /peers, revoking tokens).
* access: maps made on the way judged by what they holdtv3 days1-0/+84
| | | | | | | | | | | | A write makes the maps on its way where there are none (store::write_path); the rules judged each made map as a write at its own path, so a user whose capability lies below a map not made yet (write on servers/eu, a first PUT at servers/eu/0) had its first write taken by its node and refused by every other. A map made where there was none, in a change writing within it, is now judged by what is written within it. Review finding 3 (parent maps created on the way).
* access: signed values in before the next is judgedtv3 days1-2/+73
| | | | | | | | | | | Under a strict policy the rules read user data: the value at a signed place (prev) and what holds one. A batch judged at its frontier missed a signed write earlier in the same batch, so two successive signed writes at one path received together were refused on some nodes and taken on others. A change at, within or above a signed path now goes in before the next is judged. Review finding 2.
* access: judged by the policy written undertv3 days2-2/+40
| | | | | | | | | | The rules read the policy at the change's dependencies only for strict mode, so history from before the policy was judged by today's rules when a late node caught up, or when REFUSALS had it judged again. A change written while the document had no policy, or one this node doesn't know, is now judged by none. Review finding 6.
* access: a forgotten node cancels its own recordtv3 days1-1/+8
| | | | | | | | | | A node forgotten swarm-wide while alive cancels its forget record with a change naming no user; the rules judged _continuum/forgotten by the registry alone, so every node refused the cancellation and everything the node wrote after it. A node may now write its own _continuum/forgotten/<id>, as it may its member entry. Review finding 4.
* access: an epoch's root is never droppedtv3 days1-2/+8
| | | | | | | | | | | | | | | A REFUSALS naming the swarm's first change made the node receiving it judge that change again in a document that isn't empty, refuse it as "a change without dependencies that isn't the epoch's root", and drop it with everything built on it: its whole document. The first epoch's root is now the first change a document holds, as it comes to an empty one or as it is in one; a change judged again on a peer's word is never refused for having no dependencies; and drop_taken refuses to drop an epoch's root, or anything that would leave nothing kept, logging an error instead. Review finding 1 (critical).
* swarm: changes taken unjudged, dropped (REFUSALS)tv4 days1-18/+41
| | | | | | | | | A node refusing changes a peer brought tells it which broke a rule; the peer judges them itself, and if its rules refuse them too, drops them with all built on them (its document forked without them, a fresh actor), quarantining its own writes among them. Wire version 42. Auth plan M6 (rejoin on taint).
* access: members refused as a wholetv4 days1-0/+80
| | | | | | | | | With signatures required, a member whose own change broke a rule is refused as a whole: sent nothing, shown in /peers (refused), in stats (sync.refusedPeers) and on the dashboard, until a change of its is taken again or the epoch changes. Auth plan M6 (diverged standing).
* access: refused oncetv4 days1-10/+147
| | | | | | | | A refused change is remembered by its hash: offered again it is refused without decoding, judging or logging, so is one built on it, and a peer offering nothing else is answered later each time, up to a minute. Auth plan M6 (re-sending).
* access: values sealed for their readerstv4 days4-1/+473
| | | | | | | | | | cs1.<age file>: a value encrypted with age to its readers' SSH keys, which no node decrypts. _continuum/access/sealed declares paths whose values must be sealed, for named readers or anyone; nodes check the recipients by age's key tags, at the API and on receipt. Auth plan M8, reworked: sealed values instead of containers, readers as users only (nodes hold no keys).
* access: --bootstrap-keystv4 days1-10/+62
| | | | | | | The first users' SSH keys, recorded at genesis with their entries, so a swarm can be strict from its start. Auth plan M7.
* auth: logging in by keytv4 days2-0/+206
| | | | | | | | POST /auth/challenge and /auth/login/key: a node-signed challenge, valid five minutes and taken once, signed with one of the user's SSH keys (ssh-keygen -Y sign -n continuum-login), for a token. Auth plan M7 (key login, M2b).
* access: signed values judged on receipttv4 days2-7/+219
| | | | | | | | | Inspection gives each operation's kind; under strict every node refuses, at a signed place, anything but an envelope that checks and replaces the one there (deleting first as replacing does), anything within one, and above one anything replacing what holds one. Auth plan M7.
* api: signed values at the storetv4 days3-12/+39
| | | | | | | | | PUT with application/continuum-signed writes an envelope where values are signed (403/409 saying why); reads open envelopes and name the signer (x-continuum-signed-by), ?raw=true shows them. Under strict, unsigned writes reaching a signed value and the users API are 409. Auth plan M7.
* access: strict policy, signed pathstv4 days4-25/+97
| | | | | | | | | "values": "signed" (strict, requiring signatures too): the registry, _continuum/access, bans and the paths in _continuum/access/userSigned (* for any key) hold values their users signed. Envelopes read as the values they hold where the node reads protocol data. Auth plan M7.
* access: logouts apart from users' entriestv4 days3-19/+24
| | | | | | | | _continuum/logouts/<name> holds when a user's tokens were last revoked, written by the user itself or by one who may manage users, so users' entries can be signed by their managers alone. Auth plan M7.
* access: values signed by their userstv4 days4-2/+288
| | | | | | | | | access::envelope: cv1.<payload>.<signature>, the payload naming the path, value, user, time and the envelope it replaces (prev), signed with one of the user's SSH keys from the registry (keys). Checked against the registry as the writer saw it. Auth plan M7.
* access: SSH signaturestv4 days2-0/+260
| | | | | | | access::sshsig: OpenSSH's SSHSIG, verified and made natively (Ed25519, sha512/sha256), checked against OpenSSH's own test vector. Auth plan M7.
* access: banstv4 days3-1/+52
| | | | | | | | _continuum/banned/<node ID>: every node refuses the banned node's changes from then on (judged as the ban stood) and leaves its handshakes unanswered. Auth plan M6.
* access: signatures requiredtv4 days2-10/+140
| | | | | | | | "signatures": "required": a change counts only once a signature by its committer vouches for it, and waits until then; every node then signs every change it makes. Auth plan M6.
* access: the policy enforcedtv4 days3-4/+169
| | | | | | | | _continuum/access/policy ({"version": 1}) has every node screen every change it receives, on every path changes come in. A policy a node doesn't know stops its writes through the API. GET /admin/refused. Auth plan M6.
* access: screening received changestv4 days3-1/+389
| | | | | | | | | access::screen: a batch of received changes judged change by change, those that change what rules read applied before the next is judged; a refused change stays out with whatever builds on it, kept aside for operators; changes missing dependencies wait. Auth plan M6.
* access: rules by pathtv4 days2-0/+407
| | | | | | | | | | access::rules::judge: a change judged as its writer saw the document (at its dependencies): committer a member or registering itself; members' entries and votes their own; epochs and swarm ID from roots; a remake's decision by its coordinator; the rest by the registry for the user the change names. Auth plan M6.
* docs: tokens through a proxy; token formats latertv4 days1-1/+2
| | | | | | | | operations.md: an nginx proxy passing requests with a token on to the node and asking the others for its own login. future-work: other token formats. Auth plan M2.
* store: keys_at tells no map from an empty onetv4 days1-2/+5
| | | | | | | | registry::exists counted any value at _continuum/users as a registry; keys_at answers None where there is no map, and its users (records, members, forget records, remakes) say what they make of it. Auth plan M1 (fix).
* access: tokenstv4 days3-7/+354
| | | | | | | | | ct1 tokens: who, how they logged in, a session, when they expire, and optionally a narrower limit; signed by the issuing node's key and taken by every member (a node ID is its key). Revocation by the registry as it stands when a request comes. Auth plan M2.
* access: the users endpointstv4 days1-34/+20
| | | | | | | | /admin/users: list, add (one or several), remove, disable, grant and revoke capabilities; each one change, refused if it would lock its writer out. Capabilities as the store's paths name them. Auth plan M1.
* access: bootstrap users onlytv4 days1-26/+9
| | | | | | | The first users come only from --bootstrap-users; the genesis node warns of htpasswd users that aren't among them. Auth plan M1.
* access: genesis of swarms from before the registrytv4 days1-34/+19
| | | | | | | | Swarms started before the registry keep working without one; the genesis node's options for a registry apply only to new swarms. What tests and migration leave is noted in future-work. Auth plan M1, bootstrap and migration (2.5).
* access: keeping the swarm manageabletv4 days1-0/+26
| | | | | | | | | A write that would leave its own writer unable to manage users (deleting, disabling or narrowing its entry, removing the registry) is refused; --protocol-writers can set a registry right that nobody may manage any more. Auth plan M1.
* access: first users at genesistv4 days1-0/+87
| | | | | | | | --bootstrap-users gives a new swarm a registry from its first change, each first user with everything; other users may do nothing until added. Without it the swarm has no registry and works as before. Auth plan M1.
* access: the user registrytv4 days2-0/+414
_continuum/users/<name>: one entry per user, with capabilities by path (read, write) granted by whom and when, and a disabled flag. Read leniently: a damaged entry gives less, never more. Protocol data stays apart: a capability outside _continuum never covers it. Auth plan M1.