diff options
author | Quentin Dufour <quentin@deuxfleurs.fr> | 2024-04-18 13:55:57 +0200 |
---|---|---|
committer | Quentin Dufour <quentin@deuxfleurs.fr> | 2024-04-18 13:55:57 +0200 |
commit | 2bda8ef081d9c8f47081845bb4545a12b6ae8a18 (patch) | |
tree | 5c5d8d1077f9cd571c8cbf954f3e9fe15fab29e2 /aero-proto/src/dav/middleware.rs | |
parent | 66eac8ec7a420f20fa01bb77ccc25d964a404af3 (diff) | |
download | aerogramme-2bda8ef081d9c8f47081845bb4545a12b6ae8a18.tar.gz aerogramme-2bda8ef081d9c8f47081845bb4545a12b6ae8a18.zip |
split dav module in multiple files
Diffstat (limited to 'aero-proto/src/dav/middleware.rs')
-rw-r--r-- | aero-proto/src/dav/middleware.rs | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/aero-proto/src/dav/middleware.rs b/aero-proto/src/dav/middleware.rs new file mode 100644 index 0000000..c4edbd8 --- /dev/null +++ b/aero-proto/src/dav/middleware.rs @@ -0,0 +1,70 @@ +use anyhow::{anyhow, Result}; +use base64::Engine; +use hyper::{Request, Response, body::Bytes}; +use hyper::body::Incoming; +use http_body_util::combinators::BoxBody; + +use aero_user::login::ArcLoginProvider; +use aero_collections::user::User; + +use super::codec::text_body; + +type ArcUser = std::sync::Arc<User>; + +pub(super) async fn auth<'a>( + login: ArcLoginProvider, + req: Request<Incoming>, + next: impl Fn(ArcUser, Request<Incoming>) -> futures::future::BoxFuture<'a, Result<Response<BoxBody<Bytes, std::io::Error>>>>, +) -> Result<Response<BoxBody<Bytes, std::io::Error>>> { + let auth_val = match req.headers().get(hyper::header::AUTHORIZATION) { + Some(hv) => hv.to_str()?, + None => { + tracing::info!("Missing authorization field"); + return Ok(Response::builder() + .status(401) + .header("WWW-Authenticate", "Basic realm=\"Aerogramme\"") + .body(text_body("Missing Authorization field"))?) + }, + }; + + let b64_creds_maybe_padded = match auth_val.split_once(" ") { + Some(("Basic", b64)) => b64, + _ => { + tracing::info!("Unsupported authorization field"); + return Ok(Response::builder() + .status(400) + .body(text_body("Unsupported Authorization field"))?) + }, + }; + + // base64urlencoded may have trailing equals, base64urlsafe has not + // theoretically authorization is padded but "be liberal in what you accept" + let b64_creds_clean = b64_creds_maybe_padded.trim_end_matches('='); + + // Decode base64 + let creds = base64::engine::general_purpose::STANDARD_NO_PAD.decode(b64_creds_clean)?; + let str_creds = std::str::from_utf8(&creds)?; + + // Split username and password + let (username, password) = str_creds + .split_once(':') + .ok_or(anyhow!("Missing colon in Authorization, can't split decoded value into a username/password pair"))?; + + // Call login provider + let creds = match login.login(username, password).await { + Ok(c) => c, + Err(_) => { + tracing::info!(user=username, "Wrong credentials"); + return Ok(Response::builder() + .status(401) + .header("WWW-Authenticate", "Basic realm=\"Aerogramme\"") + .body(text_body("Wrong credentials"))?) + }, + }; + + // Build a user + let user = User::new(username.into(), creds).await?; + + // Call router with user + next(user, req).await +} |