server/rest.rs: verify auth cookie

This commit is contained in:
Dietmar Maurer 2019-01-31 12:22:00 +01:00
parent f484eed3c2
commit b9903d6331
3 changed files with 55 additions and 3 deletions

View File

@ -29,7 +29,7 @@ fn create_ticket(
match authenticate_user(username, password) { match authenticate_user(username, password) {
Ok(_) => { 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); let token = assemble_csrf_prevention_token(csrf_secret(), username);

View File

@ -2,6 +2,7 @@ use crate::tools;
use crate::api::schema::*; use crate::api::schema::*;
use crate::api::router::*; use crate::api::router::*;
use crate::api::config::*; use crate::api::config::*;
use crate::auth_helpers::*;
use super::environment::RestEnvironment; use super::environment::RestEnvironment;
use super::formatter::*; use super::formatter::*;
@ -421,6 +422,20 @@ pub fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> BoxFut {
let env_type = api.env_type(); let env_type = api.env_type();
let mut rpcenv = RestEnvironment::new(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" { if comp_len >= 1 && components[0] == "api2" {
println!("GOT API REQUEST"); println!("GOT API REQUEST");
if comp_len >= 2 { if comp_len >= 2 {
@ -435,8 +450,21 @@ pub fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> BoxFut {
let mut uri_param = HashMap::new(); let mut uri_param = HashMap::new();
// fixme: handle auth if comp_len == 4 && components[2] == "access" && components[3] == "ticket" {
rpcenv.set_user(Some(String::from("root@pam"))); // 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) { match api.find_method(&components[2..], method, &mut uri_param) {
MethodDefinition::None => {} MethodDefinition::None => {}

View File

@ -416,3 +416,27 @@ pub fn assert_if_modified(digest1: &str, digest2: &str) -> Result<(), Error> {
} }
Ok(()) 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<String> {
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
}