From 3ccb4ab05fc1d7dbd4ebbba9ff2de0ecc9139b27 Mon Sep 17 00:00:00 2001 From: Brendon Walsh Date: Fri, 29 Dec 2023 16:20:46 -0500 Subject: [PATCH] Authorization middleware supports cookie or authorization header (#594) * Authorization middleware supports cookie or authorization header * fix typo for 'message' in error response --- Cargo.lock | 155 +++++++++++++++++++++++++++++++++----- dim-web/Cargo.toml | 1 + dim-web/src/error.rs | 2 +- dim-web/src/lib.rs | 4 +- dim-web/src/middleware.rs | 76 +++++++++++++------ 5 files changed, 190 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9aa9eeb6e..adb78aa7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -228,14 +228,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "axum-macros", "base64 0.21.5", "bitflags 1.3.2", "bytes 1.5.0", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "hyper", "itoa", "matchit", @@ -258,6 +258,33 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" +dependencies = [ + "async-trait", + "axum-core 0.4.1", + "bytes 1.5.0", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-core" version = "0.3.4" @@ -267,14 +294,56 @@ dependencies = [ "async-trait", "bytes 1.5.0", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "mime", "rustversion", "tower-layer", "tower-service", ] +[[package]] +name = "axum-core" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa" +dependencies = [ + "async-trait", + "bytes 1.5.0", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-extra" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523ae92256049a3b02d3bb4df80152386cd97ddba0c8c5077619bdc8c4b1859b" +dependencies = [ + "axum 0.7.2", + "axum-core 0.4.1", + "bytes 1.5.0", + "cookie", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-macros" version = "0.3.8" @@ -567,6 +636,17 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "cookie" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8" +dependencies = [ + "percent-encoding", + "time 0.3.30", + "version_check", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -854,7 +934,7 @@ name = "dim-core" version = "0.4.0-dev" dependencies = [ "async-trait", - "axum", + "axum 0.6.20", "cfg-if", "chrono", "criterion", @@ -867,7 +947,7 @@ dependencies = [ "displaydoc", "futures", "fuzzy-matcher", - "http", + "http 0.2.9", "hyper", "ignore", "image", @@ -967,7 +1047,8 @@ dependencies = [ name = "dim-web" version = "0.1.0" dependencies = [ - "axum", + "axum 0.6.20", + "axum-extra", "cfg-if", "chrono", "dim-core", @@ -979,7 +1060,7 @@ dependencies = [ "dominant_color", "futures", "fuzzy-matcher", - "http", + "http 0.2.9", "hyper", "image", "nightfall", @@ -1398,7 +1479,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap", "slab", "tokio", @@ -1492,6 +1573,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes 1.5.0", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -1499,7 +1591,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes 1.5.0", - "http", + "http 0.2.9", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes 1.5.0", + "http 1.0.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes 1.5.0", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", "pin-project-lite", ] @@ -1532,8 +1647,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", @@ -1552,7 +1667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", + "http 0.2.9", "hyper", "rustls 0.21.8", "tokio", @@ -1922,7 +2037,7 @@ dependencies = [ "bytes 1.5.0", "encoding_rs", "futures-util", - "http", + "http 0.2.9", "httparse", "log", "memchr", @@ -2509,8 +2624,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "hyper", "hyper-rustls", "ipnet", @@ -3375,8 +3490,8 @@ dependencies = [ "bytes 1.5.0", "futures-core", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "http-range-header", "httpdate", "iri-string", @@ -3506,7 +3621,7 @@ dependencies = [ "byteorder", "bytes 1.5.0", "data-encoding", - "http", + "http 0.2.9", "httparse", "log", "rand", diff --git a/dim-web/Cargo.toml b/dim-web/Cargo.toml index 845cf06e9..2da5764d5 100644 --- a/dim-web/Cargo.toml +++ b/dim-web/Cargo.toml @@ -20,6 +20,7 @@ nightfall = { git = "https://github.com/Dusk-Labs/nightfall", tag = "0.3.12-rc4" ] } axum = { version = "0.6.20", features = ["ws", "http2", "macros", "multipart"] } +axum-extra = { version = "0.9.0", features = ["cookie"] } cfg-if = "1.0.0" chrono = { version = "0.4.19", features = ["serde"] } displaydoc = "0.2.3" diff --git a/dim-web/src/error.rs b/dim-web/src/error.rs index 8f0c87fad..bb342a296 100644 --- a/dim-web/src/error.rs +++ b/dim-web/src/error.rs @@ -49,7 +49,7 @@ impl IntoResponse for DimErrorWrapper { let resp = serde_json::json!({ "error": serde_json::json!(&self.0)["error"], - "messsage": self.0.to_string(), + "message": self.0.to_string(), }); (status, serde_json::to_string(&resp).unwrap()).into_response() } diff --git a/dim-web/src/lib.rs b/dim-web/src/lib.rs index 2c8ee367d..3d77ef602 100644 --- a/dim-web/src/lib.rs +++ b/dim-web/src/lib.rs @@ -27,7 +27,7 @@ pub mod error; pub use error::DimErrorWrapper; pub mod middleware; -pub use middleware::verify_cookie_token; +pub use middleware::verify_token; #[derive(Debug, Clone)] pub struct AppState { @@ -385,7 +385,7 @@ pub async fn start_webserver( .merge(stream_routes()) .route_layer(axum::middleware::from_fn_with_state( app.clone(), - verify_cookie_token, + verify_token, )) // --- End of routes authenticated by Axum middleware --- .merge(public_auth_routes()) diff --git a/dim-web/src/middleware.rs b/dim-web/src/middleware.rs index 3d9b6e3d2..98de64e09 100644 --- a/dim-web/src/middleware.rs +++ b/dim-web/src/middleware.rs @@ -1,36 +1,62 @@ use crate::AppState; +use axum::body::Body; +use axum::http::Request; use axum::extract::State; +use axum_extra::extract::cookie::Cookie; use dim_core::errors::DimError; +use dim_database::user::UserID; use crate::DimErrorWrapper; -pub async fn verify_cookie_token( +pub fn get_cookie_token_value( + request: &Request, +) -> Option { + request + .headers() + .get_all("Cookie") + .iter() + .filter_map(|cookie| { + cookie + .to_str() + .ok() + .and_then(|cookie| cookie.parse::().ok()) + }) + .find_map(|cookie| { + (cookie.name() == "token").then(move || cookie.value().to_owned()) + }) +} + +pub async fn verify_token( State(AppState { conn, .. }): State, - mut req: axum::http::Request, - next: axum::middleware::Next, + mut req: axum::http::Request, + next: axum::middleware::Next, ) -> Result { - match req.headers().get(axum::http::header::AUTHORIZATION) { - Some(token) => { - let mut tx = match conn.read().begin().await { - Ok(tx) => tx, - Err(_) => { - return Err(DimErrorWrapper(DimError::DatabaseError { - description: String::from("Failed to start transaction"), - })) - } - }; - let id = dim_database::user::Login::verify_cookie(token.to_str().unwrap().to_string()) - .map_err(|e| DimError::CookieError(e)) - .map_err(|e| DimErrorWrapper(e))?; - - let current_user = dim_database::user::User::get_by_id(&mut tx, id) - .await - .map_err(|_| DimError::UserNotFound) - .map_err(|e| DimErrorWrapper(e))?; + let id: UserID; + if let Some(token) = get_cookie_token_value(&req) { + id = dim_database::user::Login::verify_cookie(token) + .map_err(|e| DimError::CookieError(e)) + .map_err(|e| DimErrorWrapper(e))?; + } else if let Some(token) = req.headers().get(axum::http::header::AUTHORIZATION) { + id = dim_database::user::Login::verify_cookie(token.to_str().unwrap().to_string()) + .map_err(|e| DimError::CookieError(e)) + .map_err(|e| DimErrorWrapper(e))?; + } else { + return Err(DimErrorWrapper(DimError::NoToken)); + } - req.extensions_mut().insert(current_user); - Ok(next.run(req).await) + let mut tx = match conn.read().begin().await { + Ok(tx) => tx, + Err(_) => { + return Err(DimErrorWrapper(DimError::DatabaseError { + description: String::from("Failed to start transaction"), + })) } - None => Err(DimErrorWrapper(DimError::NoToken)), - } + }; + let current_user = dim_database::user::User::get_by_id(&mut tx, id) + .await + .map_err(|_| DimError::UserNotFound) + .map_err(|e| DimErrorWrapper(e))?; + + req.extensions_mut().insert(current_user); + Ok(next.run(req).await) }