aboutsummaryrefslogtreecommitdiffstats
path: root/docs/access.md
blob: 519113c17b4a676ee10fc3368844bbde3e505832 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# Users and what they may do

Who the users are, and what each may do, is the swarm's: a registry in the document,
the same on every node. How a user proves who it is stays each node's: its
`--htpasswd`, or a reverse proxy naming the user (`--user-header`, [`trust.md`](trust.md)).

## The registry

`_continuum/users/<name>`, one entry per user. It is protocol data: every member holds
it, a remake's snapshot carries it into the next epoch, and it holds no secrets (no
password hashes: every member reads the document).

```json
{ "since": 1762400000000, "by": "continuum:3f…",
  "caps": { "8c41e2…": { "path": [], "rights": ["read", "write"],
                        "by": "continuum:3f…", "since": 1762400000000 } },
  "disabled": false }
```

* **Names** are what `--htpasswd` and the proxy give: 1 to 64 of `A-Z a-z 0-9 . _ @ -`.
* **Capabilities** (`caps`): each a path, as segments as the store's API takes them,
  and the rights it gives there and below: `read`, `write`. A capability covers its
  path segment by segment (`servers/eu` covers `servers/eu/0`, not `servers/europe`).
  One outside protocol data never covers protocol data: `[]` is all of the swarm's
  data, `["_continuum"]` protocol data, managing users included (`_continuum/users`).
  They are kept by a random ID, so two capabilities granted at once both hold, and
  revoking one removes it alone. Each names who granted it (`by`: a user as
  `user:<name>`, or the node that recorded it) and when (`since`).
* **`disabled`**: the entry stays (who wrote what stays readable), and gives nothing.
  An entry that doesn't read as above gives less, never more: a capability that
  doesn't read is left out, and anything but `false` disables.

## A new swarm

A swarm gets a registry from its start if its genesis node is given its first users,
`--bootstrap-users`: it records them, with the swarm ID, in its first change, each with
everything (`[]` and `["_continuum"]`). Other users, of its `--htpasswd` or any node's,
may do nothing until added (the genesis node warns of those of its `--htpasswd`).
Without it, the swarm has no registry, and is as swarms were before: users all alike
(An existing swarm, below), until someone gives it one. `--protocol-writers` counts in
both: without a registry, as who may write protocol data; with one, to set it right
should nobody be left who may manage users (Keeping the swarm manageable, below).

## At the HTTP API

Every request is checked against the registry, as the node serving it holds it: a
change to it counts on a node as soon as it has reached it.

* **The store** (`/store`, `/stream`): writing a path (`PUT`, `POST`, `DELETE`) takes
  `write` on it; `?prune=true` deletes maps left empty only up to the highest one the
  user may write. Reading takes `read`: of a place the user may read only partly, it
  sees the keys on the way to what it may read, as a directory one may pass through
  but not list (a capability on `servers/eu` shows `servers` with `eu` alone in it),
  and nothing else; a list on the way is left out whole, as its items have no paths of
  their own. Native forms (`text/plain` of a map, a counter as its own type) only of
  what it may read whole. What a write answers with is what was written. A stream
  shows what the user could read when it opened.
* **Protocol data** is in the store too, under `_continuum`: `read` and `write` on it
  as on any path.
* **Looking at the node** (`/admin/stats`, `GET /peers`, the dashboard): any user with
  a capability. The dashboard's document box is read through the store, as the user
  may; the page is told only of changes where its user may read.
* **Remakes** (`/admin/remakes`): `read` on `_continuum/remakes` to look, `write` to
  propose or abort one. **Forgetting a peer** (`DELETE /peers/…`): `write` on
  `_continuum/forgotten`.
* **Everything else an operator does** (`/admin/config`, `/admin/log`,
  `/admin/document`, `/admin/changes`, `/admin/epochs`, `/admin/quarantine`, `/debug`):
  `read` on `_continuum` to look, `write` on it to act.

A user the node lets in but the registry doesn't have may do nothing (`403`).

`[]` and `["_continuum"]` are two capabilities on purpose: protocol data acts on the
whole swarm (its members, its remakes, its users), so it is given apart, never by
accident with the data. A user who may do both has both.

## An existing swarm

A swarm whose document has no registry (one from before it, `_continuum/users`
missing) goes on as before: every user a node lets in may read and write the swarm's
data and use the admin endpoints, and only those in `--protocol-writers` write
protocol data. It gets a registry once a protocol writer writes one, through the store:

```sh
curl -u alice --request PUT --header 'Content-Type: application/json' \
  --data '{"since": 0, "by": "user:alice", "disabled": false,
           "caps": {"1": {"path": [], "rights": ["read", "write"]},
                    "2": {"path": ["_continuum"], "rights": ["read", "write"]}}}' \
  http://localhost:3000/store/_continuum/users/alice
```

From that write on, every node serves only the users the registry has, so the first
entry must be the writer's own, with `["_continuum"]` (a first write that isn't is
refused, `409`); add the other users the same way.

## Keeping the swarm manageable

A user may not lock itself out: a write that would keep its writer from managing users
(enabled, with `write` on `_continuum/users`) when it could, deleting, disabling or
narrowing its own entry, is refused (`409`), and nothing of it is written; so is one
that would remove the registry (`_continuum/users`). Others are not kept from removing
the last user who may manage users: each node can only judge what it holds, and two
such writes on two nodes at once would leave nobody once they merge anyway. Then,
while nobody may manage users, the users in a node's `--protocol-writers` may do
everything there again, to set it right.