aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/access.md6
-rw-r--r--src/access/bans.rs4
-rw-r--r--src/access/token.rs18
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();