From 56bb1d4e23b7bd4a2721d1ef9be08a94c92341bf Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sat, 6 May 2017 20:22:10 -0700 Subject: [PATCH] Added support for http Authorization header --- src/api.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/src/api.rs b/src/api.rs index 2de873c..e4d1ce1 100644 --- a/src/api.rs +++ b/src/api.rs @@ -5,8 +5,8 @@ use std::ops::Deref; use std::sync::Arc; use iron::prelude::*; -use iron::headers::CookiePair; -use iron::{BeforeMiddleware, status}; +use iron::headers::{Authorization, Basic, CookiePair}; +use iron::{AroundMiddleware, Handler, status}; use mount::Mount; use oven::prelude::*; use params; @@ -19,7 +19,7 @@ use thumbnails::*; use utils::*; const CURRENT_MAJOR_VERSION: i32 = 1; -const CURRENT_MINOR_VERSION: i32 = 1; +const CURRENT_MINOR_VERSION: i32 = 2; #[derive(RustcEncodable)] struct Version { @@ -74,7 +74,8 @@ pub fn get_api_handler(collection: Arc) -> Mount { } let mut auth_api_chain = Chain::new(auth_api_mount); - auth_api_chain.link_before(AuthRequirement); + let auth = AuthRequirement { collection:collection.clone() }; + auth_api_chain.link_around(auth); api_handler.mount("/", auth_api_chain); } @@ -87,13 +88,65 @@ fn path_from_request(request: &Request) -> Result { Ok(PathBuf::from(decoded_path.deref())) } -struct AuthRequirement; -impl BeforeMiddleware for AuthRequirement { - fn before(&self, req: &mut Request) -> IronResult<()> { - match req.get_cookie("username") { - Some(_) => Ok(()), - None => Err(Error::from(ErrorKind::AuthenticationRequired).into()), +struct AuthRequirement { + collection: Arc, +} + +impl AroundMiddleware for AuthRequirement { + fn around(self, handler: Box) -> Box { + Box::new(AuthHandler { + collection: self.collection, + handler: handler + }) as Box + } +} + +struct AuthHandler { + handler: Box, + collection: Arc, +} + +fn set_cookie(username: &str, response: &mut Response) { + let mut username_cookie = CookiePair::new("username".to_string(), username.to_string()); + username_cookie.path = Some("/".to_owned()); + response.set_cookie(username_cookie); +} + +impl Handler for AuthHandler { + fn handle(&self, req: &mut Request) -> IronResult { + let mut username = None; + { + let mut auth_success = false; + + // Auth via Authorization header + if let Some(auth) = req.headers.get::>() { + if let Some(ref password) = auth.password { + auth_success = self.collection.auth(auth.username.as_str(), password.as_str()); + username = Some(auth.username.clone()); + } + } + + // Auth via Cookie + if !auth_success { + auth_success = req.get_cookie("username").is_some(); + } + + // Reject + if !auth_success { + return Err(Error::from(ErrorKind::AuthenticationRequired).into()); + } } + + let mut response = self.handler.handle(req); + + // Add cookie to response + if let Some(username) = username { + if let Ok(ref mut response) = response { + set_cookie(username.as_str(), response); + } + } + + response } } @@ -117,9 +170,7 @@ fn auth(request: &mut Request, collection: &Collection) -> IronResult }; if collection.auth(username.as_str(), password.as_str()) { let mut response = Response::with((status::Ok, "")); - let mut username_cookie = CookiePair::new("username".to_string(), username.clone()); - username_cookie.path = Some("/".to_owned()); - response.set_cookie(username_cookie); + set_cookie(username.as_str(), &mut response); Ok(response) } else { Err(Error::from(ErrorKind::IncorrectCredentials).into())