diff options
| author | tv <tv@krebsco.de> | 2026-11-07 22:35:09 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-07 22:35:09 +0100 |
| commit | ec70060ae5fa665953741da921e28031b56bc5e0 (patch) | |
| tree | cd1f6f5ae90d3ad87b9667da20d6e85b62394ab1 /src/api/auth.rs | |
| parent | eed8f86912f53f549d9f9068f9bdf2c8e23aa0f7 (diff) | |
auth: logging in, and tokens as bearers
POST /auth/login (by htpasswd or the proxy), /auth/refresh,
/auth/logout, GET /auth/whoami; every request may bring
Authorization: Bearer instead of a password. --token-lifetime and
--session-lifetime.
Auth plan M2.
Diffstat (limited to 'src/api/auth.rs')
| -rw-r--r-- | src/api/auth.rs | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/src/api/auth.rs b/src/api/auth.rs index f85b64e..69c7ddb 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -203,10 +203,16 @@ fn parse_basic(headers: &HeaderMap) -> Option<(String, String)> { Some((user.to_owned(), pass.to_owned())) } -/// The user a request authenticated as (a request extension, set by [`basic_auth`]). +/// The user a request authenticated as (a request extension, set by [`basic_auth`], or +/// by `login::bearer` for a token). #[derive(Clone, Debug)] pub(crate) struct AuthenticatedUser(pub(crate) String); +/// How the request's user proved who it is (a request extension, beside +/// `AuthenticatedUser`): `htpasswd`, `header` (a trusted proxy's), or `token`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct Via(pub(crate) &'static str); + /// The user the trusted proxy the request came from names, if it does. fn proxied_user(state: &AuthState, headers: &HeaderMap, from: Option<Peer>) -> Option<String> { let proxy = state.proxy.as_ref()?; @@ -279,15 +285,21 @@ pub(crate) async fn basic_auth( mut request: Request<Body>, next: axum::middleware::Next, ) -> Response { + // A token, taken already (`login::bearer`). + if request.extensions().get::<AuthenticatedUser>().is_some() { + return next.run(request).await; + } let from = request .extensions() .get::<ConnectInfo<Peer>>() .map(|ConnectInfo(peer)| *peer); let user = match proxied_user(&state, &headers, from) { - Some(user) => Some(user), - None => authenticate(&state, &headers).await, + Some(user) => Some((user, Via("header"))), + None => authenticate(&state, &headers) + .await + .map(|user| (user, Via("htpasswd"))), }; - let Some(user) = user else { + let Some((user, via)) = user else { sleep(Duration::from_millis(1500)).await; // A challenge only where basic authentication can answer it. return match state.users { @@ -302,6 +314,7 @@ pub(crate) async fn basic_auth( }; request.extensions_mut().insert(AuthenticatedUser(user)); + request.extensions_mut().insert(via); next.run(request).await } |
