src/config/cached_user_info.rs: cache it up to 5 seconds
This commit is contained in:
parent
365f0f720c
commit
6e695960ca
|
@ -1,10 +1,11 @@
|
||||||
//! Cached user info for fast ACL permission checks
|
//! Cached user info for fast ACL permission checks
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::{RwLock, Arc};
|
||||||
|
|
||||||
use anyhow::{Error, bail};
|
use anyhow::{Error, bail};
|
||||||
|
|
||||||
use proxmox::api::section_config::SectionConfigData;
|
use proxmox::api::section_config::SectionConfigData;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use proxmox::api::UserInformation;
|
use proxmox::api::UserInformation;
|
||||||
|
|
||||||
use super::acl::{AclTree, ROLE_NAMES};
|
use super::acl::{AclTree, ROLE_NAMES};
|
||||||
|
@ -16,14 +17,43 @@ pub struct CachedUserInfo {
|
||||||
acl_tree: Arc<AclTree>,
|
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 {
|
impl CachedUserInfo {
|
||||||
|
|
||||||
/// Creates a new instance.
|
/// Returns a cached instance (up to 5 seconds old).
|
||||||
pub fn new() -> Result<Self, Error> {
|
pub fn new() -> Result<Arc<Self>, Error> {
|
||||||
Ok(CachedUserInfo {
|
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()?,
|
user_cfg: super::user::cached_config()?,
|
||||||
acl_tree: super::acl::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
|
/// Test if a user account is enabled and not expired
|
||||||
|
@ -34,8 +64,7 @@ impl CachedUserInfo {
|
||||||
}
|
}
|
||||||
if let Some(expire) = info.expire {
|
if let Some(expire) = info.expire {
|
||||||
if expire > 0 {
|
if expire > 0 {
|
||||||
let now = unsafe { libc::time(std::ptr::null_mut()) };
|
if expire <= now() {
|
||||||
if expire <= now {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -562,7 +562,7 @@ pub async fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> Result<R
|
||||||
}
|
}
|
||||||
Some(api_method) => {
|
Some(api_method) => {
|
||||||
let user = rpcenv.get_user();
|
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"));
|
let err = http_err!(FORBIDDEN, format!("permission check failed"));
|
||||||
tokio::time::delay_until(Instant::from_std(access_forbidden_time)).await;
|
tokio::time::delay_until(Instant::from_std(access_forbidden_time)).await;
|
||||||
return Ok((formatter.format_error)(err));
|
return Ok((formatter.format_error)(err));
|
||||||
|
|
Loading…
Reference in New Issue