//! Shared TLS types for Foxhunt services. //! //! This module contains type definitions shared across all service TLS configurations: //! - [`TlsProtocolVersion`] - TLS 1.2 / 1.3 selection //! - [`UserRole`] - RBAC roles extracted from client certificates //! - [`ClientIdentity`] - Client identity extracted from mTLS certificates //! //! Each service retains its own `TlsConfig` struct and validation logic because //! the validation approaches differ (async vs sync, delegated vs monolithic). /// TLS protocol version options. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TlsProtocolVersion { /// TLS version 1.2 Tls12, /// TLS version 1.3 Tls13, } /// User roles based on certificate attributes (RBAC). #[derive(Debug, Clone, PartialEq, Eq)] pub enum UserRole { /// Administrator with full access Admin, /// Trader with trading permissions Trader, /// Analyst with read/analysis permissions Analyst, /// Risk manager with risk oversight RiskManager, /// Compliance officer with audit access ComplianceOfficer, /// Read-only access ReadOnly, } impl UserRole { /// Get permissions for this role. pub fn get_permissions(&self) -> Vec<&'static str> { match self { UserRole::Admin => vec![ "trading.submit_order", "trading.cancel_order", "trading.modify_order", "risk.view_positions", "risk.modify_limits", "analytics.view_data", "analytics.run_backtest", "compliance.view_reports", "system.configure", ], UserRole::Trader => vec![ "trading.submit_order", "trading.cancel_order", "trading.modify_order", "risk.view_positions", "analytics.view_data", ], UserRole::Analyst => vec![ "analytics.view_data", "analytics.run_backtest", "risk.view_positions", ], UserRole::RiskManager => vec![ "risk.view_positions", "risk.modify_limits", "analytics.view_data", "compliance.view_reports", ], UserRole::ComplianceOfficer => vec![ "compliance.view_reports", "analytics.view_data", "risk.view_positions", ], UserRole::ReadOnly => vec!["analytics.view_data"], } } } /// Client identity extracted from mTLS certificate. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ClientIdentity { /// Common Name (CN) from certificate pub common_name: String, /// Organizational Unit (OU) from certificate pub organizational_unit: String, /// Certificate serial number pub serial_number: String, /// Certificate issuer pub issuer: String, } impl ClientIdentity { /// Check if client is authorized for trading operations. pub fn is_authorized_for_trading(&self) -> bool { matches!(self.organizational_unit.as_str(), "trading" | "admin") } /// Check if client is authorized for read-only operations. pub fn is_authorized_for_readonly(&self) -> bool { matches!( self.organizational_unit.as_str(), "trading" | "admin" | "analytics" | "risk" | "compliance" ) } /// Get user role based on certificate. pub fn get_role(&self) -> UserRole { match self.organizational_unit.as_str() { "admin" => UserRole::Admin, "trading" => UserRole::Trader, "analytics" => UserRole::Analyst, "risk" => UserRole::RiskManager, "compliance" => UserRole::ComplianceOfficer, _ => UserRole::ReadOnly, } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_client_identity_authorization() { let trading_identity = ClientIdentity { common_name: "trader1.trading.foxhunt.internal".to_string(), organizational_unit: "trading".to_string(), serial_number: "12345".to_string(), issuer: "Foxhunt Trading CA".to_string(), }; assert!(trading_identity.is_authorized_for_trading()); assert!(trading_identity.is_authorized_for_readonly()); assert_eq!(trading_identity.get_role(), UserRole::Trader); let readonly_identity = ClientIdentity { common_name: "analyst1.analytics.foxhunt.internal".to_string(), organizational_unit: "analytics".to_string(), serial_number: "12346".to_string(), issuer: "Foxhunt Trading CA".to_string(), }; assert!(!readonly_identity.is_authorized_for_trading()); assert!(readonly_identity.is_authorized_for_readonly()); assert_eq!(readonly_identity.get_role(), UserRole::Analyst); } #[test] fn test_user_role_permissions() { let trader = UserRole::Trader; let permissions = trader.get_permissions(); assert!(permissions.contains(&"trading.submit_order")); assert!(permissions.contains(&"trading.cancel_order")); assert!(!permissions.contains(&"system.configure")); let readonly = UserRole::ReadOnly; let readonly_permissions = readonly.get_permissions(); assert!(!readonly_permissions.contains(&"trading.submit_order")); assert!(readonly_permissions.contains(&"analytics.view_data")); } #[test] fn test_tls_protocol_version_equality() { let tls13 = TlsProtocolVersion::Tls13; let tls12 = TlsProtocolVersion::Tls12; assert_ne!(tls13, tls12); assert_eq!(tls13, TlsProtocolVersion::Tls13); } }