From 977059c90d3c6836289c14822195c3d38e80b2b9 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Fri, 18 Nov 2022 08:44:17 -0500 Subject: [PATCH] Set up the authentication filter --- server/src/authentication.rs | 2 +- server/src/main.rs | 129 ++++++++++++++++++++++------------- 2 files changed, 82 insertions(+), 49 deletions(-) diff --git a/server/src/authentication.rs b/server/src/authentication.rs index 440864a..e356f23 100644 --- a/server/src/authentication.rs +++ b/server/src/authentication.rs @@ -140,7 +140,7 @@ impl FromSql for Username { } } -pub trait AuthenticationDB { +pub trait AuthenticationDB: Send + Sync { fn create_user(&mut self, username: Username) -> AppResult; fn create_invitation(&mut self, user: UserId) -> AppResult; diff --git a/server/src/main.rs b/server/src/main.rs index b293ee8..83a8b7e 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -6,11 +6,43 @@ use std::{ use warp::Filter; mod authentication; -use authentication::{AuthenticationDB, MemoryAuth, Username}; +use authentication::{AuthenticationDB, AuthenticationError, MemoryAuth, UserId, Username}; mod database; mod errors; +#[derive(Debug)] +struct AuthenticationRefused; +impl warp::reject::Reject for AuthenticationRefused {} + +fn with_authentication( + auth_ctx: Arc>, +) -> impl Filter + Clone { + let auth_ctx = auth_ctx.clone(); + warp::header("authentication").and_then({ + let auth_ctx = auth_ctx.clone(); + move |auth_header: String| { + let auth_ctx = auth_ctx.clone(); + async move { + if auth_header.starts_with("Basic ") { + let username = auth_header.split(" ").skip(1).collect::(); + match auth_ctx + .read() + .unwrap() + .get_user_id(Username::from(username.as_str())) + { + Ok(Ok(userid)) => Ok((Username::from(username.as_str()), userid)), + Ok(Err(_)) => Err(warp::reject::custom(AuthenticationRefused)), + Err(err) => panic!("{}", err), + } + } else { + Err(warp::reject::custom(AuthenticationRefused)) + } + } + } + }) +} + #[derive(Serialize)] struct ErrorResponse { error: String, @@ -26,52 +58,52 @@ struct MakeUserResponse { userid: String, } +fn make_user( + auth_ctx: Arc>, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "users") + .and(warp::put()) + .and(warp::body::json()) + .map(move |params: MakeUserParameters| { + let mut auth_ctx = auth_ctx.write().unwrap(); + match (*auth_ctx).create_user(Username::from(params.username.as_str())) { + Ok(Ok(userid)) => warp::reply::json(&MakeUserResponse { + userid: String::from(userid), + }), + Ok(auth_error) => warp::reply::json(&ErrorResponse { + error: format!("{:?}", auth_error), + }), + Err(err) => panic!("{}", err), + } + }) +} + +fn list_users( + auth_ctx: Arc>, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "users") + .and(warp::get()) + .map(move || { + let auth_ctx = auth_ctx.read().unwrap(); + match (*auth_ctx).list_users() { + Ok(Ok(users)) => warp::reply::json( + &users + .iter() + .map(|u| String::from(u)) + .collect::>(), + ), + Ok(auth_error) => warp::reply::json(&ErrorResponse { + error: format!("{:?}", auth_error), + }), + Err(err) => panic!("{}", err), + } + }) +} + #[tokio::main] pub async fn main() { let auth_ctx: Arc> = Arc::new(RwLock::new(Default::default())); - let make_user = { - let auth_ctx = auth_ctx.clone(); - warp::path!("api" / "v1" / "user") - .and(warp::put()) - .and(warp::body::json()) - .map(move |params: MakeUserParameters| { - let mut auth_ctx = auth_ctx.write().unwrap(); - println!("{:?}", *auth_ctx); - match (*auth_ctx).create_user(Username::from(params.username.as_str())) { - Ok(Ok(userid)) => warp::reply::json(&MakeUserResponse { - userid: String::from(userid), - }), - Ok(auth_error) => warp::reply::json(&ErrorResponse { - error: format!("{:?}", auth_error), - }), - Err(err) => panic!("{}", err), - } - }) - }; - - let list_users = { - let auth_ctx = auth_ctx.clone(); - warp::path!("api" / "v1" / "user") - .and(warp::get()) - .map(move || { - let auth_ctx = auth_ctx.read().unwrap(); - println!("{:?}", *auth_ctx); - match (*auth_ctx).list_users() { - Ok(Ok(users)) => warp::reply::json( - &users - .iter() - .map(|u| String::from(u)) - .collect::>(), - ), - Ok(auth_error) => warp::reply::json(&ErrorResponse { - error: format!("{:?}", auth_error), - }), - Err(err) => panic!("{}", err), - } - }) - }; - let echo_unauthenticated = warp::path!("api" / "v1" / "echo" / String).map(|param: String| { println!("param: {}", param); warp::reply::json(&vec!["unauthenticated", param.as_str()]) @@ -85,15 +117,16 @@ pub async fn main() { */ let echo_authenticated = warp::path!("api" / "v1" / "echo" / String) - .and(warp::header::("authentication")) - .map(|auth: String, param: String| { - println!("auth: {}", auth); + .and(with_authentication(auth_ctx.clone())) + .map(|param: String, (username, userid)| { + println!("param: {:?}", username); + println!("param: {:?}", userid); println!("param: {}", param); warp::reply::json(&vec!["authed", param.as_str()]) }); - let filter = list_users - .or(make_user) + let filter = list_users(auth_ctx.clone()) + .or(make_user(auth_ctx.clone())) .or(echo_authenticated) .or(echo_unauthenticated);