aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-07 22:35:09 +0100
committertv <tv@krebsco.de>2026-11-07 22:35:09 +0100
commit3a9d9da74f55395ead20f3915ed04639e37b2f03 (patch)
tree1cb7d8cb8ff3acd8ce87b9169d535c9d36561fef /src
parent75ba06027496df9cea0054d8d8e9c504031d1b2c (diff)
access: bootstrap users only
The first users come only from --bootstrap-users; the genesis node warns of htpasswd users that aren't among them. Auth plan M1.
Diffstat (limited to 'src')
-rw-r--r--src/access/registry.rs35
-rw-r--r--src/config/mod.rs4
-rw-r--r--src/main.rs22
3 files changed, 26 insertions, 35 deletions
diff --git a/src/access/registry.rs b/src/access/registry.rs
index 094e62c..3006b31 100644
--- a/src/access/registry.rs
+++ b/src/access/registry.rs
@@ -146,24 +146,12 @@ pub(crate) fn capability(by: &str, since: u64, path: &[String], rights: &[Right]
/// included), not only read and write the swarm's data.
pub(crate) type FirstUsers = Vec<(String, bool)>;
-/// The first users of a new swarm, from the genesis node's options: those of
-/// `bootstrap_users` may do everything, and the other users of its htpasswd file
-/// (`htpasswd`) read and write the swarm's data. None without `bootstrap_users`: then
-/// the swarm has no registry, and its users are all alike, as before there were
-/// registries (`access.md`).
-pub(crate) fn first_users(bootstrap_users: &[String], htpasswd: &[String]) -> FirstUsers {
- if bootstrap_users.is_empty() {
- return Vec::new();
- }
- let mut users: BTreeMap<String, bool> = htpasswd
- .iter()
- .filter(|name| valid_name(name))
- .map(|name| (name.clone(), false))
- .collect();
- for name in bootstrap_users {
- users.insert(name.clone(), true);
- }
- users.into_iter().collect()
+/// The first users of a new swarm, from the genesis node's `--bootstrap-users`: each may
+/// do everything. None without: then the swarm has no registry, and its users are all
+/// alike, as before there were registries (`access.md`).
+pub(crate) fn first_users(bootstrap_users: &[String]) -> FirstUsers {
+ let users: std::collections::BTreeSet<&String> = bootstrap_users.iter().collect();
+ users.into_iter().map(|name| (name.clone(), true)).collect()
}
/// The capabilities of a first user (`first_users`): the swarm's data, and for one who
@@ -261,16 +249,11 @@ mod tests {
fn the_first_users() {
let names = |list: &[&str]| list.iter().map(|n| (*n).to_owned()).collect::<Vec<_>>();
assert_eq!(
- first_users(&names(&["alice"]), &names(&["alice", "bob"])),
- vec![("alice".to_owned(), true), ("bob".to_owned(), false)]
- );
- // One the proxy names, not in htpasswd.
- assert_eq!(
- first_users(&names(&["carol"]), &names(&["bob"])),
- vec![("bob".to_owned(), false), ("carol".to_owned(), true)]
+ first_users(&names(&["bob", "alice", "bob"])),
+ vec![("alice".to_owned(), true), ("bob".to_owned(), true)]
);
// Without bootstrap users, no registry.
- assert!(first_users(&[], &names(&["alice"])).is_empty());
+ assert!(first_users(&[]).is_empty());
let admin = Caps::new(
first_caps(true)
.into_iter()
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 320d2a8..5306c5e 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -121,14 +121,14 @@ pub(crate) const OPTIONS: &[OptionSpec] = &[
Kind::List,
"USER,[USER...]",
None,
- "HTTP API users (from htpasswd or user-header) who may write protocol data under /store/_continuum (remake records, members, forget records), e.g. to repair a stuck remake, in a swarm without a user registry. Such writes act on the whole swarm and are logged. Epoch metadata and the swarm ID are never writable. With a registry its capabilities decide instead (docs/access.md).",
+ "HTTP API users (from htpasswd or user-header) who may write protocol data under /store/_continuum (remake records, members, forget records), e.g. to repair a stuck remake, in a swarm without a user registry. Such writes act on the whole swarm and are logged. Epoch metadata and the swarm ID are never writable. With a registry its capabilities decide instead (docs/access.md), but for a registry nobody may manage users of any more: then these may do everything on this node, to set it right.",
),
option(
"bootstrap-users",
Kind::List,
"USER,[USER...]",
None,
- "With genesis: give the new swarm a user registry (docs/access.md), these its first users, each may do everything, protocol data and managing users included; htpasswd's other users may read and write the swarm's data. Unset, the swarm has no registry: its users are all alike, and only those in protocol-writers write protocol data.",
+ "With genesis: give the new swarm a user registry (docs/access.md), these its first users, each may do everything, protocol data and managing users included; other users may do nothing until added. Unset, the swarm has no registry: its users are all alike, and only those in protocol-writers write protocol data.",
),
option(
"log-format",
diff --git a/src/main.rs b/src/main.rs
index 2b8c376..fb3c0ad 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -97,16 +97,24 @@ async fn main() -> Result<()> {
// A broken htpasswd will abort startup.
let auth_state =
AuthState::from_settings(&args)?.context("htpasswd or user-header is required")?;
- // A new swarm's first users, if it is to have a user registry.
- let first_users = if args.genesis && !args.bootstrap_users.is_empty() {
- let htpasswd = match args.htpasswd.as_deref() {
- Some(path) => api::auth::htpasswd_names(path)?,
- None => Vec::new(),
- };
- access::registry::first_users(&args.bootstrap_users, &htpasswd)
+ // A new swarm's first users, if it is to have a user registry; the users of the
+ // htpasswd file that aren't among them may do nothing until they are added.
+ let first_users = if args.genesis {
+ access::registry::first_users(&args.bootstrap_users)
} else {
Vec::new()
};
+ if !first_users.is_empty()
+ && let Some(path) = args.htpasswd.as_deref()
+ {
+ let missing: Vec<String> = api::auth::htpasswd_names(path)?
+ .into_iter()
+ .filter(|name| !args.bootstrap_users.contains(name))
+ .collect();
+ if !missing.is_empty() {
+ warn!(users = ?missing, "Users of htpasswd not among bootstrap-users: the new swarm's registry doesn't have them, so they may do nothing until added (docs/access.md)");
+ }
+ }
info!(
bind_addr = ?args.bind_addr.iter().map(ToString::to_string).collect::<Vec<_>>(),