mockforge_http/auth/
token_lifecycle.rs1use chrono::Utc;
10use serde::{Deserialize, Serialize};
11use sha2::{Digest, Sha256};
12use std::collections::HashMap;
13use std::sync::Arc;
14use tokio::sync::RwLock;
15
16use mockforge_core::Error;
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct RevokedToken {
21 pub token_id: String,
23 pub user_id: Option<String>,
25 pub revoked_at: i64,
27 pub reason: String,
29 pub expires_at: Option<i64>,
31}
32
33#[derive(Debug, Clone)]
35pub struct TokenRevocationStore {
36 revoked_tokens: Arc<RwLock<HashMap<String, RevokedToken>>>,
38 user_revoked_tokens: Arc<RwLock<HashMap<String, Vec<String>>>>,
40}
41
42impl TokenRevocationStore {
43 pub fn new() -> Self {
45 Self {
46 revoked_tokens: Arc::new(RwLock::new(HashMap::new())),
47 user_revoked_tokens: Arc::new(RwLock::new(HashMap::new())),
48 }
49 }
50
51 pub async fn revoke_token(
53 &self,
54 token_id: String,
55 user_id: Option<String>,
56 reason: String,
57 expires_at: Option<i64>,
58 ) {
59 let revoked = RevokedToken {
60 token_id: token_id.clone(),
61 user_id: user_id.clone(),
62 revoked_at: Utc::now().timestamp(),
63 reason,
64 expires_at,
65 };
66
67 let mut tokens = self.revoked_tokens.write().await;
68 tokens.insert(token_id.clone(), revoked);
69
70 if let Some(uid) = user_id {
71 let mut user_tokens = self.user_revoked_tokens.write().await;
72 user_tokens.entry(uid).or_insert_with(Vec::new).push(token_id);
73 }
74 }
75
76 pub async fn revoke_user_tokens(&self, user_id: String, reason: String) {
78 let mut user_tokens = self.user_revoked_tokens.write().await;
79 if let Some(token_ids) = user_tokens.get(&user_id) {
80 let mut tokens = self.revoked_tokens.write().await;
81 for token_id in token_ids {
82 if let Some(revoked) = tokens.get_mut(token_id) {
83 revoked.revoked_at = Utc::now().timestamp();
84 revoked.reason = reason.clone();
85 }
86 }
87 }
88 }
89
90 pub async fn is_revoked(&self, token_id: &str) -> Option<RevokedToken> {
92 let tokens = self.revoked_tokens.read().await;
93 tokens.get(token_id).cloned()
94 }
95
96 pub async fn get_revocation_status(&self, token_id: &str) -> Option<RevokedToken> {
98 self.is_revoked(token_id).await
99 }
100
101 pub async fn cleanup_expired(&self) {
103 let now = Utc::now().timestamp();
104 let mut tokens = self.revoked_tokens.write().await;
105 tokens.retain(|_, revoked| revoked.expires_at.map_or(true, |exp| exp > now));
106 }
107}
108
109impl Default for TokenRevocationStore {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115#[derive(Debug, Clone)]
117pub struct KeyRotationState {
118 active_keys: Arc<RwLock<HashMap<String, ActiveKey>>>,
120 grace_period_seconds: i64,
122}
123
124#[derive(Debug, Clone)]
126pub struct ActiveKey {
127 pub kid: String,
129 pub created_at: i64,
131 pub inactive_at: Option<i64>,
133 pub is_primary: bool,
135}
136
137impl KeyRotationState {
138 pub fn new(grace_period_seconds: i64) -> Self {
140 Self {
141 active_keys: Arc::new(RwLock::new(HashMap::new())),
142 grace_period_seconds,
143 }
144 }
145
146 pub async fn add_key(&self, kid: String, is_primary: bool) {
148 let mut keys = self.active_keys.write().await;
149 keys.insert(
150 kid.clone(),
151 ActiveKey {
152 kid,
153 created_at: Utc::now().timestamp(),
154 inactive_at: None,
155 is_primary,
156 },
157 );
158 }
159
160 pub async fn rotate_key(&self, new_kid: String) -> Result<(), Error> {
162 let mut keys = self.active_keys.write().await;
163
164 for key in keys.values_mut() {
166 key.is_primary = false;
167 key.inactive_at = Some(Utc::now().timestamp() + self.grace_period_seconds);
169 }
170
171 keys.insert(
173 new_kid.clone(),
174 ActiveKey {
175 kid: new_kid,
176 created_at: Utc::now().timestamp(),
177 inactive_at: None,
178 is_primary: true,
179 },
180 );
181
182 Ok(())
183 }
184
185 pub async fn get_active_keys(&self) -> Vec<ActiveKey> {
187 let now = Utc::now().timestamp();
188 let keys = self.active_keys.read().await;
189 keys.values()
190 .filter(|key| key.inactive_at.map_or(true, |inactive_at| inactive_at > now))
191 .cloned()
192 .collect()
193 }
194
195 pub async fn get_primary_key(&self) -> Option<ActiveKey> {
197 let keys = self.active_keys.read().await;
198 keys.values().find(|key| key.is_primary).cloned()
199 }
200
201 pub async fn cleanup_old_keys(&self) {
203 let now = Utc::now().timestamp();
204 let mut keys = self.active_keys.write().await;
205 keys.retain(|_, key| key.inactive_at.map_or(true, |inactive_at| inactive_at > now));
206 }
207}
208
209#[derive(Debug, Clone)]
211pub struct ClockSkewState {
212 skew_seconds: Arc<RwLock<i64>>,
214 apply_to_issuance: bool,
216 apply_to_validation: bool,
218}
219
220impl ClockSkewState {
221 pub fn new() -> Self {
223 Self {
224 skew_seconds: Arc::new(RwLock::new(0)),
225 apply_to_issuance: true,
226 apply_to_validation: true,
227 }
228 }
229
230 pub async fn set_skew(&self, skew_seconds: i64) {
232 let mut skew = self.skew_seconds.write().await;
233 *skew = skew_seconds;
234 }
235
236 pub async fn get_skew(&self) -> i64 {
238 let skew = self.skew_seconds.read().await;
239 *skew
240 }
241
242 pub async fn get_adjusted_time(&self) -> i64 {
244 let skew = self.skew_seconds.read().await;
245 Utc::now().timestamp() + *skew
246 }
247
248 pub async fn apply_issuance_skew(&self, timestamp: i64) -> i64 {
250 if self.apply_to_issuance {
251 let skew = self.skew_seconds.read().await;
252 timestamp + *skew
253 } else {
254 timestamp
255 }
256 }
257
258 pub async fn apply_validation_skew(&self, timestamp: i64) -> i64 {
260 if self.apply_to_validation {
261 let skew = self.skew_seconds.read().await;
262 timestamp - *skew
263 } else {
264 timestamp
265 }
266 }
267}
268
269impl Default for ClockSkewState {
270 fn default() -> Self {
271 Self::new()
272 }
273}
274
275#[derive(Debug, Clone)]
277pub struct TokenLifecycleManager {
278 pub revocation: TokenRevocationStore,
280 pub key_rotation: KeyRotationState,
282 pub clock_skew: ClockSkewState,
284}
285
286impl TokenLifecycleManager {
287 pub fn new(grace_period_seconds: i64) -> Self {
289 Self {
290 revocation: TokenRevocationStore::new(),
291 key_rotation: KeyRotationState::new(grace_period_seconds),
292 clock_skew: ClockSkewState::new(),
293 }
294 }
295}
296
297impl Default for TokenLifecycleManager {
298 fn default() -> Self {
299 Self::new(3600) }
301}
302
303pub fn extract_token_id(token: &str) -> String {
305 let mut hasher = Sha256::new();
308 hasher.update(token.as_bytes());
309 format!("{:x}", hasher.finalize())
310}