diff options
| -rw-r--r-- | docs/access.md | 6 | ||||
| -rw-r--r-- | src/access/bans.rs | 4 | ||||
| -rw-r--r-- | src/access/token.rs | 18 |
3 files changed, 22 insertions, 6 deletions
diff --git a/docs/access.md b/docs/access.md index 107de8d..a85dfa4 100644 --- a/docs/access.md +++ b/docs/access.md @@ -106,8 +106,8 @@ curl -H "Authorization: Bearer ct1.…" http://other-node:3000/store * **Revoking**: a user disabled or removed is refused at once; all of a user's tokens, by the user (`POST /auth/logout`) or by one who may manage users (`DELETE /admin/users/{name}/tokens`), which sets `_continuum/logouts/<name>`: tokens issued - before aren't taken any more. A token of a node forgotten by the swarm isn't taken - either. In a swarm without a registry, a token is taken until it expires. + before aren't taken any more. A token of a node banned or forgotten by the swarm isn't + taken either. In a swarm without a registry, a token is taken until it expires. * **What it means to trust**: any member could sign a token for any user, as it could write anything as anyone ([`trust.md`](trust.md)). A token is a bearer's: whoever holds it is the user until it ends, so it goes over TLS only, as passwords do. @@ -307,7 +307,7 @@ A node can be banned: `_continuum/banned/<node ID>`, written by a user who may w there (protocol data). Every node then leaves its handshakes unanswered, so it is neither synced with nor counted a member, and with the policy every node refuses the changes it commits from then on, judged as the ban stood when they were made (what it -wrote before stays). Deleting the entry lifts the ban. A ban doesn't remove the node +wrote before stays), and the tokens it issued. Deleting the entry lifts the ban. A ban doesn't remove the node from the member list: forget it too (`DELETE /peers/<node ID>`). ```sh diff --git a/src/access/bans.rs b/src/access/bans.rs index c4fad1f..a314f49 100644 --- a/src/access/bans.rs +++ b/src/access/bans.rs @@ -2,8 +2,8 @@ //! user who may write there, as any protocol data: a node refuses a banned node's //! handshake, so it neither syncs with it nor counts it a member (`swarm::peer`), and //! with the swarm's policy every node refuses the changes a banned node commits -//! (`access::rules`, judged as the ban stood when they were made). Deleting the entry -//! lifts the ban. +//! (`access::rules`, judged as the ban stood when they were made), and the tokens it +//! issued (`access::token`). Deleting the entry lifts the ban. use crate::document::{ReadDoc, meta, store}; diff --git a/src/access/token.rs b/src/access/token.rs index 3af8672..d33a3fe 100644 --- a/src/access/token.rs +++ b/src/access/token.rs @@ -75,6 +75,8 @@ pub(crate) enum Refused { OtherSwarm, #[error("issued by a node that isn't a member here (not yet, or no longer)")] UnknownIssuer, + #[error("issued by a node the swarm banned")] + BannedIssuer, #[error("its signature doesn't hold")] BadSignature, #[error("expired")] @@ -90,7 +92,7 @@ pub(crate) enum Refused { } /// The claims of `token` if this node takes it: well formed, for `swarm`, signed by a -/// node that is a member in `doc`, not expired at `now` (Unix ms), nor issued later +/// node that is a member in `doc` and not banned, not expired at `now` (Unix ms), nor issued later /// than a clock off by `SKEW_MS` would; and in a swarm with a registry, for a /// registered user that is enabled, issued after its tokens were last revoked /// (`registry::User::tokens_not_before`). @@ -126,6 +128,9 @@ pub(crate) fn verify( if !member { return Err(Refused::UnknownIssuer); } + if super::bans::banned(doc, &claims.issuer) { + return Err(Refused::BannedIssuer); + } let mut signed = LABEL.to_vec(); signed.extend_from_slice(&payload); if !identity::verify(&key, &signed, &signature) { @@ -236,6 +241,17 @@ mod tests { verify(&doc, &forged, "s", 1_500), Err(Refused::BadSignature) ); + // By a member banned since. + let token = issue(&key, &claims(&key)); + let ban = crate::access::bans::path(&key.id()); + let mut banned = doc.fork(); + change(&mut banned, |tx| { + store::write_path(tx, &ban, &json!({"reason": "lost"})).unwrap() + }); + assert_eq!( + verify(&banned, &token, "s", 1_500), + Err(Refused::BannedIssuer) + ); // Changed claims, the signature kept. let token = issue(&key, &claims(&key)); let (_, signature) = token.rsplit_once('.').unwrap(); |
