use crate::{middleware::AuthenticatedAdminMiddleware, model::AdminAuthCredentials, AppState}; use actix_web::{ post, web::{Data, Form}, HttpMessage, HttpRequest, HttpResponse, Responder, }; /// Performs administrator authentication from form data /// If the authentication succeed, a cookie with an auth token is returned /// If not, 401 is returned and if an auth cookie is found it is deleted. #[post("/admin-auth")] pub async fn admin_authentication<'a>( app_state: Data<AppState>, auth_mw: Data<AuthenticatedAdminMiddleware<'a>>, req: HttpRequest, form_data: Form<AdminAuthCredentials>, ) -> impl Responder { let cookie_opt = auth_mw.exec(&app_state, &req, Some(form_data)).await; match cookie_opt { Ok(cookie) => HttpResponse::Accepted().cookie(cookie).finish(), Err(_) => { return match req.cookie(auth_mw.cookie_name) { Some(c) => { // Invalidate auth_cookie if auth failed in any way HttpResponse::Unauthorized().del_cookie(&c).finish() } None => HttpResponse::Unauthorized().finish(), }; } } } /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@@ *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@@ * _______ ______ ______ _______ *@@ * |__ __@ | ____@ / ____@ |__ __@ *@@ * | @ | @__ \_ @_ | @ *@@ * | @ | __@ \ @_ | @ *@@ * | @ | @___ ____\ @ | @ *@@ * |__@ |______@ \______@ |__@ *@@ * *@@ *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@@ *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@*/ #[cfg(test)] mod test_admin_auth { use super::*; use crate::model::Administrator; use actix_web::{ http::{Method, StatusCode}, test, web::Data, App, }; use futures::stream::StreamExt; use wither::prelude::Model; #[tokio::test] async fn test_admin_auth() { dotenv::dotenv().ok(); let app_state = AppState::for_test().await; let admin_user = Administrator::find(&app_state.db, None, None) .await .unwrap() .next() .await .unwrap() .unwrap(); // Get the first admin user we find. At least one should exist. let password = app_state.encryption.decrypt(&admin_user.password_hash); let username = admin_user.username.to_owned(); let mut app = test::init_service( App::new() .app_data(Data::new(app_state.clone())) .app_data(Data::new(AuthenticatedAdminMiddleware::new( "kuadrado-admin-auth", ))) .service(admin_authentication), ) .await; let req = test::TestRequest::with_uri("/admin-auth") .method(Method::POST) .set_form(&AdminAuthCredentials { username, password }) .to_request(); let resp = test::call_service(&mut app, req).await; assert_eq!(resp.status(), StatusCode::ACCEPTED); } #[tokio::test] async fn test_admin_auth_unauthorized() { dotenv::dotenv().ok(); let app_state = AppState::for_test().await; let mut app = test::init_service( App::new() .app_data(Data::new(app_state.clone())) .app_data(Data::new(AuthenticatedAdminMiddleware::new( "kuadrado-admin-auth", ))) .service(admin_authentication), ) .await; let req = test::TestRequest::with_uri("/admin-auth") .method(Method::POST) .set_form(&AdminAuthCredentials { username: String::from("whatever"), password: String::from("whatever"), }) .to_request(); let resp = test::call_service(&mut app, req).await; assert_eq!(resp.status(), StatusCode::UNAUTHORIZED); } }