src/config/cached_user_info.rs: cache it up to 5 seconds
This commit is contained in:
		| @ -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)); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user