diff --git a/crates/dav/src/lib.rs b/crates/dav/src/lib.rs index 777c904..7a5eb37 100644 --- a/crates/dav/src/lib.rs +++ b/crates/dav/src/lib.rs @@ -1,9 +1,9 @@ use actix_web::http::Method; use actix_web::web::{self, Data}; use actix_web::{guard, HttpResponse, Responder}; -use actix_web_httpauth::middleware::HttpAuthentication; use error::Error; use routes::{calendar, event, principal, root}; +use rustical_auth::CheckAuthentication; use rustical_store::calendar::CalendarStore; use std::str::FromStr; use std::sync::Arc; @@ -24,7 +24,6 @@ pub fn configure_well_known(cfg: &mut web::ServiceConfig, caldav_root: String) { cfg.service(web::redirect("/caldav", caldav_root).permanent()); } -pub fn configure_dav( pub fn configure_dav( cfg: &mut web::ServiceConfig, prefix: String, @@ -34,16 +33,9 @@ pub fn configure_dav( let propfind_method = || Method::from_str("PROPFIND").unwrap(); let report_method = || Method::from_str("REPORT").unwrap(); - let auth = HttpAuthentication::basic(|req, creds| async move { - if creds.user_id().is_empty() { - // not authenticated - Err((actix_web::error::ErrorUnauthorized("Unauthorized"), req)) - } else { - Ok(req) - } - }); cfg.app_data(Data::new(CalDavContext { prefix, store })) + .app_data(Data::from(auth)) .service( web::resource("{path:.*}") // Without the guard this service would handle all requests @@ -52,26 +44,24 @@ pub fn configure_dav( ) .service( web::resource("") - .route(web::method(propfind_method()).to(root::route_propfind_root::)) - .wrap(auth.clone()), + .route(web::method(propfind_method()).to(root::route_propfind_root::)), ) .service( - web::resource("/{principal}") - .route(web::method(propfind_method()).to(principal::route_propfind_principal::)) - .wrap(auth.clone()), + web::resource("/{principal}").route( + web::method(propfind_method()).to(principal::route_propfind_principal::), + ), ) .service( web::resource("/{principal}/{calendar}") - .route(web::method(report_method()).to(calendar::route_report_calendar::)) - .route(web::method(propfind_method()).to(calendar::route_propfind_calendar::)) - .wrap(auth.clone()), + .route(web::method(report_method()).to(calendar::route_report_calendar::)) + .route(web::method(propfind_method()).to(calendar::route_propfind_calendar::)) + .route(web::method(mkcol_method()).to(calendar::route_mkcol_calendar::)), ) .service( web::resource("/{principal}/{calendar}/{event}") - .route(web::method(Method::DELETE).to(event::delete_event::)) - .route(web::method(Method::GET).to(event::get_event::)) - .route(web::method(Method::PUT).to(event::put_event::)) - .wrap(auth.clone()), + .route(web::method(Method::DELETE).to(event::delete_event::)) + .route(web::method(Method::GET).to(event::get_event::)) + .route(web::method(Method::PUT).to(event::put_event::)), ); } diff --git a/crates/dav/src/routes/calendar.rs b/crates/dav/src/routes/calendar.rs index 9b1799c..beb71e6 100644 --- a/crates/dav/src/routes/calendar.rs +++ b/crates/dav/src/routes/calendar.rs @@ -1,3 +1,4 @@ +use rustical_auth::{AuthInfoExtractor, CheckAuthentication}; use crate::namespace::Namespace; use crate::propfind::{ generate_multistatus, parse_propfind, write_invalid_props_response, write_propstat_response, @@ -8,7 +9,6 @@ use actix_web::http::header::ContentType; use actix_web::http::StatusCode; use actix_web::web::{Data, Path}; use actix_web::{HttpRequest, HttpResponse}; -use actix_web_httpauth::extractors::basic::BasicAuth; use anyhow::Result; use quick_xml::events::BytesText; use quick_xml::Writer; @@ -69,12 +69,14 @@ async fn handle_report_calendar_query( .body(output)) } -pub async fn route_report_calendar( +pub async fn route_report_calendar( context: Data>, body: String, path: Path<(String, String)>, request: HttpRequest, + _auth: AuthInfoExtractor, ) -> Result { + // TODO: Check authorization let (_principal, cid) = path.into_inner(); let doc = roxmltree::Document::parse(&body).map_err(|_e| Error::InternalError)?; @@ -167,13 +169,14 @@ pub fn generate_propfind_calendar_response( Ok(std::str::from_utf8(&output_buffer)?.to_string()) } -pub async fn route_propfind_calendar( +pub async fn route_propfind_calendar( path: Path<(String, String)>, body: String, request: HttpRequest, - auth: BasicAuth, context: Data>, + auth: AuthInfoExtractor, ) -> Result { + // TODO: Check authorization let (_principal, cid) = path.into_inner(); let calendar = context .store @@ -187,7 +190,7 @@ pub async fn route_propfind_calendar( let responses_string = generate_propfind_calendar_response( props.clone(), - auth.user_id(), + &auth.inner.user_id, request.path(), &context.prefix, &calendar, diff --git a/crates/dav/src/routes/event.rs b/crates/dav/src/routes/event.rs index 84ca750..3075041 100644 --- a/crates/dav/src/routes/event.rs +++ b/crates/dav/src/routes/event.rs @@ -1,12 +1,16 @@ use crate::{CalDavContext, Error}; use actix_web::web::{Data, Path}; use actix_web::HttpResponse; +use rustical_auth::{AuthInfoExtractor, CheckAuthentication}; use rustical_store::calendar::CalendarStore; -pub async fn delete_event( +pub async fn delete_event( context: Data>, path: Path<(String, String, String)>, + auth: AuthInfoExtractor, ) -> Result { + let _user = auth.inner.user_id; + // TODO: verify whether user is authorized let (_principal, mut cid, uid) = path.into_inner(); if cid.ends_with(".ics") { cid.truncate(cid.len() - 4); @@ -22,13 +26,12 @@ pub async fn delete_event( Ok(HttpResponse::Ok().body("")) } -pub async fn get_event( +pub async fn get_event( context: Data>, path: Path<(String, String, String)>, + _auth: AuthInfoExtractor, ) -> Result { - let (_principal, mut cid, uid) = path.into_inner(); - if cid.ends_with(".ics") { - cid.truncate(cid.len() - 4); + // TODO: verify whether user is authorized } let event = context .store @@ -43,10 +46,11 @@ pub async fn get_event( .body(event.to_ics().to_string())) } -pub async fn put_event( +pub async fn put_event( context: Data>, path: Path<(String, String, String)>, body: String, + _auth: AuthInfoExtractor, ) -> Result { let (_principal, mut cid, uid) = path.into_inner(); // Incredibly bodged method of normalising the uid but works for a prototype diff --git a/crates/dav/src/routes/principal.rs b/crates/dav/src/routes/principal.rs index 6ce275b..8495f88 100644 --- a/crates/dav/src/routes/principal.rs +++ b/crates/dav/src/routes/principal.rs @@ -13,12 +13,12 @@ use actix_web::{ web::Data, HttpRequest, HttpResponse, }; -use actix_web_httpauth::extractors::basic::BasicAuth; use anyhow::Result; use quick_xml::{ events::{BytesText, Event}, Writer, }; +use rustical_auth::{AuthInfoExtractor, CheckAuthentication}; use rustical_store::calendar::CalendarStore; // Executes the PROPFIND request and returns a XML string to be written into a object. @@ -86,13 +86,14 @@ pub async fn generate_propfind_principal_response( Ok(std::str::from_utf8(&output_buffer)?.to_string()) } -pub async fn route_propfind_principal( +pub async fn route_propfind_principal( body: String, request: HttpRequest, - auth: BasicAuth, + auth: AuthInfoExtractor, context: Data>, depth: Depth, ) -> Result { + let user = &auth.inner.user_id; let props = parse_propfind(&body).map_err(|_e| Error::BadRequest)?; let mut responses = Vec::new(); @@ -110,7 +111,7 @@ pub async fn route_propfind_principal( responses.push( generate_propfind_calendar_response( props.clone(), - auth.user_id(), + &auth.inner.user_id, &format!("{}/{}", request.path(), cal.id), &context.prefix, &cal, @@ -121,14 +122,9 @@ pub async fn route_propfind_principal( } responses.push( - generate_propfind_principal_response( - props.clone(), - auth.user_id(), - request.path(), - &context.prefix, - ) - .await - .map_err(|_e| Error::InternalError)?, + generate_propfind_principal_response(props.clone(), user, request.path(), &context.prefix) + .await + .map_err(|_e| Error::InternalError)?, ); let output = generate_multistatus(vec![Namespace::Dav, Namespace::CalDAV], |writer| { diff --git a/crates/dav/src/routes/root.rs b/crates/dav/src/routes/root.rs index 6b791da..9cdf28b 100644 --- a/crates/dav/src/routes/root.rs +++ b/crates/dav/src/routes/root.rs @@ -3,11 +3,11 @@ use actix_web::{ web::Data, HttpRequest, HttpResponse, }; -use actix_web_httpauth::extractors::basic::BasicAuth; use quick_xml::{ events::{BytesText, Event}, Writer, }; +use rustical_auth::{AuthInfoExtractor, CheckAuthentication}; use rustical_store::calendar::CalendarStore; use crate::{ @@ -64,22 +64,19 @@ pub async fn generate_propfind_root_response( Ok(std::str::from_utf8(&output_buffer)?.to_string()) } -pub async fn route_propfind_root( +pub async fn route_propfind_root( body: String, request: HttpRequest, - auth: BasicAuth, context: Data>, + auth: AuthInfoExtractor, ) -> Result { + let principal = &auth.inner.user_id; let props = parse_propfind(&body).map_err(|_e| Error::BadRequest)?; - let responses_string = generate_propfind_root_response( - props.clone(), - auth.user_id(), - request.path(), - &context.prefix, - ) - .await - .map_err(|_e| Error::InternalError)?; + let responses_string = + generate_propfind_root_response(props.clone(), principal, request.path(), &context.prefix) + .await + .map_err(|_e| Error::InternalError)?; let output = generate_multistatus(vec![Namespace::Dav, Namespace::CalDAV], |writer| { writer.write_event(Event::Text(BytesText::from_escaped(responses_string)))?;