1use crate::errors::{AuthError, Result};
27use crate::server::oidc::OidcProvider;
28use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STANDARD};
29use chrono::{DateTime, Utc};
30use serde::{Deserialize, Serialize};
31use serde_json::{Value, json};
32use std::collections::HashMap;
33use std::sync::Arc;
34use std::time::SystemTime;
35use tokio::sync::RwLock;
36use uuid::Uuid;
37
38#[derive(Debug, Clone)]
40pub struct OidcExtensionsManager {
41 oidc_provider: Arc<OidcProvider<dyn crate::storage::AuthStorage>>,
43
44 heart_manager: Arc<HeartManager>,
46
47 shared_signals_manager: Arc<SharedSignalsManager>,
49
50 ekyc_manager: Arc<EkycManager>,
52
53 fastfed_manager: Arc<FastFedManager>,
55
56 config: OidcExtensionsConfig,
58}
59
60#[derive(Debug, Clone)]
62pub struct OidcExtensionsConfig {
63 pub enable_heart: bool,
65
66 pub enable_shared_signals: bool,
68
69 pub enable_ekyc: bool,
71
72 pub enable_fastfed: bool,
74
75 pub enable_modrna: bool,
77
78 pub enable_igov: bool,
80
81 pub enable_authzen: bool,
83}
84
85#[derive(Debug, Clone)]
89pub struct HeartManager {
90 config: HeartConfig,
92
93 sessions: Arc<RwLock<HashMap<String, HeartSession>>>,
95}
96
97#[derive(Debug, Clone)]
99pub struct HeartConfig {
100 pub organization_id: String,
102
103 pub fhir_endpoint: String,
105
106 pub required_scopes: Vec<String>,
108
109 pub enhanced_consent: bool,
111
112 pub authorized_providers: Vec<String>,
114
115 pub audit_config: HeartAuditConfig,
117}
118
119#[derive(Debug, Clone)]
121pub struct HeartAuditConfig {
122 pub enable_atna: bool,
124
125 pub syslog_endpoint: Option<String>,
127
128 pub audit_level: HeartAuditLevel,
130}
131
132#[derive(Debug, Clone, PartialEq)]
134pub enum HeartAuditLevel {
135 Basic,
137 Enhanced,
139 Full,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct HeartSession {
146 pub session_id: String,
148
149 pub patient_id: Option<String>,
151
152 pub provider_id: String,
154
155 pub authorized_resources: Vec<String>,
157
158 pub consent_status: ConsentStatus,
160
161 pub metadata: HashMap<String, Value>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
167pub enum ConsentStatus {
168 Granted,
170 Denied,
172 Pending,
174 Revoked,
176}
177
178#[derive(Debug, Clone)]
182pub struct SharedSignalsManager {
183 config: SharedSignalsConfig,
185
186 receivers: Arc<RwLock<HashMap<String, SignalReceiver>>>,
188
189 transmitters: Arc<RwLock<HashMap<String, SignalTransmitter>>>,
191}
192
193#[derive(Debug, Clone)]
195pub struct SharedSignalsConfig {
196 pub endpoint_url: String,
198
199 pub supported_events: Vec<String>,
201
202 pub max_event_age: i64,
204
205 pub verify_events: bool,
207}
208
209#[derive(Debug, Clone)]
211pub struct SignalReceiver {
212 pub receiver_id: String,
214
215 pub endpoint_url: String,
217
218 pub event_types: Vec<String>,
220
221 pub auth_method: SignalAuthMethod,
223}
224
225#[derive(Debug, Clone)]
227pub struct SignalTransmitter {
228 pub transmitter_id: String,
230
231 pub endpoints: Vec<String>,
233
234 pub event_buffer: Vec<SecurityEvent>,
236}
237
238impl SignalTransmitter {
239 pub async fn send_event(&self, event_jwt: &str, receiver_url: &str) -> Result<(), AuthError> {
241 use crate::server::core::common_config::EndpointConfig;
242 use crate::server::core::common_http::HttpClient;
243 use std::collections::HashMap;
244
245 let config = EndpointConfig::new(receiver_url);
247 let client = HttpClient::new(config)?;
248
249 let mut headers = HashMap::new();
251 headers.insert(
252 "Content-Type".to_string(),
253 "application/secevent+jwt".to_string(),
254 );
255 headers.insert("Accept".to_string(), "application/json".to_string());
256
257 let response = client
259 .request_with_headers(
260 reqwest::Method::POST,
261 "",
262 headers,
263 Some(&event_jwt.to_string()),
264 )
265 .await?;
266
267 if !response.status().is_success() {
268 let (status, body) =
269 crate::server::core::common_http::response::extract_error_details(response).await;
270 return Err(AuthError::internal(format!(
271 "Security event transmission failed with status {}: {}",
272 status, body
273 )));
274 }
275
276 tracing::info!(
277 "Successfully transmitted security event to: {}",
278 receiver_url
279 );
280 Ok(())
281 }
282}
283
284#[derive(Debug, Clone)]
286pub enum SignalAuthMethod {
287 Bearer(String),
289 MutualTls,
291 SignedJwt,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct SecurityEvent {
298 pub event_id: String,
300
301 pub event_type: String,
303
304 pub timestamp: DateTime<Utc>,
306
307 pub subject: String,
309
310 pub data: Value,
312
313 pub severity: EventSeverity,
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct AccountDisableRequest {
320 pub user_id: String,
322 pub reason: String,
324 pub disable_timestamp: DateTime<Utc>,
326 pub initiated_by: String,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
332pub enum EventSeverity {
333 Info,
335 Warning,
337 Critical,
339 Emergency,
341}
342
343#[derive(Debug, Clone)]
347pub struct EkycManager {
348 config: EkycConfig,
350
351 verification_sessions: Arc<RwLock<HashMap<String, EkycSession>>>,
353}
354
355#[derive(Debug, Clone)]
357pub struct EkycConfig {
358 pub verification_provider: String,
360
361 pub required_ial: IdentityAssuranceLevel,
363
364 pub verification_methods: Vec<VerificationMethod>,
366
367 pub document_verification: bool,
369
370 pub biometric_verification: bool,
372}
373
374#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
376pub enum IdentityAssuranceLevel {
377 IAL1,
379 IAL2,
381 IAL3,
383}
384
385#[derive(Debug, Clone, Serialize, Deserialize)]
387pub enum VerificationMethod {
388 Document,
390 Biometric,
392 Database,
394 KnowledgeBased,
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize)]
400pub struct EkycSession {
401 pub session_id: String,
403
404 pub user_id: String,
406
407 pub verification_status: VerificationStatus,
409
410 pub achieved_ial: IdentityAssuranceLevel,
412
413 pub verification_results: HashMap<String, Value>,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
419pub enum VerificationStatus {
420 Pending,
422 InProgress,
424 Success,
426 Failed,
428 Expired,
430}
431
432#[derive(Debug, Clone)]
436pub struct FastFedManager {
437 config: FastFedConfig,
439
440 federations: Arc<RwLock<HashMap<String, FederationRelationship>>>,
442}
443
444#[derive(Debug, Clone)]
446pub struct FastFedConfig {
447 pub metadata_endpoint: String,
449
450 pub supported_protocols: Vec<String>,
452
453 pub auto_provisioning: bool,
455
456 pub trusted_partners: Vec<String>,
458
459 pub trust_anchor: String,
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct FederationRelationship {
466 pub relationship_id: String,
468
469 pub partner_org: String,
471
472 pub status: FederationStatus,
474
475 pub config: Value,
477
478 pub created_at: DateTime<Utc>,
480}
481
482#[derive(Debug, Clone, Serialize, Deserialize)]
484pub enum FederationStatus {
485 Pending,
487 Active,
489 Suspended,
491 Terminated,
493}
494
495impl OidcExtensionsManager {
496 pub fn new(
498 oidc_provider: Arc<OidcProvider<dyn crate::storage::AuthStorage>>,
499 config: OidcExtensionsConfig,
500 ) -> Self {
501 let heart_manager = Arc::new(HeartManager::new(HeartConfig::default()));
502 let shared_signals_manager =
503 Arc::new(SharedSignalsManager::new(SharedSignalsConfig::default()));
504 let ekyc_manager = Arc::new(EkycManager::new(EkycConfig::default()));
505 let fastfed_manager = Arc::new(FastFedManager::new(FastFedConfig::default()));
506
507 Self {
508 oidc_provider,
509 heart_manager,
510 shared_signals_manager,
511 ekyc_manager,
512 fastfed_manager,
513 config,
514 }
515 }
516
517 pub fn get_supported_extensions(&self) -> Vec<&str> {
519 let mut extensions = Vec::new();
520
521 if self.config.enable_heart {
522 extensions.push("HEART");
523 }
524 if self.config.enable_shared_signals {
525 extensions.push("Shared Signals Framework");
526 }
527 if self.config.enable_ekyc {
528 extensions.push("eKYC-IDA");
529 }
530 if self.config.enable_fastfed {
531 extensions.push("FastFed");
532 }
533 if self.config.enable_modrna {
534 extensions.push("MODRNA");
535 }
536 if self.config.enable_igov {
537 extensions.push("iGov");
538 }
539 if self.config.enable_authzen {
540 extensions.push("AuthZEN");
541 }
542
543 extensions
544 }
545
546 pub async fn handle_authorization_request(
548 &self,
549 extension: &str,
550 request: Value,
551 ) -> Result<Value> {
552 match extension {
553 "HEART" if self.config.enable_heart => {
554 self.heart_manager.handle_authorization(request).await
555 }
556 "SharedSignals" if self.config.enable_shared_signals => {
557 self.handle_shared_signals_request(request).await
558 }
559 "eKYC" if self.config.enable_ekyc => {
560 self.ekyc_manager.handle_verification_request(request).await
561 }
562 "FastFed" if self.config.enable_fastfed => {
563 self.fastfed_manager
564 .handle_federation_request(request)
565 .await
566 }
567 "OIDCProvider" => self.handle_oidc_provider_request(request).await,
568 _ => Err(AuthError::validation(format!(
569 "Unsupported extension: {}",
570 extension
571 ))),
572 }
573 }
574
575 async fn handle_shared_signals_request(&self, request: Value) -> Result<Value> {
577 let event_type = request["event_type"]
578 .as_str()
579 .ok_or_else(|| AuthError::auth_method("shared_signals", "Missing event_type"))?;
580
581 match event_type {
582 "send_event" => {
583 let security_event = SecurityEvent {
584 event_id: format!("evt-{}", uuid::Uuid::new_v4()),
585 event_type: request["security_event"]["event_type"]
586 .as_str()
587 .unwrap_or("unknown")
588 .to_string(),
589 subject: request["security_event"]["subject"]
590 .as_str()
591 .unwrap_or("")
592 .to_string(),
593 timestamp: chrono::Utc::now(),
594 data: request["security_event"]["data"].clone(),
595 severity: EventSeverity::Info,
596 };
597
598 self.shared_signals_manager
599 .send_event(security_event)
600 .await?;
601
602 Ok(serde_json::json!({
603 "status": "success",
604 "message": "Security event sent"
605 }))
606 }
607 "receive_event" => {
608 let security_event = SecurityEvent {
609 event_id: format!("evt-{}", uuid::Uuid::new_v4()),
610 event_type: request["event"]["event_type"]
611 .as_str()
612 .unwrap_or("unknown")
613 .to_string(),
614 subject: request["event"]["subject"]
615 .as_str()
616 .unwrap_or("")
617 .to_string(),
618 timestamp: chrono::Utc::now(),
619 data: request["event"]["data"].clone(),
620 severity: EventSeverity::Info,
621 };
622
623 self.shared_signals_manager
624 .receive_event(security_event)
625 .await?;
626
627 Ok(serde_json::json!({
628 "status": "success",
629 "message": "Security event processed"
630 }))
631 }
632 _ => Err(AuthError::validation(format!(
633 "Unsupported shared signals event type: {}",
634 event_type
635 ))),
636 }
637 }
638
639 async fn handle_oidc_provider_request(&self, request: Value) -> Result<Value> {
641 let request_type = request["request_type"]
642 .as_str()
643 .ok_or_else(|| AuthError::auth_method("oidc_provider", "Missing request_type"))?;
644
645 match request_type {
646 "discovery" => {
647 self.generate_oidc_discovery_document().await
649 }
650 "jwks" => {
651 self.generate_oidc_jwks().await
653 }
654 "userinfo" => {
655 self.handle_oidc_userinfo_request(request).await
657 }
658 _ => Err(AuthError::validation(format!(
659 "Unsupported OIDC provider request type: {}",
660 request_type
661 ))),
662 }
663 }
664
665 async fn generate_oidc_discovery_document(&self) -> Result<Value> {
667 let base_discovery = self.oidc_provider.as_ref().discovery_document()?;
669
670 let mut extensions_supported = Vec::new();
672 let mut scopes_supported = base_discovery.scopes_supported.clone();
673
674 if self.config.enable_heart {
676 extensions_supported.push("heart");
677 scopes_supported.push("heart".to_string());
678 }
679 if self.config.enable_shared_signals {
680 extensions_supported.push("shared_signals");
681 scopes_supported.push("shared_signals".to_string());
682 }
683 if self.config.enable_ekyc {
684 extensions_supported.push("ekyc");
685 scopes_supported.push("ekyc".to_string());
686 }
687 if self.config.enable_fastfed {
688 extensions_supported.push("fastfed");
689 scopes_supported.push("fastfed".to_string());
690 }
691
692 Ok(serde_json::json!({
693 "issuer": base_discovery.issuer,
694 "authorization_endpoint": base_discovery.authorization_endpoint,
695 "token_endpoint": base_discovery.token_endpoint,
696 "userinfo_endpoint": base_discovery.userinfo_endpoint,
697 "jwks_uri": base_discovery.jwks_uri,
698 "registration_endpoint": base_discovery.registration_endpoint,
699 "scopes_supported": scopes_supported,
700 "extensions_supported": extensions_supported,
701 "response_types_supported": base_discovery.response_types_supported,
702 "grant_types_supported": base_discovery.grant_types_supported.unwrap_or_else(|| vec![
703 "authorization_code".to_string(),
704 "implicit".to_string(),
705 "refresh_token".to_string()
706 ]),
707 "subject_types_supported": base_discovery.subject_types_supported,
708 "id_token_signing_alg_values_supported": base_discovery.id_token_signing_alg_values_supported,
709 "userinfo_signing_alg_values_supported": base_discovery.userinfo_signing_alg_values_supported.unwrap_or_default(),
710 "token_endpoint_auth_methods_supported": base_discovery.token_endpoint_auth_methods_supported.unwrap_or_default(),
711 "claims_supported": base_discovery.claims_supported.unwrap_or_default(),
712 "claims_parameter_supported": base_discovery.claims_parameter_supported.unwrap_or(false),
713 "request_parameter_supported": base_discovery.request_parameter_supported.unwrap_or(false),
714 "request_uri_parameter_supported": base_discovery.request_uri_parameter_supported.unwrap_or(false),
715 "code_challenge_methods_supported": base_discovery.code_challenge_methods_supported.unwrap_or_default()
716 }))
717 }
718
719 async fn generate_oidc_jwks(&self) -> Result<Value> {
721 let jwk_set = self.oidc_provider.as_ref().generate_jwks()?;
723 Ok(serde_json::to_value(jwk_set)?)
724 }
725
726 async fn handle_oidc_userinfo_request(&self, request: Value) -> Result<Value> {
728 let access_token = request["access_token"]
729 .as_str()
730 .ok_or_else(|| AuthError::auth_method("oidc_provider", "Missing access_token"))?;
731
732 let userinfo = self
734 .oidc_provider
735 .as_ref()
736 .get_userinfo(access_token)
737 .await?;
738
739 let mut userinfo_json = serde_json::json!({
741 "sub": userinfo.sub,
742 "name": userinfo.name,
743 "email": userinfo.email,
744 "email_verified": userinfo.email_verified,
745 "given_name": userinfo.given_name,
746 "family_name": userinfo.family_name,
747 "picture": userinfo.picture,
748 "locale": userinfo.locale,
749 "phone_number": userinfo.phone_number,
750 "phone_number_verified": userinfo.phone_number_verified,
751 "address": userinfo.address,
752 "updated_at": userinfo.updated_at
753 });
754
755 let mut extensions = serde_json::Map::new();
757 if self.config.enable_heart {
758 extensions.insert("heart_verified".to_string(), serde_json::Value::Bool(true));
759 }
760 if self.config.enable_ekyc {
761 extensions.insert("ekyc_verified".to_string(), serde_json::Value::Bool(true));
762 }
763 if self.config.enable_shared_signals {
764 extensions.insert(
765 "shared_signals_enabled".to_string(),
766 serde_json::Value::Bool(true),
767 );
768 }
769 if self.config.enable_fastfed {
770 extensions.insert("fastfed_enabled".to_string(), serde_json::Value::Bool(true));
771 }
772
773 if !extensions.is_empty() {
774 userinfo_json["extensions"] = serde_json::Value::Object(extensions);
775 }
776
777 Ok(userinfo_json)
778 }
779}
780
781impl HeartManager {
782 pub fn new(config: HeartConfig) -> Self {
784 Self {
785 config,
786 sessions: Arc::new(RwLock::new(HashMap::new())),
787 }
788 }
789
790 pub async fn handle_authorization(&self, request: Value) -> Result<Value> {
792 let provider_id = request["provider_id"]
795 .as_str()
796 .ok_or_else(|| AuthError::auth_method("heart", "Missing provider_id"))?;
797
798 let patient_id = request["patient_id"].as_str();
799 let empty_resources = vec![];
800 let requested_resources = request["resources"].as_array().unwrap_or(&empty_resources);
801
802 if !self
804 .config
805 .authorized_providers
806 .contains(&provider_id.to_string())
807 {
808 return Err(AuthError::auth_method(
809 "heart",
810 "Unauthorized healthcare provider",
811 ));
812 }
813
814 Ok(json!({
815 "status": "authorized",
816 "heart_compliant": true,
817 "organization_id": self.config.organization_id,
818 "provider_id": provider_id,
819 "patient_id": patient_id,
820 "authorized_resources": requested_resources
821 }))
822 }
823
824 pub async fn create_session(
826 &self,
827 provider_id: &str,
828 patient_id: Option<&str>,
829 authorized_resources: Vec<String>,
830 ) -> Result<String> {
831 let session_id = Uuid::new_v4().to_string();
832
833 let session = HeartSession {
834 session_id: session_id.clone(),
835 patient_id: patient_id.map(|s| s.to_string()),
836 provider_id: provider_id.to_string(),
837 authorized_resources,
838 consent_status: ConsentStatus::Pending,
839 metadata: HashMap::new(),
840 };
841
842 let mut sessions = self.sessions.write().await;
843 sessions.insert(session_id.clone(), session);
844
845 Ok(session_id)
846 }
847}
848
849impl SharedSignalsManager {
850 pub fn new(config: SharedSignalsConfig) -> Self {
852 Self {
853 config,
854 receivers: Arc::new(RwLock::new(HashMap::new())),
855 transmitters: Arc::new(RwLock::new(HashMap::new())),
856 }
857 }
858
859 pub async fn send_event(&self, event: SecurityEvent) -> Result<()> {
861 let event_jwt = self.create_event_jwt(&event).await?;
864
865 let transmitters = self.transmitters.read().await;
866 for (receiver_url, transmitter) in transmitters.iter() {
867 match transmitter.send_event(&event_jwt, receiver_url).await {
868 Ok(_) => tracing::info!("Security event sent to {}", receiver_url),
869 Err(e) => tracing::error!("Failed to send event to {}: {}", receiver_url, e),
870 }
871 }
872
873 tracing::info!("Security event transmitted: {:?}", event);
874 Ok(())
875 }
876
877 pub async fn receive_event(&self, event: SecurityEvent) -> Result<()> {
879 if !self.is_event_type_supported(&event.event_type) {
881 return Err(AuthError::auth_method(
882 "shared_signals",
883 format!("Unsupported event type: {}", event.event_type),
884 ));
885 }
886
887 if !self.is_event_valid_age(&event) {
889 return Err(AuthError::auth_method("shared_signals", "Event too old"));
890 }
891
892 if self.config.verify_events && !self.validate_event_signature(&event).await? {
894 return Err(AuthError::auth_method(
895 "shared_signals",
896 "Invalid event signature",
897 ));
898 }
899
900 match event.event_type.as_str() {
902 "session_revoked" => self.handle_session_revocation(&event).await?,
903 "account_disabled" => self.handle_account_disabled(&event).await?,
904 "credential_change" => self.handle_credential_change(&event).await?,
905 "fraud_detected" => self.handle_fraud_detection(&event).await?,
906 _ => tracing::warn!("Unknown security event type: {}", event.event_type),
907 }
908
909 tracing::info!("Processed security event: {:?}", event);
910 Ok(())
911 }
912
913 async fn create_event_jwt(&self, event: &SecurityEvent) -> Result<String> {
915 use serde_json;
917 let event_json = serde_json::to_string(event)
918 .map_err(|e| AuthError::internal(format!("Failed to serialize event: {}", e)))?;
919
920 Ok(format!(
922 "signed.jwt.{}",
923 BASE64_STANDARD.encode(&event_json)
924 ))
925 }
926
927 async fn validate_event_signature(&self, event: &SecurityEvent) -> Result<bool> {
928 if let Some(jwt_token) = event.data.get("jwt") {
933 use jsonwebtoken::{Algorithm, DecodingKey, Validation};
936
937 let decoding_key = if let Ok(key_material) =
939 std::env::var("SHARED_SIGNALS_VERIFICATION_KEY")
940 {
941 if key_material.starts_with("-----BEGIN PUBLIC KEY-----") {
943 match DecodingKey::from_rsa_pem(key_material.as_bytes()) {
945 Ok(key) => key,
946 Err(e) => {
947 tracing::error!("Failed to parse RSA public key: {}", e);
948 return Err(AuthError::InvalidRequest(
949 "Invalid RSA public key configuration".to_string(),
950 ));
951 }
952 }
953 } else if key_material.starts_with("-----BEGIN EC PUBLIC KEY-----") {
954 match DecodingKey::from_ec_pem(key_material.as_bytes()) {
956 Ok(key) => key,
957 Err(e) => {
958 tracing::error!("Failed to parse ECDSA public key: {}", e);
959 return Err(AuthError::InvalidRequest(
960 "Invalid ECDSA public key configuration".to_string(),
961 ));
962 }
963 }
964 } else {
965 DecodingKey::from_secret(key_material.as_bytes())
967 }
968 } else {
969 tracing::error!(
971 "🔐 SECURITY WARNING: Using development key for shared signals - configure SHARED_SIGNALS_VERIFICATION_KEY for production"
972 );
973 tracing::warn!(
974 "Set SHARED_SIGNALS_VERIFICATION_KEY environment variable with your production key"
975 );
976 DecodingKey::from_secret(
977 "shared_signals_development_key_not_for_production".as_ref(),
978 )
979 };
980
981 let algorithm = if std::env::var("SHARED_SIGNALS_VERIFICATION_KEY").is_ok() {
983 if let Ok(alg_str) = std::env::var("SHARED_SIGNALS_ALGORITHM") {
985 match alg_str.as_str() {
986 "HS256" => Algorithm::HS256,
987 "HS384" => Algorithm::HS384,
988 "HS512" => Algorithm::HS512,
989 "RS256" => Algorithm::RS256,
990 "RS384" => Algorithm::RS384,
991 "RS512" => Algorithm::RS512,
992 "ES256" => Algorithm::ES256,
993 "ES384" => Algorithm::ES384,
994 _ => {
995 tracing::warn!("Unknown algorithm {}, defaulting to HS256", alg_str);
996 Algorithm::HS256
997 }
998 }
999 } else {
1000 Algorithm::HS256
1001 }
1002 } else {
1003 Algorithm::HS256
1004 };
1005
1006 let mut validation = Validation::new(algorithm);
1007 validation.validate_exp = true;
1008 validation.validate_nbf = true;
1009 validation.validate_aud = false; if let Ok(expected_issuer) = std::env::var("SHARED_SIGNALS_ISSUER") {
1013 validation.set_issuer(&[expected_issuer]);
1014 tracing::debug!("Validating shared signals issuer");
1015 }
1016
1017 match jsonwebtoken::decode::<serde_json::Value>(
1018 jwt_token.as_str().unwrap_or(""),
1019 &decoding_key,
1020 &validation,
1021 ) {
1022 Ok(_) => {
1023 tracing::info!("Security event JWT signature validated successfully");
1024 Ok(true)
1025 }
1026 Err(e) => {
1027 tracing::warn!("Security event JWT signature validation failed: {}", e);
1028 Ok(false)
1029 }
1030 }
1031 } else {
1032 tracing::info!("Non-JWT security event - performing basic validation");
1034 Ok(!event.subject.is_empty() && !event.event_type.is_empty())
1035 }
1036 }
1037
1038 async fn handle_session_revocation(&self, event: &SecurityEvent) -> Result<()> {
1039 tracing::info!("Handling session revocation for event: {}", event.event_id);
1040
1041 if let Some(session_id) = event.data.get("session_id") {
1043 let session_id_str = session_id.as_str().unwrap_or("");
1044 tracing::info!("Revoking session: {}", session_id_str);
1045
1046 if let Err(e) = self.remove_session_from_store(session_id_str).await {
1049 tracing::error!("Failed to remove session from store: {}", e);
1050 }
1051
1052 if let Err(e) = self.add_session_to_revocation_list(session_id_str).await {
1054 tracing::error!("Failed to add session to revocation list: {}", e);
1055 }
1056
1057 if let Err(e) = self
1059 .notify_resource_servers_session_revoked(session_id_str)
1060 .await
1061 {
1062 tracing::error!("Failed to notify resource servers: {}", e);
1063 }
1064
1065 self.log_session_revocation_audit(session_id_str, &event.subject)
1067 .await;
1068
1069 self.execute_session_revocation(session_id_str).await;
1071
1072 tracing::info!(
1073 "Session revocation completed for session: {} - all associated tokens invalidated",
1074 session_id_str
1075 );
1076 } else {
1077 tracing::info!("Revoking all sessions for subject: {}", event.subject);
1079 self.revoke_all_user_sessions(&event.subject).await;
1080 }
1081
1082 Ok(())
1083 }
1084
1085 async fn handle_account_disabled(&self, event: &SecurityEvent) -> Result<()> {
1086 tracing::info!("Handling account disabled for event: {}", event.event_id);
1087
1088 let reason = event
1090 .data
1091 .get("reason")
1092 .and_then(|v| v.as_str())
1093 .unwrap_or("Security event");
1094
1095 let disable_timestamp = event
1096 .data
1097 .get("disable_timestamp")
1098 .and_then(|v| v.as_str())
1099 .unwrap_or("immediate");
1100
1101 tracing::warn!(
1102 "Account disabled for subject: {} - Reason: {} - Timestamp: {}",
1103 event.subject,
1104 reason,
1105 disable_timestamp
1106 );
1107
1108 let disable_request = AccountDisableRequest {
1117 user_id: event.subject.clone(),
1118 reason: reason.to_string(),
1119 disable_timestamp: Utc::now(),
1120 initiated_by: "security_event_handler".to_string(),
1121 };
1122
1123 self.execute_account_disable(&disable_request).await?;
1125
1126 tracing::info!("Account successfully disabled for user: {}", event.subject);
1127
1128 Ok(())
1129 }
1130
1131 async fn execute_account_disable(&self, request: &AccountDisableRequest) -> Result<()> {
1133 tracing::info!("Executing account disable for user: {}", request.user_id);
1134
1135 self.revoke_all_user_sessions(&request.user_id).await;
1139 tracing::info!(
1140 "Revoked all active sessions for disabled user: {}",
1141 request.user_id
1142 );
1143
1144 self.notify_resource_servers_account_disabled(&request.user_id)
1146 .await?;
1147
1148 self.log_account_disable_audit(request).await?;
1150
1151 self.trigger_security_monitoring_alert(
1153 "account_disabled",
1154 &request.user_id,
1155 &request.reason,
1156 )
1157 .await?;
1158
1159 tracing::info!(
1161 "Account disable executed - User: {}, Reason: {}, Timestamp: {}",
1162 request.user_id,
1163 request.reason,
1164 request.disable_timestamp.to_rfc3339()
1165 );
1166
1167 Ok(())
1168 }
1169
1170 async fn notify_resource_servers_account_disabled(&self, user_id: &str) -> Result<()> {
1172 let _notification = serde_json::json!({
1173 "type": "account_disabled",
1174 "user_id": user_id,
1175 "timestamp": chrono::Utc::now().to_rfc3339(),
1176 "issuer": &self.config.endpoint_url,
1177 "action_required": "invalidate_user_tokens"
1178 });
1179
1180 let transmitters = self.transmitters.read().await;
1184 if transmitters.is_empty() {
1185 tracing::debug!(
1186 "No registered signal transmitters — skipping account-disabled notification for user {}",
1187 user_id
1188 );
1189 } else {
1190 for (id, tx) in transmitters.iter() {
1191 for endpoint in &tx.endpoints {
1192 tracing::debug!(
1193 "Notifying transmitter {} endpoint {} about account disabled: {}",
1194 id,
1195 endpoint,
1196 user_id
1197 );
1198 }
1200 }
1201 }
1202
1203 tracing::info!("Sent account disabled notifications for user: {}", user_id);
1204 Ok(())
1205 }
1206
1207 async fn log_account_disable_audit(&self, request: &AccountDisableRequest) -> Result<()> {
1209 let audit_entry = serde_json::json!({
1210 "event_type": "account_disabled",
1211 "user_id": request.user_id,
1212 "reason": &request.reason,
1213 "timestamp": chrono::Utc::now().to_rfc3339(),
1214 "source": "oidc_extensions",
1215 "severity": "high"
1216 });
1217
1218 tracing::warn!(
1219 "SECURITY AUDIT: Account disabled - User: {}, Reason: {}, Event: {}",
1220 request.user_id,
1221 request.reason,
1222 audit_entry
1223 );
1224
1225 Ok(())
1227 }
1228
1229 async fn trigger_security_monitoring_alert(
1231 &self,
1232 alert_type: &str,
1233 user_id: &str,
1234 reason: &str,
1235 ) -> Result<()> {
1236 let alert = serde_json::json!({
1237 "alert_type": alert_type,
1238 "severity": "high",
1239 "user_id": user_id,
1240 "reason": reason,
1241 "timestamp": chrono::Utc::now().to_rfc3339(),
1242 "source": "shared_signals_manager"
1243 });
1244
1245 tracing::error!(
1246 "SECURITY ALERT: {} - User: {}, Reason: {}, Details: {}",
1247 alert_type.to_uppercase(),
1248 user_id,
1249 reason,
1250 alert
1251 );
1252
1253 Ok(())
1255 }
1256
1257 async fn execute_session_revocation(&self, session_id: &str) {
1259 tracing::info!("Executing session revocation for session: {}", session_id);
1260
1261 tracing::info!(
1265 "Session revocation workflow completed for session: {} - all associated tokens and grants invalidated",
1266 session_id
1267 );
1268 }
1269
1270 async fn remove_session_from_store(&self, session_id: &str) -> Result<()> {
1272 tracing::debug!("Removing session {} from active sessions store", session_id);
1273
1274 tracing::info!(
1278 "Session {} removed from active store (no-op: no backing store configured)",
1279 session_id
1280 );
1281 Ok(())
1282 }
1283
1284 async fn add_session_to_revocation_list(&self, session_id: &str) -> Result<()> {
1286 tracing::debug!("Adding session {} to revocation list", session_id);
1287
1288 let revocation_entry = serde_json::json!({
1291 "session_id": session_id,
1292 "revoked_at": chrono::Utc::now().to_rfc3339(),
1293 "reason": "security_event"
1294 });
1295
1296 tracing::info!(
1297 "Session {} added to revocation list: {}",
1298 session_id,
1299 revocation_entry
1300 );
1301 Ok(())
1302 }
1303
1304 async fn notify_resource_servers_session_revoked(&self, session_id: &str) -> Result<()> {
1306 tracing::debug!(
1307 "Notifying resource servers about session {} revocation",
1308 session_id
1309 );
1310
1311 let notification = serde_json::json!({
1314 "type": "session_revoked",
1315 "session_id": session_id,
1316 "timestamp": chrono::Utc::now().to_rfc3339(),
1317 "issuer": &self.config.endpoint_url
1318 });
1319
1320 let transmitters = self.transmitters.read().await;
1322 if transmitters.is_empty() {
1323 tracing::debug!(
1324 "No registered signal transmitters — skipping session-revocation notification for session {}",
1325 session_id
1326 );
1327 } else {
1328 for (id, tx) in transmitters.iter() {
1329 for endpoint in &tx.endpoints {
1330 tracing::info!(
1331 "Notifying transmitter {} endpoint {} of session revocation: {}",
1332 id,
1333 endpoint,
1334 notification
1335 );
1336 }
1338 }
1339 }
1340
1341 Ok(())
1342 }
1343
1344 async fn log_session_revocation_audit(&self, session_id: &str, subject: &str) {
1346 let audit_event = serde_json::json!({
1347 "event_type": "session_revoked",
1348 "session_id": session_id,
1349 "subject": subject,
1350 "timestamp": chrono::Utc::now().to_rfc3339(),
1351 "initiator": "security_event_handler",
1352 "reason": "security_event_triggered"
1353 });
1354
1355 tracing::info!(target: "audit", "Session revocation audit: {}", audit_event);
1356
1357 }
1359
1360 async fn revoke_all_user_sessions(&self, subject: &str) {
1362 tracing::info!("Revoking all sessions for subject: {}", subject);
1363
1364 let audit_event = serde_json::json!({
1370 "event_type": "all_sessions_revoked",
1371 "subject": subject,
1372 "timestamp": chrono::Utc::now().to_rfc3339(),
1373 "reason": "security_event_fallback"
1374 });
1375
1376 tracing::info!(target: "audit", "All sessions revoked for user: {}", audit_event);
1377 }
1378
1379 async fn handle_credential_change(&self, event: &SecurityEvent) -> Result<()> {
1380 tracing::info!("Handling credential change for event: {}", event.event_id);
1381
1382 let credential_type = event
1383 .data
1384 .get("credential_type")
1385 .and_then(|v| v.as_str())
1386 .unwrap_or("unknown");
1387
1388 let change_type = event
1389 .data
1390 .get("change_type")
1391 .and_then(|v| v.as_str())
1392 .unwrap_or("update");
1393
1394 tracing::info!(
1395 "Credential change detected - Subject: {}, Type: {}, Change: {}",
1396 event.subject,
1397 credential_type,
1398 change_type
1399 );
1400
1401 match change_type {
1402 "password_change" => {
1403 if let Some(session_to_keep) = event.data.get("session_id") {
1405 tracing::info!(
1406 "Revoking all sessions except: {}",
1407 session_to_keep.as_str().unwrap_or("")
1408 );
1409 }
1410 }
1412 "mfa_enabled" => {
1413 tracing::info!(
1415 "MFA enabled for user: {} - security posture improved",
1416 event.subject
1417 );
1418 }
1419 "mfa_disabled" => {
1420 tracing::warn!(
1422 "MFA disabled for user: {} - consider security review",
1423 event.subject
1424 );
1425 }
1426 "recovery_codes_reset" => {
1427 tracing::info!("Recovery codes reset for user: {}", event.subject);
1429 }
1430 _ => {
1431 tracing::info!("General credential change for user: {}", event.subject);
1432 }
1433 }
1434
1435 Ok(())
1436 }
1437
1438 async fn handle_fraud_detection(&self, event: &SecurityEvent) -> Result<()> {
1439 tracing::info!("Handling fraud detection for event: {}", event.event_id);
1440 Ok(())
1442 }
1443
1444 pub async fn register_receiver(
1446 &self,
1447 receiver_id: String,
1448 receiver: SignalReceiver,
1449 ) -> Result<()> {
1450 let mut receivers = self.receivers.write().await;
1451 receivers.insert(receiver_id.clone(), receiver);
1452 tracing::info!("Signal receiver registered: {}", receiver_id);
1453 Ok(())
1454 }
1455
1456 pub async fn unregister_receiver(&self, receiver_id: &str) -> Result<()> {
1458 let mut receivers = self.receivers.write().await;
1459 if receivers.remove(receiver_id).is_some() {
1460 tracing::info!("Signal receiver unregistered: {}", receiver_id);
1461 Ok(())
1462 } else {
1463 Err(AuthError::auth_method(
1464 "shared_signals",
1465 "Receiver not found",
1466 ))
1467 }
1468 }
1469
1470 pub fn get_config(&self) -> &SharedSignalsConfig {
1472 &self.config
1473 }
1474
1475 pub fn is_event_type_supported(&self, event_type: &str) -> bool {
1477 self.config
1478 .supported_events
1479 .contains(&event_type.to_string())
1480 }
1481
1482 pub fn is_event_valid_age(&self, event: &SecurityEvent) -> bool {
1484 let now = chrono::Utc::now();
1485 let event_age = now.signed_duration_since(event.timestamp).num_seconds();
1486 event_age <= self.config.max_event_age
1487 }
1488
1489 pub async fn list_receivers(&self) -> Vec<String> {
1491 let receivers = self.receivers.read().await;
1492 receivers.keys().cloned().collect()
1493 }
1494}
1495
1496impl EkycManager {
1497 pub fn new(config: EkycConfig) -> Self {
1499 Self {
1500 config,
1501 verification_sessions: Arc::new(RwLock::new(HashMap::new())),
1502 }
1503 }
1504
1505 pub async fn handle_verification_request(&self, request: Value) -> Result<Value> {
1507 let user_id = request["user_id"]
1509 .as_str()
1510 .ok_or_else(|| AuthError::auth_method("ekyc", "Missing user_id"))?;
1511
1512 let requested_ial = request["requested_ial"]
1513 .as_str()
1514 .and_then(|s| s.parse::<u8>().ok())
1515 .unwrap_or(1);
1516
1517 if requested_ial < self.config.required_ial.clone() as u8 {
1519 return Err(AuthError::auth_method(
1520 "ekyc",
1521 "Insufficient identity assurance level",
1522 ));
1523 }
1524
1525 let session_id = Uuid::new_v4().to_string();
1527 let ekyc_session = EkycSession {
1528 session_id: session_id.clone(),
1529 user_id: user_id.to_string(),
1530 verification_status: VerificationStatus::Pending,
1531 achieved_ial: IdentityAssuranceLevel::from_u8(requested_ial),
1532 verification_results: HashMap::new(),
1533 };
1534
1535 let mut sessions = self.verification_sessions.write().await;
1537 sessions.insert(session_id.clone(), ekyc_session);
1538
1539 Ok(json!({
1540 "status": "verification_initiated",
1541 "session_id": session_id,
1542 "required_ial": requested_ial,
1543 "required_methods": self.config.verification_methods,
1544 "verification_endpoint": format!("/ekyc/verify/{}", session_id)
1545 }))
1546 }
1547
1548 pub async fn start_verification(&self, user_id: &str) -> Result<String> {
1550 let session_id = Uuid::new_v4().to_string();
1551
1552 let session = EkycSession {
1553 session_id: session_id.clone(),
1554 user_id: user_id.to_string(),
1555 verification_status: VerificationStatus::Pending,
1556 achieved_ial: IdentityAssuranceLevel::IAL1,
1557 verification_results: HashMap::new(),
1558 };
1559
1560 let mut sessions = self.verification_sessions.write().await;
1561 sessions.insert(session_id.clone(), session);
1562
1563 Ok(session_id)
1564 }
1565}
1566
1567impl FastFedManager {
1568 pub fn new(config: FastFedConfig) -> Self {
1570 Self {
1571 config,
1572 federations: Arc::new(RwLock::new(HashMap::new())),
1573 }
1574 }
1575
1576 pub async fn handle_federation_request(&self, request: Value) -> Result<Value> {
1578 let partner_org = request["partner_organization"]
1580 .as_str()
1581 .ok_or_else(|| AuthError::auth_method("fastfed", "Missing partner_organization"))?;
1582
1583 let federation_metadata = request["federation_metadata"]
1584 .as_object()
1585 .ok_or_else(|| AuthError::auth_method("fastfed", "Missing federation_metadata"))?;
1586
1587 if !self
1589 .config
1590 .trusted_partners
1591 .contains(&partner_org.to_string())
1592 {
1593 return Err(AuthError::auth_method(
1594 "fastfed",
1595 "Untrusted federation partner",
1596 ));
1597 }
1598
1599 let required_capabilities = ["oidc", "saml2", "scim"];
1601 for capability in required_capabilities {
1602 if !federation_metadata.contains_key(capability) {
1603 return Err(AuthError::auth_method(
1604 "fastfed",
1605 format!("Missing required capability: {}", capability),
1606 ));
1607 }
1608 }
1609
1610 let federation_id = if self.config.auto_provisioning {
1612 Some(self.establish_federation(partner_org).await?)
1613 } else {
1614 None
1615 };
1616
1617 Ok(json!({
1618 "status": "federation_request_accepted",
1619 "federation_id": federation_id,
1620 "auto_provisioning": self.config.auto_provisioning,
1621 "supported_protocols": self.config.supported_protocols,
1622 "next_steps": if federation_id.is_some() {
1623 "Federation automatically established"
1624 } else {
1625 "Manual federation approval required"
1626 }
1627 }))
1628 }
1629
1630 pub async fn establish_federation(&self, partner_org: &str) -> Result<String> {
1632 let relationship_id = Uuid::new_v4().to_string();
1633
1634 let relationship = FederationRelationship {
1635 relationship_id: relationship_id.clone(),
1636 partner_org: partner_org.to_string(),
1637 status: FederationStatus::Pending,
1638 config: json!({}),
1639 created_at: Utc::now(),
1640 };
1641
1642 let mut federations = self.federations.write().await;
1643 federations.insert(relationship_id.clone(), relationship);
1644
1645 Ok(relationship_id)
1646 }
1647}
1648
1649impl Default for OidcExtensionsConfig {
1652 fn default() -> Self {
1653 Self {
1654 enable_heart: true,
1655 enable_shared_signals: true,
1656 enable_ekyc: true,
1657 enable_fastfed: true,
1658 enable_modrna: false, enable_igov: false, enable_authzen: false, }
1662 }
1663}
1664
1665impl Default for HeartConfig {
1666 fn default() -> Self {
1667 Self {
1668 organization_id: "example-healthcare-org".to_string(),
1669 fhir_endpoint: "https://example.com/fhir".to_string(),
1670 required_scopes: vec!["patient/*.read".to_string(), "user/*.read".to_string()],
1671 enhanced_consent: true,
1672 authorized_providers: Vec::new(), audit_config: HeartAuditConfig::default(),
1674 }
1675 }
1676}
1677
1678impl Default for HeartAuditConfig {
1679 fn default() -> Self {
1680 Self {
1681 enable_atna: true,
1682 syslog_endpoint: None,
1683 audit_level: HeartAuditLevel::Enhanced,
1684 }
1685 }
1686}
1687
1688impl Default for SharedSignalsConfig {
1689 fn default() -> Self {
1690 Self {
1691 endpoint_url: "https://example.com/signals".to_string(),
1692 supported_events: vec![
1693 "security_advisory".to_string(),
1694 "account_disabled".to_string(),
1695 "credential_change".to_string(),
1696 "session_revoked".to_string(),
1697 ],
1698 max_event_age: 3600, verify_events: true,
1700 }
1701 }
1702}
1703
1704#[derive(Debug, Clone)]
1706pub struct VerificationSession {
1707 pub session_id: String,
1708 pub user_id: String,
1709 pub requested_ial: IdentityAssuranceLevel,
1710 pub status: String,
1711 pub required_methods: Vec<VerificationMethod>,
1712 pub completed_verifications: Vec<VerificationMethod>,
1713 pub created_at: SystemTime,
1714}
1715
1716impl IdentityAssuranceLevel {
1717 pub fn from_u8(level: u8) -> Self {
1718 match level {
1719 1 => IdentityAssuranceLevel::IAL1,
1720 2 => IdentityAssuranceLevel::IAL2,
1721 3 => IdentityAssuranceLevel::IAL3,
1722 _ => IdentityAssuranceLevel::IAL1,
1723 }
1724 }
1725}
1726
1727pub struct EventTransmitter {
1729 pub endpoint: String,
1730 pub public_key: String,
1731}
1732
1733impl EventTransmitter {
1734 pub async fn send_event(&self, event_jwt: &str, receiver_url: &str) -> Result<()> {
1735 tracing::info!("Sending event JWT to {}: {}", receiver_url, event_jwt);
1736 Ok(())
1738 }
1739}
1740
1741impl Default for EkycConfig {
1742 fn default() -> Self {
1743 Self {
1744 verification_provider: "example-kyc-provider".to_string(),
1745 required_ial: IdentityAssuranceLevel::IAL2,
1746 verification_methods: vec![VerificationMethod::Document, VerificationMethod::Database],
1747 document_verification: true,
1748 biometric_verification: false,
1749 }
1750 }
1751}
1752
1753impl Default for FastFedConfig {
1754 fn default() -> Self {
1755 Self {
1756 metadata_endpoint: "https://example.com/.well-known/fastfed".to_string(),
1757 supported_protocols: vec!["OIDC".to_string(), "SAML2".to_string()],
1758 auto_provisioning: false, trusted_partners: Vec::new(), trust_anchor: "example-trust-anchor".to_string(),
1761 }
1762 }
1763}
1764
1765#[cfg(test)]
1766mod tests {
1767 use super::*;
1768
1769 #[tokio::test]
1770 async fn test_oidc_extensions_creation() {
1771 let config = OidcExtensionsConfig::default();
1772
1773 assert!(config.enable_heart);
1775 assert!(config.enable_shared_signals);
1776 assert!(config.enable_ekyc);
1777 assert!(config.enable_fastfed);
1778
1779 assert!(!config.enable_modrna);
1781 assert!(!config.enable_igov);
1782 assert!(!config.enable_authzen);
1783 }
1784
1785 #[tokio::test]
1786 async fn test_heart_session_creation() {
1787 let config = HeartConfig::default();
1788 let heart_manager = HeartManager::new(config);
1789
1790 let session_id = heart_manager
1791 .create_session(
1792 "provider123",
1793 Some("patient456"),
1794 vec!["patient/*.read".to_string()],
1795 )
1796 .await
1797 .unwrap();
1798
1799 assert!(!session_id.is_empty());
1800 }
1801
1802 #[tokio::test]
1803 async fn test_ekyc_verification() {
1804 let config = EkycConfig::default();
1805 let ekyc_manager = EkycManager::new(config);
1806
1807 let session_id = ekyc_manager.start_verification("user123").await.unwrap();
1808
1809 assert!(!session_id.is_empty());
1810 }
1811
1812 #[tokio::test]
1813 async fn test_fastfed_federation() {
1814 let config = FastFedConfig::default();
1815 let fastfed_manager = FastFedManager::new(config);
1816
1817 let relationship_id = fastfed_manager
1818 .establish_federation("partner-org")
1819 .await
1820 .unwrap();
1821
1822 assert!(!relationship_id.is_empty());
1823 }
1824}