From b9903d6331af7b2c0b86fe5d02d18cec40f3968a Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 31 Jan 2019 12:22:00 +0100 Subject: [PATCH] server/rest.rs: verify auth cookie --- src/api2/access.rs | 2 +- src/server/rest.rs | 32 ++++++++++++++++++++++++++++++-- src/tools.rs | 24 ++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/api2/access.rs b/src/api2/access.rs index 390e54cf..3ffc4dcd 100644 --- a/src/api2/access.rs +++ b/src/api2/access.rs @@ -29,7 +29,7 @@ fn create_ticket( match authenticate_user(username, password) { Ok(_) => { - let ticket = assemble_rsa_ticket( private_auth_key(), "PBS", None, None)?; + let ticket = assemble_rsa_ticket( private_auth_key(), "PBS", Some(username), None)?; let token = assemble_csrf_prevention_token(csrf_secret(), username); diff --git a/src/server/rest.rs b/src/server/rest.rs index d9263778..787bf20f 100644 --- a/src/server/rest.rs +++ b/src/server/rest.rs @@ -2,6 +2,7 @@ use crate::tools; use crate::api::schema::*; use crate::api::router::*; use crate::api::config::*; +use crate::auth_helpers::*; use super::environment::RestEnvironment; use super::formatter::*; @@ -421,6 +422,20 @@ pub fn handle_request(api: Arc, req: Request) -> BoxFut { let env_type = api.env_type(); let mut rpcenv = RestEnvironment::new(env_type); + let delay_unauth_time = std::time::Instant::now() + std::time::Duration::from_millis(3000); + + if let Some(raw_cookie) = parts.headers.get("COOKIE") { + if let Ok(cookie) = raw_cookie.to_str() { + if let Some(ticket) = tools::extract_auth_cookie(cookie, "PBSAuthCookie") { + if let Ok((_, Some(username))) = tools::ticket::verify_rsa_ticket( + public_auth_key(), "PBS", &ticket, None, -300, 3600*2) { + rpcenv.set_user(Some(username)); + } + } + } + } + + if comp_len >= 1 && components[0] == "api2" { println!("GOT API REQUEST"); if comp_len >= 2 { @@ -435,8 +450,21 @@ pub fn handle_request(api: Arc, req: Request) -> BoxFut { let mut uri_param = HashMap::new(); - // fixme: handle auth - rpcenv.set_user(Some(String::from("root@pam"))); + if comp_len == 4 && components[2] == "access" && components[3] == "ticket" { + // explicitly allow those calls without auth + } else { + if let Some(_username) = rpcenv.get_user() { + // fixme: check permissions + } else { + // always delay unauthorized calls by 3 seconds (from start of request) + let resp = (formatter.format_error)(http_err!(UNAUTHORIZED, "permission check failed.".into())); + let delayed_response = tokio::timer::Delay::new(delay_unauth_time) + .map_err(|err| http_err!(INTERNAL_SERVER_ERROR, format!("tokio timer delay error: {}", err))) + .and_then(|_| Ok(resp)); + + return Box::new(delayed_response); + } + } match api.find_method(&components[2..], method, &mut uri_param) { MethodDefinition::None => {} diff --git a/src/tools.rs b/src/tools.rs index 8b522cd3..6932fc56 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -416,3 +416,27 @@ pub fn assert_if_modified(digest1: &str, digest2: &str) -> Result<(), Error> { } Ok(()) } + +/// Extract authentication cookie from cookie header. +/// We assume cookie_name is already url encoded. +pub fn extract_auth_cookie(cookie: &str, cookie_name: &str) -> Option { + + for pair in cookie.split(';') { + + let (name, value) = match pair.find('=') { + Some(i) => (pair[..i].trim(), pair[(i + 1)..].trim()), + None => return None, // Cookie format error + }; + + if name == cookie_name { + use url::percent_encoding::percent_decode; + if let Ok(value) = percent_decode(value.as_bytes()).decode_utf8() { + return Some(value.into()); + } else { + return None; // Cookie format error + } + } + } + + None +}