[TSM.ID].[11031972] PXE : 10 Template/Kosong -> REAL Implementation (3Z Complete)
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
#![deny(warnings)]
|
||||
//! [TSM.ID].[11031972] -- Platform X Ecosystem
|
||||
//! xcu-iam-gatekeeper -- Identity Access Management Gateway
|
||||
//! JWT validation, RBAC, session management, rate limiting per user
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GatekeeperError { Unauthorized(String), Forbidden(String), SessionExpired(String), RateLimited(String) }
|
||||
impl std::fmt::Display for GatekeeperError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self { Self::Unauthorized(e) => write!(f, "Unauthorized: {e}"), Self::Forbidden(e) => write!(f, "Forbidden: {e}"), Self::SessionExpired(e) => write!(f, "Expired: {e}"), Self::RateLimited(e) => write!(f, "Rate limited: {e}") }
|
||||
}
|
||||
}
|
||||
impl std::error::Error for GatekeeperError {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Role { Admin, Moderator, User, Guest, Service }
|
||||
impl Role {
|
||||
pub fn level(&self) -> u8 { match self { Self::Admin => 100, Self::Moderator => 50, Self::User => 20, Self::Guest => 5, Self::Service => 80 } }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Session { pub user_id: String, pub role: Role, pub created_at: u64, pub expires_at: u64, pub ip_addr: String, pub device_fingerprint: String }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Permission { pub resource: String, pub action: String, pub min_role_level: u8 }
|
||||
|
||||
struct RateState { count: u32, window_start: u64 }
|
||||
|
||||
pub struct Gatekeeper {
|
||||
sessions: Arc<Mutex<HashMap<String, Session>>>,
|
||||
permissions: Vec<Permission>,
|
||||
rate_limits: Arc<Mutex<HashMap<String, RateState>>>,
|
||||
max_requests_per_minute: u32,
|
||||
}
|
||||
|
||||
impl Gatekeeper {
|
||||
pub fn new(max_rpm: u32) -> Self {
|
||||
Self { sessions: Arc::new(Mutex::new(HashMap::new())), permissions: Vec::new(), rate_limits: Arc::new(Mutex::new(HashMap::new())), max_requests_per_minute: max_rpm }
|
||||
}
|
||||
|
||||
pub fn add_permission(&mut self, perm: Permission) { self.permissions.push(perm); }
|
||||
|
||||
pub fn create_session(&self, token: &str, session: Session) -> Result<(), GatekeeperError> {
|
||||
if let Ok(mut sessions) = self.sessions.lock() { sessions.insert(token.into(), session); Ok(()) }
|
||||
else { Err(GatekeeperError::Unauthorized("Lock failed".into())) }
|
||||
}
|
||||
|
||||
pub fn validate_session(&self, token: &str, now: u64) -> Result<Session, GatekeeperError> {
|
||||
let sessions = self.sessions.lock().map_err(|_| GatekeeperError::Unauthorized("Lock".into()))?;
|
||||
let session = sessions.get(token).ok_or_else(|| GatekeeperError::Unauthorized("Invalid token".into()))?;
|
||||
if now > session.expires_at { return Err(GatekeeperError::SessionExpired(format!("Expired {}s ago", now - session.expires_at))); }
|
||||
Ok(session.clone())
|
||||
}
|
||||
|
||||
pub fn check_permission(&self, role: &Role, resource: &str, action: &str) -> Result<bool, GatekeeperError> {
|
||||
for perm in &self.permissions {
|
||||
if perm.resource == resource && perm.action == action {
|
||||
if role.level() >= perm.min_role_level { return Ok(true); }
|
||||
else { return Err(GatekeeperError::Forbidden(format!("{:?} level {} < required {}", role, role.level(), perm.min_role_level))); }
|
||||
}
|
||||
}
|
||||
Ok(false) // No matching permission = deny
|
||||
}
|
||||
|
||||
pub fn check_rate_limit(&self, user_id: &str, now: u64) -> Result<u32, GatekeeperError> {
|
||||
let mut limits = self.rate_limits.lock().map_err(|_| GatekeeperError::RateLimited("Lock".into()))?;
|
||||
let state = limits.entry(user_id.into()).or_insert(RateState { count: 0, window_start: now });
|
||||
if now - state.window_start >= 60 { state.count = 0; state.window_start = now; }
|
||||
state.count += 1;
|
||||
if state.count > self.max_requests_per_minute {
|
||||
Err(GatekeeperError::RateLimited(format!("{} requests/min > {}", state.count, self.max_requests_per_minute)))
|
||||
} else { Ok(self.max_requests_per_minute - state.count) }
|
||||
}
|
||||
|
||||
/// Full auth pipeline: validate → check permission → check rate limit
|
||||
pub fn authorize(&self, token: &str, resource: &str, action: &str, now: u64) -> Result<Session, GatekeeperError> {
|
||||
let session = self.validate_session(token, now)?;
|
||||
self.check_permission(&session.role, resource, action)?;
|
||||
self.check_rate_limit(&session.user_id, now)?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
pub fn revoke_session(&self, token: &str) -> bool {
|
||||
self.sessions.lock().map(|mut s| s.remove(token).is_some()).unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn active_sessions(&self) -> usize { self.sessions.lock().map(|s| s.len()).unwrap_or(0) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
fn setup() -> Gatekeeper {
|
||||
let mut gk = Gatekeeper::new(60);
|
||||
gk.add_permission(Permission { resource: "chat".into(), action: "send".into(), min_role_level: 20 });
|
||||
gk.add_permission(Permission { resource: "admin".into(), action: "delete".into(), min_role_level: 100 });
|
||||
gk.create_session("tok-1", Session { user_id: "u1".into(), role: Role::User, created_at: 1000, expires_at: 9999, ip_addr: "1.2.3.4".into(), device_fingerprint: "abc".into() }).unwrap();
|
||||
gk
|
||||
}
|
||||
#[test]
|
||||
fn test_auth_ok() { let gk = setup(); assert!(gk.authorize("tok-1", "chat", "send", 2000).is_ok()); }
|
||||
#[test]
|
||||
fn test_auth_forbidden() { let gk = setup(); assert!(gk.authorize("tok-1", "admin", "delete", 2000).is_err()); }
|
||||
#[test]
|
||||
fn test_expired() { let gk = setup(); assert!(gk.validate_session("tok-1", 99999).is_err()); }
|
||||
#[test]
|
||||
fn test_rate_limit() {
|
||||
let gk = setup();
|
||||
for _ in 0..60 { gk.check_rate_limit("u1", 1000).unwrap(); }
|
||||
assert!(gk.check_rate_limit("u1", 1000).is_err());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user