1use crate::errors::{AuthError, Result};
92use crate::server::oidc::oidc_session_management::SessionManager;
93use crate::server::token_exchange::token_exchange_common::{
94 ServiceComplexityLevel, TokenExchangeCapabilities, TokenExchangeService, TokenValidationResult,
95 ValidationUtils,
96};
97
98use async_trait::async_trait;
99use chrono::{DateTime, Duration, Utc};
100use jsonwebtoken::{DecodingKey, EncodingKey};
101use serde::{Deserialize, Serialize};
102use std::collections::{HashMap, HashSet};
103use std::str::FromStr;
104use std::sync::Arc;
105use uuid::Uuid;
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
109pub enum AuthLevel {
110 Basic = 1,
112 Mfa = 2,
114 High = 3,
116}
117
118impl FromStr for AuthLevel {
119 type Err = AuthError;
120
121 fn from_str(s: &str) -> Result<Self, Self::Err> {
122 match s.to_lowercase().as_str() {
123 "basic" => Ok(AuthLevel::Basic),
124 "mfa" => Ok(AuthLevel::Mfa),
125 "high" => Ok(AuthLevel::High),
126 _ => Err(AuthError::InvalidRequest(format!(
127 "Invalid auth level: {}",
128 s
129 ))),
130 }
131 }
132}
133
134impl std::fmt::Display for AuthLevel {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 let level_str = match self {
137 AuthLevel::Basic => "basic",
138 AuthLevel::Mfa => "mfa",
139 AuthLevel::High => "high",
140 };
141 write!(f, "{}", level_str)
142 }
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct AdvancedTokenExchangeConfig {
148 pub enable_multi_party_chains: bool,
150
151 pub max_delegation_depth: usize,
153
154 pub require_audit_trail: bool,
156
157 pub enable_context_preservation: bool,
159
160 pub default_token_lifetime: Duration,
162
163 pub supported_subject_token_types: Vec<String>,
165
166 pub supported_requested_token_types: Vec<String>,
168
169 pub exchange_policies: Vec<TokenExchangePolicy>,
171
172 pub cross_domain_settings: CrossDomainExchangeSettings,
174
175 pub jwt_signing_key: String,
177
178 pub jwt_verification_key: String,
180
181 pub trusted_issuers: Vec<String>,
183}
184
185impl Default for AdvancedTokenExchangeConfig {
186 fn default() -> Self {
187 Self {
188 enable_multi_party_chains: true,
189 max_delegation_depth: 3,
190 require_audit_trail: true,
191 enable_context_preservation: true,
192 default_token_lifetime: Duration::try_hours(1).unwrap_or(Duration::zero()),
193 supported_subject_token_types: vec![
194 "urn:ietf:params:oauth:token-type:jwt".to_string(),
195 "urn:ietf:params:oauth:token-type:access_token".to_string(),
196 "urn:ietf:params:oauth:token-type:refresh_token".to_string(),
197 "urn:ietf:params:oauth:token-type:id_token".to_string(),
198 "urn:ietf:params:oauth:token-type:saml2".to_string(),
199 ],
200 supported_requested_token_types: vec![
201 "urn:ietf:params:oauth:token-type:jwt".to_string(),
202 "urn:ietf:params:oauth:token-type:access_token".to_string(),
203 "urn:ietf:params:oauth:token-type:refresh_token".to_string(),
204 ],
205 exchange_policies: Vec::new(),
206 cross_domain_settings: CrossDomainExchangeSettings::default(),
207 jwt_signing_key: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA...".to_string(), jwt_verification_key: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0B...".to_string(), trusted_issuers: vec![
210 "https://auth.example.com".to_string(),
211 "https://login.example.org".to_string(),
212 ],
213 }
214 }
215}
216
217#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct AdvancedTokenExchangeRequest {
220 pub grant_type: String,
222
223 pub subject_token: String,
225
226 pub subject_token_type: String,
228
229 pub actor_token: Option<String>,
231
232 pub actor_token_type: Option<String>,
234
235 pub requested_token_type: String,
237
238 pub scope: Option<String>,
240
241 pub audience: Vec<String>,
243
244 pub resource: Vec<String>,
246
247 pub exchange_context: Option<ExchangeContext>,
249
250 pub policy_requirements: Vec<String>,
252
253 pub custom_parameters: HashMap<String, serde_json::Value>,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct ExchangeContext {
260 pub transaction_id: String,
262
263 pub business_context: serde_json::Value,
265
266 pub delegation_chain: Vec<DelegationLink>,
268
269 pub original_request: Option<ExchangeRequestMetadata>,
271
272 pub security_context: Option<SecurityContext>,
274
275 pub custom_fields: HashMap<String, serde_json::Value>,
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct DelegationLink {
282 pub delegator: String,
284
285 pub delegatee: String,
287
288 pub delegated_at: DateTime<Utc>,
290
291 pub delegation_reason: String,
293
294 pub delegated_scopes: Vec<String>,
296
297 pub restrictions: Vec<DelegationRestriction>,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
303#[serde(tag = "type", rename_all = "snake_case")]
304pub enum DelegationRestriction {
305 TimeLimit { expires_at: DateTime<Utc> },
307
308 UsageLimit { max_uses: u32, current_uses: u32 },
310
311 IpRestriction { allowed_ips: Vec<String> },
313
314 ScopeRestriction { restricted_scopes: Vec<String> },
316
317 Custom {
319 restriction_type: String,
320 parameters: HashMap<String, serde_json::Value>,
321 },
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize)]
326pub struct ExchangeRequestMetadata {
327 pub client_id: String,
329
330 pub user_agent: Option<String>,
332
333 pub ip_address: Option<String>,
335
336 pub timestamp: DateTime<Utc>,
338
339 pub headers: HashMap<String, String>,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct SecurityContext {
346 pub session_id: Option<String>,
348
349 pub authentication_level: String,
351
352 pub mfa_completed: bool,
354
355 pub risk_score: f64,
357
358 pub device_info: Option<DeviceContext>,
360
361 pub location_info: Option<LocationContext>,
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct DeviceContext {
368 pub device_id: String,
370
371 pub device_type: String,
373
374 pub trust_level: String,
376
377 pub fingerprint: Option<String>,
379}
380
381#[derive(Debug, Clone, Serialize, Deserialize)]
383pub struct LocationContext {
384 pub country: Option<String>,
386
387 pub city: Option<String>,
389
390 pub geo_data: Option<serde_json::Value>,
392
393 pub network_info: Option<String>,
395}
396
397#[derive(Debug, Clone, Serialize, Deserialize)]
399pub struct TokenExchangePolicy {
400 pub id: String,
402
403 pub name: String,
405
406 pub conditions: Vec<PolicyCondition>,
408
409 pub actions: Vec<PolicyAction>,
411
412 pub mandatory: bool,
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize)]
418#[serde(tag = "type", rename_all = "snake_case")]
419pub enum PolicyCondition {
420 SubjectTokenType { allowed_types: Vec<String> },
422
423 ScopeRequirement {
425 required_scopes: Vec<String>,
426 all_required: bool,
427 },
428
429 DelegationDepth { max_depth: usize },
431
432 ClientAuthorization { authorized_clients: Vec<String> },
434
435 TimeRestriction {
437 allowed_hours: Vec<u8>,
438 timezone: String,
439 },
440
441 Custom {
443 condition_type: String,
444 parameters: HashMap<String, serde_json::Value>,
445 },
446}
447
448#[derive(Debug, Clone, Serialize, Deserialize)]
450#[serde(tag = "type", rename_all = "snake_case")]
451pub enum PolicyAction {
452 Allow,
454
455 Deny { reason: String },
457
458 RequireStepUp { required_level: String },
460
461 RestrictScopes { allowed_scopes: Vec<String> },
463
464 RestrictLifetime { max_lifetime: Duration },
466
467 Custom {
469 action_type: String,
470 parameters: HashMap<String, serde_json::Value>,
471 },
472}
473
474#[derive(Debug, Clone, Serialize, Deserialize)]
476pub struct CrossDomainExchangeSettings {
477 pub enabled: bool,
479
480 pub trusted_domains: Vec<String>,
482
483 pub cross_domain_policies: Vec<CrossDomainPolicy>,
485
486 pub require_domain_validation: bool,
488}
489
490impl Default for CrossDomainExchangeSettings {
491 fn default() -> Self {
492 Self {
493 enabled: false,
494 trusted_domains: Vec::new(),
495 cross_domain_policies: Vec::new(),
496 require_domain_validation: true,
497 }
498 }
499}
500
501#[derive(Debug, Clone, Serialize, Deserialize)]
503pub struct CrossDomainPolicy {
504 pub id: String,
506
507 pub source_domain: String,
509
510 pub target_domain: String,
512
513 pub allowed_token_types: Vec<String>,
515
516 pub required_claims: Vec<String>,
518
519 pub scope_mappings: HashMap<String, String>,
521}
522
523#[derive(Debug, Clone, Serialize, Deserialize)]
525pub struct AdvancedTokenExchangeResponse {
526 pub access_token: String,
528
529 pub issued_token_type: String,
531
532 pub token_type: String,
534
535 pub expires_in: Option<u64>,
537
538 pub scope: Option<String>,
540
541 pub refresh_token: Option<String>,
543
544 pub exchange_audit: Option<ExchangeAuditInfo>,
546
547 pub preserved_context: Option<ExchangeContext>,
549
550 pub additional_parameters: HashMap<String, serde_json::Value>,
552}
553
554#[derive(Debug, Clone, Serialize, Deserialize)]
556pub struct ExchangeAuditInfo {
557 pub exchange_id: Uuid,
559
560 pub timestamp: DateTime<Utc>,
562
563 pub exchange_type: TokenExchangeType,
565
566 pub subject_info: SubjectInfo,
568
569 pub actor_info: Option<TokenActorInfo>,
571
572 pub policy_decisions: Vec<PolicyDecision>,
574
575 pub security_assessments: Vec<SecurityAssessment>,
577}
578
579#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
581#[serde(rename_all = "snake_case")]
582pub enum TokenExchangeType {
583 Impersonation,
585
586 Delegation,
588
589 Translation,
591
592 ContextExchange,
594
595 Federation,
597
598 PrivilegeEscalation,
600}
601
602#[derive(Debug, Clone, Serialize, Deserialize)]
604pub struct SubjectInfo {
605 pub subject: String,
607
608 pub subject_type: String,
610
611 pub original_token_info: TokenInfo,
613
614 pub attributes: HashMap<String, serde_json::Value>,
616}
617
618#[derive(Debug, Clone, Serialize, Deserialize)]
620pub struct TokenActorInfo {
621 pub actor: String,
623
624 pub actor_type: String,
626
627 pub actor_token_info: TokenInfo,
629
630 pub attributes: HashMap<String, serde_json::Value>,
632}
633
634#[derive(Debug, Clone, Serialize, Deserialize)]
636pub struct TokenInfo {
637 pub token_type: String,
639
640 pub issuer: String,
642
643 pub audience: Vec<String>,
645
646 pub scopes: Vec<String>,
648
649 pub expires_at: Option<DateTime<Utc>>,
651
652 pub metadata: HashMap<String, serde_json::Value>,
654}
655
656#[derive(Debug, Clone, Serialize, Deserialize)]
658pub struct PolicyDecision {
659 pub policy_id: String,
661
662 pub decision: PolicyDecisionResult,
664
665 pub reason: String,
667
668 pub applied_modifications: Vec<String>,
670}
671
672#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
674#[serde(rename_all = "snake_case")]
675pub enum PolicyDecisionResult {
676 Allow,
678
679 Deny,
681
682 Modify,
684
685 RequireVerification,
687}
688
689#[derive(Debug, Clone, Serialize, Deserialize)]
691pub struct SecurityAssessment {
692 pub assessment_type: String,
694
695 pub result: SecurityAssessmentResult,
697
698 pub risk_score: f64,
700
701 pub details: HashMap<String, serde_json::Value>,
703}
704
705#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
707#[serde(rename_all = "snake_case")]
708pub enum SecurityAssessmentResult {
709 Pass,
711
712 Fail,
714
715 RequiresReview,
717
718 Inconclusive,
720}
721
722#[async_trait]
724pub trait TokenExchangeProcessor: Send + Sync {
725 async fn process_exchange(
727 &self,
728 request: &AdvancedTokenExchangeRequest,
729 context: &ExchangeContext,
730 ) -> Result<AdvancedTokenExchangeResponse>;
731
732 async fn validate_subject_token(&self, token: &str, token_type: &str) -> Result<TokenInfo>;
734
735 async fn validate_actor_token(&self, token: &str, token_type: &str) -> Result<TokenInfo>;
737
738 async fn generate_exchanged_token(
740 &self,
741 subject_info: &SubjectInfo,
742 actor_info: Option<&TokenActorInfo>,
743 request: &AdvancedTokenExchangeRequest,
744 ) -> Result<String>;
745}
746
747pub struct AdvancedTokenExchangeManager {
749 config: AdvancedTokenExchangeConfig,
751
752 session_manager: Arc<SessionManager>,
754
755 processors: HashMap<String, Arc<dyn TokenExchangeProcessor>>,
757
758 exchange_audit: Arc<tokio::sync::RwLock<Vec<ExchangeAuditInfo>>>,
760
761 encoding_key: EncodingKey,
763
764 decoding_key: DecodingKey,
766}
767
768impl AdvancedTokenExchangeManager {
769 pub fn new(
771 config: AdvancedTokenExchangeConfig,
772 session_manager: Arc<SessionManager>,
773 ) -> Result<Self> {
774 let encoding_key = EncodingKey::from_rsa_pem(config.jwt_signing_key.as_bytes())?;
776 let decoding_key = DecodingKey::from_rsa_pem(config.jwt_verification_key.as_bytes())?;
777
778 Ok(Self {
779 config,
780 session_manager,
781 processors: HashMap::new(),
782 exchange_audit: Arc::new(tokio::sync::RwLock::new(Vec::new())),
783 encoding_key,
784 decoding_key,
785 })
786 }
787
788 pub fn register_processor(
790 &mut self,
791 token_type: String,
792 processor: Arc<dyn TokenExchangeProcessor>,
793 ) {
794 self.processors.insert(token_type, processor);
795 }
796
797 pub async fn exchange_token(
799 &self,
800 request: AdvancedTokenExchangeRequest,
801 ) -> Result<AdvancedTokenExchangeResponse> {
802 self.validate_exchange_request(&request).await?;
804
805 let context = request
807 .exchange_context
808 .clone()
809 .unwrap_or_else(|| ExchangeContext {
810 transaction_id: Uuid::new_v4().to_string(),
811 business_context: serde_json::Value::Null,
812 delegation_chain: Vec::new(),
813 original_request: None,
814 security_context: None,
815 custom_fields: HashMap::new(),
816 });
817
818 if context.delegation_chain.len() > self.config.max_delegation_depth {
820 return Err(AuthError::InvalidRequest(
821 "Maximum delegation depth exceeded".to_string(),
822 ));
823 }
824
825 self.apply_exchange_policies(&request, &context).await?;
827
828 let subject_info = self.validate_and_extract_subject_info(&request).await?;
830
831 let actor_info = if request.actor_token.is_some() {
833 Some(self.validate_and_extract_actor_info(&request).await?)
834 } else {
835 None
836 };
837
838 let exchange_type = self.determine_exchange_type(&request, &subject_info, &actor_info);
840
841 let processor = self.get_processor(&request.requested_token_type)?;
843 let mut response = processor.process_exchange(&request, &context).await?;
844
845 let audit_info = self
847 .create_audit_info(
848 exchange_type,
849 &subject_info,
850 &actor_info,
851 &request,
852 &context,
853 )
854 .await?;
855
856 {
858 let mut audit_log = self.exchange_audit.write().await;
859 audit_log.push(audit_info.clone());
860 }
861
862 if self.config.require_audit_trail {
864 response.exchange_audit = Some(audit_info.clone());
865
866 let audit_token = self.generate_audit_token(&audit_info)?;
868 response.additional_parameters.insert(
869 "audit_token".to_string(),
870 serde_json::Value::String(audit_token),
871 );
872 }
873
874 if self.config.enable_context_preservation {
876 let preserved_context = context.clone();
877 response.preserved_context = Some(preserved_context.clone());
878
879 let delegation_token = self.generate_delegation_token(&preserved_context)?;
881 response.additional_parameters.insert(
882 "delegation_token".to_string(),
883 serde_json::Value::String(delegation_token),
884 );
885 }
886
887 Ok(response)
888 }
889
890 pub async fn get_exchange_audit(&self) -> Vec<ExchangeAuditInfo> {
892 let audit_log = self.exchange_audit.read().await;
893 audit_log.clone()
894 }
895
896 async fn validate_exchange_request(
898 &self,
899 request: &AdvancedTokenExchangeRequest,
900 ) -> Result<()> {
901 if request.grant_type != "urn:ietf:params:oauth:grant-type:token-exchange" {
903 return Err(AuthError::InvalidRequest(
904 "Invalid grant type for token exchange".to_string(),
905 ));
906 }
907
908 if !self
910 .config
911 .supported_subject_token_types
912 .contains(&request.subject_token_type)
913 {
914 return Err(AuthError::InvalidRequest(format!(
915 "Unsupported subject token type: {}",
916 request.subject_token_type
917 )));
918 }
919
920 if !self
922 .config
923 .supported_requested_token_types
924 .contains(&request.requested_token_type)
925 {
926 return Err(AuthError::InvalidRequest(format!(
927 "Unsupported requested token type: {}",
928 request.requested_token_type
929 )));
930 }
931
932 if let Some(ref actor_token_type) = request.actor_token_type
934 && !self
935 .config
936 .supported_subject_token_types
937 .contains(actor_token_type)
938 {
939 return Err(AuthError::InvalidRequest(format!(
940 "Unsupported actor token type: {}",
941 actor_token_type
942 )));
943 }
944
945 Ok(())
946 }
947
948 async fn apply_exchange_policies(
950 &self,
951 request: &AdvancedTokenExchangeRequest,
952 context: &ExchangeContext,
953 ) -> Result<()> {
954 if request.subject_token_type == "urn:ietf:params:oauth:token-type:jwt" {
956 match self.introspect_jwt_token(&request.subject_token) {
957 Ok(token_claims) => {
958 if let Some(iss) = token_claims.get("iss").and_then(|v| v.as_str())
960 && !self.config.trusted_issuers.contains(&iss.to_string())
961 {
962 return Err(AuthError::InvalidRequest(format!(
963 "Token issued by untrusted issuer: {}",
964 iss
965 )));
966 }
967 }
968 Err(_) => {
969 }
972 }
973 }
974
975 for policy in &self.config.exchange_policies {
976 let policy_applies = self.evaluate_policy_conditions(policy, request, context)?;
977
978 if policy_applies {
979 for action in &policy.actions {
980 match action {
981 PolicyAction::Deny { reason } => {
982 return Err(AuthError::InvalidRequest(format!(
983 "Exchange denied by policy '{}': {}",
984 policy.name, reason
985 )));
986 }
987 PolicyAction::RequireStepUp { required_level } => {
988 let auth_level = required_level.parse::<AuthLevel>().map_err(|_| {
990 AuthError::InvalidRequest(format!(
991 "Invalid authentication level: {}",
992 required_level
993 ))
994 })?;
995 return self
996 .handle_step_up_authentication(auth_level, context)
997 .await;
998 }
999 _ => {
1000 }
1002 }
1003 }
1004 }
1005 }
1006
1007 Ok(())
1008 }
1009
1010 fn evaluate_policy_conditions(
1012 &self,
1013 policy: &TokenExchangePolicy,
1014 request: &AdvancedTokenExchangeRequest,
1015 context: &ExchangeContext,
1016 ) -> Result<bool> {
1017 for condition in &policy.conditions {
1018 match condition {
1019 PolicyCondition::SubjectTokenType { allowed_types } => {
1020 if !allowed_types.contains(&request.subject_token_type) {
1021 return Ok(false);
1022 }
1023 }
1024 PolicyCondition::DelegationDepth { max_depth } => {
1025 if context.delegation_chain.len() > *max_depth {
1026 return Ok(false);
1027 }
1028 }
1029 PolicyCondition::ScopeRequirement {
1030 required_scopes,
1031 all_required,
1032 } => {
1033 if let Some(ref scope) = request.scope {
1034 let request_scopes: HashSet<&str> = scope.split(' ').collect();
1035 let required: HashSet<&str> =
1036 required_scopes.iter().map(|s| s.as_str()).collect();
1037
1038 if *all_required {
1039 if !required.is_subset(&request_scopes) {
1040 return Ok(false);
1041 }
1042 } else if required.is_disjoint(&request_scopes) {
1043 return Ok(false);
1044 }
1045 }
1046 }
1047 _ => {
1048 }
1050 }
1051 }
1052
1053 Ok(true)
1054 }
1055
1056 async fn validate_and_extract_subject_info(
1058 &self,
1059 request: &AdvancedTokenExchangeRequest,
1060 ) -> Result<SubjectInfo> {
1061 let processor = self.get_processor(&request.subject_token_type)?;
1062 let token_info = processor
1063 .validate_subject_token(&request.subject_token, &request.subject_token_type)
1064 .await?;
1065
1066 Ok(SubjectInfo {
1067 subject: token_info
1068 .metadata
1069 .get("sub")
1070 .and_then(|v| v.as_str())
1071 .unwrap_or("unknown")
1072 .to_string(),
1073 subject_type: "user".to_string(), original_token_info: token_info,
1075 attributes: HashMap::new(),
1076 })
1077 }
1078
1079 async fn validate_and_extract_actor_info(
1081 &self,
1082 request: &AdvancedTokenExchangeRequest,
1083 ) -> Result<TokenActorInfo> {
1084 let actor_token = request
1085 .actor_token
1086 .as_ref()
1087 .ok_or_else(|| AuthError::InvalidRequest("actor_token is required".to_string()))?;
1088 let actor_token_type = request
1089 .actor_token_type
1090 .as_ref()
1091 .ok_or_else(|| AuthError::InvalidRequest("actor_token_type is required".to_string()))?;
1092
1093 let processor = self.get_processor(actor_token_type)?;
1094 let token_info = processor
1095 .validate_actor_token(actor_token, actor_token_type)
1096 .await?;
1097
1098 Ok(TokenActorInfo {
1099 actor: token_info
1100 .metadata
1101 .get("sub")
1102 .and_then(|v| v.as_str())
1103 .unwrap_or("unknown")
1104 .to_string(),
1105 actor_type: "service".to_string(), actor_token_info: token_info,
1107 attributes: HashMap::new(),
1108 })
1109 }
1110
1111 fn determine_exchange_type(
1113 &self,
1114 request: &AdvancedTokenExchangeRequest,
1115 _subject_info: &SubjectInfo,
1116 actor_info: &Option<TokenActorInfo>,
1117 ) -> TokenExchangeType {
1118 if actor_info.is_some() {
1119 TokenExchangeType::Delegation
1120 } else if request.exchange_context.is_some() {
1121 TokenExchangeType::ContextExchange
1122 } else if request.subject_token_type != request.requested_token_type {
1123 TokenExchangeType::Translation
1124 } else {
1125 TokenExchangeType::Impersonation
1126 }
1127 }
1128
1129 fn get_processor(&self, token_type: &str) -> Result<Arc<dyn TokenExchangeProcessor>> {
1131 self.processors.get(token_type).cloned().ok_or_else(|| {
1132 AuthError::InvalidRequest(format!(
1133 "No processor registered for token type: {}",
1134 token_type
1135 ))
1136 })
1137 }
1138
1139 async fn create_audit_info(
1141 &self,
1142 exchange_type: TokenExchangeType,
1143 _subject_info: &SubjectInfo,
1144 actor_info: &Option<TokenActorInfo>,
1145 _request: &AdvancedTokenExchangeRequest,
1146 _context: &ExchangeContext,
1147 ) -> Result<ExchangeAuditInfo> {
1148 Ok(ExchangeAuditInfo {
1149 exchange_id: Uuid::new_v4(),
1150 timestamp: Utc::now(),
1151 exchange_type,
1152 subject_info: _subject_info.clone(),
1153 actor_info: actor_info.clone(),
1154 policy_decisions: Vec::new(), security_assessments: Vec::new(), })
1157 }
1158
1159 pub async fn cleanup_old_audit_entries(&self, older_than: DateTime<Utc>) -> usize {
1161 let mut audit_log = self.exchange_audit.write().await;
1162 let original_len = audit_log.len();
1163
1164 audit_log.retain(|entry| entry.timestamp > older_than);
1165
1166 original_len - audit_log.len()
1167 }
1168
1169 pub fn generate_audit_token(&self, audit_info: &ExchangeAuditInfo) -> Result<String> {
1171 use jsonwebtoken::{Algorithm, Header, encode};
1172 use serde_json::json;
1173
1174 let header = Header::new(Algorithm::HS256);
1175
1176 let claims = json!({
1177 "iss": "advanced-token-exchange",
1178 "sub": audit_info.subject_info.subject,
1179 "aud": "audit-verification",
1180 "exp": (Utc::now() + Duration::seconds(3600)).timestamp(),
1181 "iat": Utc::now().timestamp(),
1182 "exchange_id": audit_info.exchange_id,
1183 "exchange_type": audit_info.exchange_type,
1184 "timestamp": audit_info.timestamp,
1185 "policy_decisions": audit_info.policy_decisions.len(),
1186 "security_assessments": audit_info.security_assessments.len()
1187 });
1188
1189 encode(&header, &claims, &self.encoding_key).map_err(|e| {
1190 AuthError::TokenGeneration(format!("Failed to generate audit token: {}", e))
1191 })
1192 }
1193
1194 pub fn validate_delegation_token(&self, token: &str) -> Result<serde_json::Value> {
1196 use jsonwebtoken::{Algorithm, Validation, decode};
1197
1198 let mut validation = Validation::new(Algorithm::HS256);
1199 validation.set_audience(&["delegation-context"]);
1200 validation.set_issuer(&["advanced-token-exchange"]);
1201
1202 let token_data = decode::<serde_json::Value>(token, &self.decoding_key, &validation)
1203 .map_err(|e| AuthError::token(format!("Invalid delegation token: {}", e)))?;
1204
1205 Ok(token_data.claims)
1206 }
1207
1208 pub fn generate_delegation_token(&self, context: &ExchangeContext) -> Result<String> {
1210 use jsonwebtoken::{Algorithm, Header, encode};
1211 use serde_json::json;
1212
1213 let header = Header::new(Algorithm::RS256);
1214
1215 let claims = json!({
1216 "iss": "advanced-token-exchange",
1217 "aud": "delegation-context",
1218 "exp": (Utc::now() + Duration::seconds(1800)).timestamp(), "iat": Utc::now().timestamp(),
1220 "transaction_id": context.transaction_id,
1221 "delegation_chain_length": context.delegation_chain.len(),
1222 "delegation_chain": context.delegation_chain,
1223 "business_context": context.business_context,
1224 "custom_fields": context.custom_fields
1225 });
1226
1227 encode(&header, &claims, &self.encoding_key).map_err(|e| {
1228 AuthError::TokenGeneration(format!("Failed to generate delegation token: {}", e))
1229 })
1230 }
1231
1232 pub fn introspect_jwt_token(&self, token: &str) -> Result<serde_json::Value> {
1234 use jsonwebtoken::dangerous;
1235
1236 let token_data = dangerous::insecure_decode::<serde_json::Value>(token)
1238 .map_err(|e| AuthError::token(format!("Token introspection failed: {}", e)))?;
1239
1240 Ok(token_data.claims)
1241 }
1242
1243 async fn handle_step_up_authentication(
1245 &self,
1246 required_level: AuthLevel,
1247 context: &ExchangeContext,
1248 ) -> Result<()> {
1249 if let Some(session_id) = context
1251 .security_context
1252 .as_ref()
1253 .and_then(|sc| sc.session_id.as_ref())
1254 {
1255 match self.session_manager.get_session(session_id) {
1257 Some(session) => {
1258 if let Some(current_level) = session
1260 .metadata
1261 .get("auth_level")
1262 .map(|v| v.as_str())
1263 .and_then(|s| s.parse::<AuthLevel>().ok())
1264 && current_level >= required_level
1265 {
1266 return Ok(());
1268 }
1269
1270 Err(AuthError::StepUpRequired {
1272 current_level: session
1273 .metadata
1274 .get("auth_level")
1275 .map(|v| v.as_str())
1276 .unwrap_or("basic")
1277 .to_string(),
1278 required_level: required_level.to_string(),
1279 step_up_url: format!(
1280 "/auth/step-up?session_id={}&level={}",
1281 session_id, required_level
1282 ),
1283 })
1284 }
1285 None => {
1286 Err(AuthError::Unauthorized(
1288 "No active session found".to_string(),
1289 ))
1290 }
1291 }
1292 } else {
1293 Err(AuthError::Unauthorized(
1295 "No session context available".to_string(),
1296 ))
1297 }
1298 }
1299}
1300
1301#[async_trait]
1303impl TokenExchangeService for AdvancedTokenExchangeManager {
1304 type Request = AdvancedTokenExchangeRequest;
1305 type Response = AdvancedTokenExchangeResponse;
1306 type Config = AdvancedTokenExchangeConfig;
1307
1308 async fn exchange_token(&self, request: Self::Request) -> Result<Self::Response> {
1310 self.exchange_token(request).await
1311 }
1312
1313 async fn validate_token(&self, token: &str, token_type: &str) -> Result<TokenValidationResult> {
1315 let supported_types = self.supported_subject_token_types();
1317 ValidationUtils::validate_token_type(token_type, &supported_types)?;
1318
1319 if ValidationUtils::is_jwt_token_type(token_type) {
1321 match self.introspect_jwt_token(token) {
1322 Ok(claims) => {
1323 let subject = ValidationUtils::extract_subject(
1325 &claims
1326 .as_object()
1327 .unwrap_or(&serde_json::Map::new())
1328 .iter()
1329 .map(|(k, v)| (k.clone(), v.clone()))
1330 .collect(),
1331 );
1332
1333 let scopes = ValidationUtils::extract_scopes(
1334 &claims
1335 .as_object()
1336 .unwrap_or(&serde_json::Map::new())
1337 .iter()
1338 .map(|(k, v)| (k.clone(), v.clone()))
1339 .collect(),
1340 None,
1341 );
1342
1343 Ok(TokenValidationResult {
1344 is_valid: true,
1345 subject,
1346 issuer: claims
1347 .get("iss")
1348 .and_then(|v| v.as_str())
1349 .map(|s| s.to_string()),
1350 audience: claims
1351 .get("aud")
1352 .and_then(|v| v.as_str())
1353 .map(|s| vec![s.to_string()])
1354 .unwrap_or_default(),
1355 scopes,
1356 expires_at: claims.get("exp").and_then(|v| v.as_i64()).and_then(|exp| {
1357 use chrono::{TimeZone, Utc};
1358 Utc.timestamp_opt(exp, 0).single()
1359 }),
1360 metadata: claims
1361 .as_object()
1362 .unwrap_or(&serde_json::Map::new())
1363 .iter()
1364 .map(|(k, v)| (k.clone(), v.clone()))
1365 .collect(),
1366 validation_messages: Vec::new(),
1367 })
1368 }
1369 Err(e) => Ok(TokenValidationResult {
1370 is_valid: false,
1371 subject: None,
1372 issuer: None,
1373 audience: Vec::new(),
1374 scopes: Vec::new(),
1375 expires_at: None,
1376 metadata: std::collections::HashMap::new(),
1377 validation_messages: vec![format!("JWT validation failed: {}", e)],
1378 }),
1379 }
1380 } else {
1381 if token.is_empty() {
1383 return Ok(TokenValidationResult {
1384 is_valid: false,
1385 subject: None,
1386 issuer: None,
1387 audience: Vec::new(),
1388 scopes: Vec::new(),
1389 expires_at: None,
1390 metadata: std::collections::HashMap::new(),
1391 validation_messages: vec!["Token is empty".to_string()],
1392 });
1393 }
1394
1395 if token_type.contains("saml") {
1397 let trimmed = token.trim();
1398 if !trimmed.starts_with('<') || !trimmed.ends_with('>') {
1399 return Ok(TokenValidationResult {
1400 is_valid: false,
1401 subject: None,
1402 issuer: None,
1403 audience: Vec::new(),
1404 scopes: Vec::new(),
1405 expires_at: None,
1406 metadata: std::collections::HashMap::new(),
1407 validation_messages: vec![format!(
1408 "Invalid SAML token structure for type: {}",
1409 token_type
1410 )],
1411 });
1412 }
1413 }
1414
1415 if !token
1417 .chars()
1418 .all(|c| !c.is_control() || c == '\n' || c == '\r' || c == '\t')
1419 {
1420 return Ok(TokenValidationResult {
1421 is_valid: false,
1422 subject: None,
1423 issuer: None,
1424 audience: Vec::new(),
1425 scopes: Vec::new(),
1426 expires_at: None,
1427 metadata: std::collections::HashMap::new(),
1428 validation_messages: vec![
1429 "Token contains invalid control characters".to_string(),
1430 ],
1431 });
1432 }
1433
1434 Ok(TokenValidationResult {
1435 is_valid: true,
1436 subject: None,
1437 issuer: None,
1438 audience: Vec::new(),
1439 scopes: Vec::new(),
1440 expires_at: None,
1441 metadata: std::collections::HashMap::new(),
1442 validation_messages: vec![format!(
1443 "Basic structural validation passed for token type: {}",
1444 token_type
1445 )],
1446 })
1447 }
1448 }
1449
1450 fn supported_subject_token_types(&self) -> Vec<String> {
1452 self.config.supported_subject_token_types.clone()
1453 }
1454
1455 fn supported_requested_token_types(&self) -> Vec<String> {
1457 self.config.supported_requested_token_types.clone()
1458 }
1459
1460 fn capabilities(&self) -> TokenExchangeCapabilities {
1462 TokenExchangeCapabilities {
1463 basic_exchange: true,
1464 multi_party_chains: self.config.enable_multi_party_chains,
1465 context_preservation: self.config.enable_context_preservation,
1466 audit_trail: self.config.require_audit_trail,
1467 session_integration: true, jwt_operations: true, policy_control: true, cross_domain_exchange: self.config.cross_domain_settings.enabled,
1471 max_delegation_depth: self.config.max_delegation_depth,
1472 complexity_level: ServiceComplexityLevel::Advanced,
1473 }
1474 }
1475}
1476
1477#[cfg(test)]
1478mod tests {
1479 use super::*;
1480
1481 #[tokio::test]
1482 async fn test_config_creation() {
1483 let config = AdvancedTokenExchangeConfig::default();
1484 assert!(config.enable_multi_party_chains);
1485 assert!(!config.supported_subject_token_types.is_empty());
1486 assert!(!config.supported_requested_token_types.is_empty());
1487 assert!(!config.trusted_issuers.is_empty());
1488 }
1489
1490 #[test]
1491 fn test_jwt_key_functionality() {
1492 use crate::server::oidc::oidc_session_management::SessionManager;
1493 use jsonwebtoken::{DecodingKey, EncodingKey};
1494
1495 let secret = b"test-secret-key-32-bytes-minimum!";
1497 let encoding_key = EncodingKey::from_secret(secret);
1498 let decoding_key = DecodingKey::from_secret(secret);
1499
1500 let config = AdvancedTokenExchangeConfig {
1501 jwt_signing_key: "test-secret-key-32-bytes-minimum!".to_string(),
1502 jwt_verification_key: "test-secret-key-32-bytes-minimum!".to_string(),
1503 ..Default::default()
1504 };
1505
1506 let session_manager = Arc::new(SessionManager::new(Default::default()));
1507
1508 let manager = AdvancedTokenExchangeManager {
1510 config,
1511 session_manager,
1512 processors: HashMap::new(),
1513 exchange_audit: Arc::new(tokio::sync::RwLock::new(Vec::new())),
1514 encoding_key,
1515 decoding_key,
1516 };
1517
1518 let audit_info = ExchangeAuditInfo {
1520 exchange_id: Uuid::new_v4(),
1521 timestamp: Utc::now(),
1522 exchange_type: TokenExchangeType::Delegation,
1523 subject_info: SubjectInfo {
1524 subject: "test_user".to_string(),
1525 subject_type: "user".to_string(),
1526 original_token_info: TokenInfo {
1527 token_type: "jwt".to_string(),
1528 issuer: "test".to_string(),
1529 audience: vec!["test".to_string()],
1530 scopes: vec!["read".to_string()],
1531 expires_at: None,
1532 metadata: HashMap::new(),
1533 },
1534 attributes: HashMap::new(),
1535 },
1536 actor_info: None,
1537 policy_decisions: Vec::new(),
1538 security_assessments: Vec::new(),
1539 };
1540
1541 let result = manager.generate_audit_token(&audit_info);
1543 assert!(
1544 result.is_ok(),
1545 "JWT keys should be properly initialized for signing"
1546 );
1547 }
1548
1549 #[test]
1550 fn test_exchange_request_creation() {
1551 let request = AdvancedTokenExchangeRequest {
1552 grant_type: "urn:ietf:params:oauth:grant-type:token-exchange".to_string(),
1553 subject_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9".to_string(),
1554 subject_token_type: "urn:ietf:params:oauth:token-type:jwt".to_string(),
1555 requested_token_type: "urn:ietf:params:oauth:token-type:access_token".to_string(),
1556 actor_token: None,
1557 actor_token_type: None,
1558 scope: Some("read write".to_string()),
1559 audience: vec!["https://api.example.com".to_string()],
1560 resource: Vec::new(),
1561 exchange_context: None,
1562 policy_requirements: Vec::new(),
1563 custom_parameters: HashMap::new(),
1564 };
1565
1566 assert_eq!(
1567 request.grant_type,
1568 "urn:ietf:params:oauth:grant-type:token-exchange"
1569 );
1570 assert_eq!(
1571 request.subject_token_type,
1572 "urn:ietf:params:oauth:token-type:jwt"
1573 );
1574 }
1575
1576 #[test]
1577 fn test_exchange_context_creation() {
1578 let context = ExchangeContext {
1579 transaction_id: "txn_123".to_string(),
1580 business_context: serde_json::json!({
1581 "operation": "payment",
1582 "amount": 100.0
1583 }),
1584 delegation_chain: Vec::new(),
1585 original_request: None,
1586 security_context: None,
1587 custom_fields: HashMap::new(),
1588 };
1589
1590 assert_eq!(context.transaction_id, "txn_123");
1591 assert_eq!(context.business_context["operation"], "payment");
1592 }
1593
1594 #[test]
1595 fn test_delegation_link_creation() {
1596 let link = DelegationLink {
1597 delegator: "service_a".to_string(),
1598 delegatee: "service_b".to_string(),
1599 delegated_at: Utc::now(),
1600 delegation_reason: "API call forwarding".to_string(),
1601 delegated_scopes: vec!["read".to_string(), "write".to_string()],
1602 restrictions: Vec::new(),
1603 };
1604
1605 assert_eq!(link.delegator, "service_a");
1606 assert_eq!(link.delegated_scopes.len(), 2);
1607 }
1608}