From 9a58a4e932156e0207380bb3b0a93a59864b0e1c Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 27 Feb 2024 01:05:51 +0100 Subject: [PATCH] WIP login --- src/dav/mod.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/dav/mod.rs b/src/dav/mod.rs index d3347f3..709abd5 100644 --- a/src/dav/mod.rs +++ b/src/dav/mod.rs @@ -1,6 +1,7 @@ use std::net::SocketAddr; -use anyhow::Result; +use anyhow::{anyhow, Result}; +use base64::Engine; use hyper::service::service_fn; use hyper::{Request, Response, body::Bytes}; use hyper::server::conn::http1 as http; @@ -46,11 +47,17 @@ impl Server { }; tracing::info!("DAV: accepted connection from {}", remote_addr); let stream = TokioIo::new(socket); - let conn = tokio::spawn(async { + let login = self.login_provider.clone(); + let conn = tokio::spawn(async move { //@FIXME should create a generic "public web" server on which "routers" could be //abitrarily bound //@FIXME replace with a handler supporting http2 and TLS - match http::Builder::new().serve_connection(stream, service_fn(router)).await { + match http::Builder::new().serve_connection(stream, service_fn(|req: Request| { + let login = login.clone(); + async move { + auth(login, req).await + } + })).await { Err(e) => tracing::warn!(err=?e, "connection failed"), Ok(()) => tracing::trace!("connection terminated with success"), } @@ -66,6 +73,45 @@ impl Server { } } +async fn auth( + login: ArcLoginProvider, + req: Request, +) -> Result>> { + + let auth_val = match req.headers().get("Authorization") { + Some(hv) => hv.to_str()?, + None => return Ok(Response::builder() + .status(401) + .body(Full::new(Bytes::from("Missing Authorization field")))?), + }; + + let b64_creds_maybe_padded = match auth_val.split_once(" ") { + Some(("Basic", b64)) => b64, + _ => return Ok(Response::builder() + .status(400) + .body(Full::new(Bytes::from("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 + + // Call router with user + + unimplemented!(); +} + async fn router(req: Request) -> Result>> { let path_segments: Vec<_> = req.uri().path().split("/").filter(|s| *s != "").collect(); match path_segments.as_slice() {