src/config/cached_user_info.rs: cache it up to 5 seconds

This commit is contained in:
Dietmar Maurer 2020-04-18 08:49:20 +02:00
parent 365f0f720c
commit 6e695960ca
2 changed files with 37 additions and 8 deletions

View File

@ -1,10 +1,11 @@
//! Cached user info for fast ACL permission checks
use std::sync::Arc;
use std::sync::{RwLock, Arc};
use anyhow::{Error, bail};
use proxmox::api::section_config::SectionConfigData;
use lazy_static::lazy_static;
use proxmox::api::UserInformation;
use super::acl::{AclTree, ROLE_NAMES};
@ -16,14 +17,43 @@ pub struct CachedUserInfo {
acl_tree: Arc<AclTree>,
}
fn now() -> i64 { unsafe { libc::time(std::ptr::null_mut()) } }
struct ConfigCache {
data: Option<Arc<CachedUserInfo>>,
last_update: i64,
}
lazy_static! {
static ref CACHED_CONFIG: RwLock<ConfigCache> = RwLock::new(
ConfigCache { data: None, last_update: 0 }
);
}
impl CachedUserInfo {
/// Creates a new instance.
pub fn new() -> Result<Self, Error> {
Ok(CachedUserInfo {
/// Returns a cached instance (up to 5 seconds old).
pub fn new() -> Result<Arc<Self>, Error> {
let now = now();
{ // limit scope
let cache = CACHED_CONFIG.read().unwrap();
if (now - cache.last_update) < 5 {
if let Some(ref config) = cache.data {
return Ok(config.clone());
}
}
}
let config = Arc::new(CachedUserInfo {
user_cfg: super::user::cached_config()?,
acl_tree: super::acl::cached_config()?,
})
});
let mut cache = CACHED_CONFIG.write().unwrap();
cache.last_update = now;
cache.data = Some(config.clone());
Ok(config)
}
/// Test if a user account is enabled and not expired
@ -34,8 +64,7 @@ impl CachedUserInfo {
}
if let Some(expire) = info.expire {
if expire > 0 {
let now = unsafe { libc::time(std::ptr::null_mut()) };
if expire <= now {
if expire <= now() {
return false;
}
}

View File

@ -562,7 +562,7 @@ pub async fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> Result<R
}
Some(api_method) => {
let user = rpcenv.get_user();
if !check_api_permission(api_method.access.permission, user.as_deref(), &uri_param, &user_info) {
if !check_api_permission(api_method.access.permission, user.as_deref(), &uri_param, user_info.as_ref()) {
let err = http_err!(FORBIDDEN, format!("permission check failed"));
tokio::time::delay_until(Instant::from_std(access_forbidden_time)).await;
return Ok((formatter.format_error)(err));