proxmox-rest-server: make check_auth async

This commit is contained in:
Dietmar Maurer 2021-10-01 07:29:11 +02:00
parent b914b94773
commit 038f385089
5 changed files with 59 additions and 35 deletions

View File

@ -1,5 +1,7 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::collections::HashMap; use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use anyhow::{bail, format_err, Error}; use anyhow::{bail, format_err, Error};
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -26,15 +28,17 @@ impl UserInformation for DummyUserInfo {
struct DummyAuth; struct DummyAuth;
impl ApiAuth for DummyAuth { impl ApiAuth for DummyAuth {
fn check_auth( fn check_auth<'a>(
&self, &'a self,
_headers: &http::HeaderMap, _headers: &'a http::HeaderMap,
_method: &hyper::Method, _method: &'a hyper::Method,
) -> Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError> { ) -> Pin<Box<dyn Future<Output = Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError>> + Send + 'a>> {
// get some global/cached userinfo Box::pin(async move {
let userinfo = DummyUserInfo; // get some global/cached userinfo
// Do some user checks, e.g. cookie/csrf let userinfo: Box<dyn UserInformation + Sync + Send> = Box::new(DummyUserInfo);
Ok(("User".to_string(), Box::new(userinfo))) // Do some user checks, e.g. cookie/csrf
Ok(("User".to_string(), userinfo))
})
} }
} }

View File

@ -16,6 +16,8 @@
//! * generic interface to authenticate user //! * generic interface to authenticate user
use std::sync::atomic::{Ordering, AtomicBool}; use std::sync::atomic::{Ordering, AtomicBool};
use std::future::Future;
use std::pin::Pin;
use anyhow::{bail, format_err, Error}; use anyhow::{bail, format_err, Error};
use nix::unistd::Pid; use nix::unistd::Pid;
@ -74,11 +76,11 @@ pub trait ApiAuth {
/// ///
/// If credenthials are valid, returns the username and a /// If credenthials are valid, returns the username and a
/// [UserInformation] object to query additional user data. /// [UserInformation] object to query additional user data.
fn check_auth( fn check_auth<'a>(
&self, &'a self,
headers: &http::HeaderMap, headers: &'a http::HeaderMap,
method: &hyper::Method, method: &'a hyper::Method,
) -> Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError>; ) -> Pin<Box<dyn Future<Output = Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError>> + Send + 'a>>;
} }
lazy_static::lazy_static!{ lazy_static::lazy_static!{

View File

@ -654,7 +654,7 @@ async fn handle_request(
let mut user_info: Box<dyn UserInformation + Send + Sync> = Box::new(EmptyUserInformation {}); let mut user_info: Box<dyn UserInformation + Send + Sync> = Box::new(EmptyUserInformation {});
if auth_required { if auth_required {
match auth.check_auth(&parts.headers, &method) { match auth.check_auth(&parts.headers, &method).await {
Ok((authid, info)) => { Ok((authid, info)) => {
rpcenv.set_auth_id(Some(authid)); rpcenv.set_auth_id(Some(authid));
user_info = info; user_info = info;
@ -726,7 +726,7 @@ async fn handle_request(
if comp_len == 0 { if comp_len == 0 {
let language = extract_lang_header(&parts.headers); let language = extract_lang_header(&parts.headers);
match auth.check_auth(&parts.headers, &method) { match auth.check_auth(&parts.headers, &method).await {
Ok((auth_id, _user_info)) => { Ok((auth_id, _user_info)) => {
return Ok(api.get_index(Some(auth_id), language, parts)); return Ok(api.get_index(Some(auth_id), language, parts));
} }

View File

@ -1,6 +1,8 @@
//! Authentication via a static ticket file //! Authentication via a static ticket file
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::future::Future;
use std::pin::Pin;
use anyhow::{bail, format_err, Error}; use anyhow::{bail, format_err, Error};
@ -25,21 +27,25 @@ pub struct StaticAuth {
} }
impl ApiAuth for StaticAuth { impl ApiAuth for StaticAuth {
fn check_auth( fn check_auth<'a>(
&self, &'a self,
headers: &http::HeaderMap, headers: &'a http::HeaderMap,
_method: &hyper::Method, _method: &'a hyper::Method,
) -> Result<(String, Box<dyn UserInformation + Send + Sync>), AuthError> { ) -> Pin<Box<dyn Future<Output = Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError>> + Send + 'a>> {
match headers.get(hyper::header::AUTHORIZATION) { Box::pin(async move {
Some(header) if header.to_str().unwrap_or("") == &self.ticket => {
Ok((String::from("root@pam"), Box::new(SimpleUserInformation {}))) match headers.get(hyper::header::AUTHORIZATION) {
Some(header) if header.to_str().unwrap_or("") == &self.ticket => {
let user_info: Box<dyn UserInformation + Send + Sync> = Box::new(SimpleUserInformation {});
Ok((String::from("root@pam"), user_info))
}
_ => {
return Err(AuthError::Generic(format_err!(
"invalid file restore ticket provided"
)));
}
} }
_ => { })
return Err(AuthError::Generic(format_err!(
"invalid file restore ticket provided"
)));
}
}
} }
} }

View File

@ -1,7 +1,10 @@
//! Provides authentication primitives for the HTTP server //! Provides authentication primitives for the HTTP server
use anyhow::format_err;
use std::sync::Arc; use std::sync::Arc;
use std::future::Future;
use std::pin::Pin;
use anyhow::format_err;
use proxmox::api::UserInformation; use proxmox::api::UserInformation;
@ -55,16 +58,15 @@ impl UserApiAuth {
_ => None, _ => None,
} }
} }
}
impl ApiAuth for UserApiAuth { async fn check_auth_async(
fn check_auth(
&self, &self,
headers: &http::HeaderMap, headers: &http::HeaderMap,
method: &hyper::Method, method: &hyper::Method,
) -> Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError> { ) -> Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError> {
// fixme: make all IO async
let user_info = CachedUserInfo::new()?; let user_info = CachedUserInfo::new()?;
let auth_data = Self::extract_auth_data(headers); let auth_data = Self::extract_auth_data(headers);
@ -124,3 +126,13 @@ impl ApiAuth for UserApiAuth {
} }
} }
} }
impl ApiAuth for UserApiAuth {
fn check_auth<'a>(
&'a self,
headers: &'a http::HeaderMap,
method: &'a hyper::Method,
) -> Pin<Box<dyn Future<Output = Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError>> + Send + 'a>> {
Box::pin(self.check_auth_async(headers, method))
}
}