From a7c70346b448f493991df1e035beaa4bde113b4f Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 8 Nov 2026 16:14:07 +0000 Subject: auth: no basic authentication offered to the dashboard What is meant for browsers logs in on its page (/login), with the passwords of --htpasswd; basic authentication's challenge stays for the API, so curl -u keeps working. 1164 kept it from a page's own requests; now nothing under /admin/dashboard is challenged either, whatever the request: a browser opening the page without a user is sent to /login, anything else answered 401 without a challenge. --- docs/dashboard.md | 3 ++- src/api/auth.rs | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/dashboard.md b/docs/dashboard.md index 7f64034..027e094 100644 --- a/docs/dashboard.md +++ b/docs/dashboard.md @@ -17,7 +17,8 @@ It is at `/admin/dashboard` on the node's HTTP API, by default `http://127.0.0.1:3000/admin/dashboard`, for a user a reverse proxy names (`--user-header`) or one logged in on the page `/login`, which a browser opening the dashboard without one is sent to. There, a user logs in with its password -(`--htpasswd`), or with a token: from `continuum-signed login` (by key, +(`--htpasswd`, the same file the API's basic authentication takes, which the dashboard +never asks for itself: no browser password prompt), or with a token: from `continuum-signed login` (by key, [`access.md`](access.md), Tokens), or any other. The page keeps a session for the browser, a cookie no script reads and no other site's page sends, renewed while the dashboard is open; it ends with the token's lifetime, or with "Log out of this diff --git a/src/api/auth.rs b/src/api/auth.rs index acf9d46..a5a987c 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -316,14 +316,17 @@ pub(crate) async fn basic_auth( ) .into_response(); } - // A challenge only where basic authentication can answer it, and not to a page's - // own requests (`Sec-Fetch-Dest: empty`: fetch, EventSource): the browser would - // ask for a password over the page, which has its own login (`/login`). - let from_a_page = headers - .get("sec-fetch-dest") - .is_some_and(|dest| dest == "empty"); + // A challenge only where basic authentication can answer it, for the API (curl), + // never for what is meant for browsers: the dashboard, nor a page's own requests + // (`Sec-Fetch-Dest: empty`: fetch, EventSource). The browser would ask for a + // password over the page, which has its own login (`/login`), taking the + // passwords of the same file. + let for_browsers = request.uri().path().starts_with("/admin/dashboard") + || headers + .get("sec-fetch-dest") + .is_some_and(|dest| dest == "empty"); return match state.users { - Some(_) if !from_a_page => ( + Some(_) if !for_browsers => ( StatusCode::UNAUTHORIZED, [(WWW_AUTHENTICATE, r#"Basic realm="Restricted""#)], "Unauthorized", -- cgit v1.3.1