diff --git a/crates/iam/src/lib.rs b/crates/iam/src/lib.rs index 592695d6..ebefb72f 100644 --- a/crates/iam/src/lib.rs +++ b/crates/iam/src/lib.rs @@ -33,7 +33,7 @@ static IAM_SYS: OnceLock>> = OnceLock::new(); #[instrument(skip(ecstore))] pub async fn init_iam_sys(ecstore: Arc) -> Result<()> { debug!("init iam system"); - let s = IamCache::new(ObjectStore::new(ecstore).await).await; + let s = IamCache::new(ObjectStore::new(ecstore)).await; IAM_SYS.get_or_init(move || IamSys::new(s).into()); Ok(()) diff --git a/crates/iam/src/store/object.rs b/crates/iam/src/store/object.rs index 05f2f3d3..0390587c 100644 --- a/crates/iam/src/store/object.rs +++ b/crates/iam/src/store/object.rs @@ -120,52 +120,18 @@ fn split_path(s: &str, last_index: bool) -> (&str, &str) { #[derive(Clone)] pub struct ObjectStore { object_api: Arc, - prev_cred: Option, } impl ObjectStore { const BUCKET_NAME: &'static str = ".rustfs.sys"; - const PREV_CRED_FILE: &'static str = "config/iam/prev_cred.json"; - /// Load previous credentials from persistent storage in .rustfs.sys bucket - async fn load_prev_cred(object_api: Arc) -> Option { - match read_config(object_api, Self::PREV_CRED_FILE).await { - Ok(data) => serde_json::from_slice::(&data).ok(), - Err(_) => None, - } + pub fn new(object_api: Arc) -> Self { + Self { object_api } } - /// Save previous credentials to persistent storage in .rustfs.sys bucket - async fn save_prev_cred(object_api: Arc, cred: &Option) -> Result<()> { - match cred { - Some(c) => { - let data = serde_json::to_vec(c).map_err(|e| Error::other(format!("Failed to serialize cred: {}", e)))?; - save_config(object_api, Self::PREV_CRED_FILE, data) - .await - .map_err(|e| Error::other(format!("Failed to write cred to storage: {}", e))) - } - None => { - // If no credentials, remove the config - match delete_config(object_api, Self::PREV_CRED_FILE).await { - Ok(_) => Ok(()), - Err(e) => { - // Ignore ConfigNotFound error when trying to delete non-existent config - if matches!(e, rustfs_ecstore::error::StorageError::ConfigNotFound) { - Ok(()) - } else { - Err(Error::other(format!("Failed to delete cred from storage: {}", e))) - } - } - } - } - } - } - - pub async fn new(object_api: Arc) -> Self { - // Load previous credentials from persistent storage in .rustfs.sys bucket - let prev_cred = Self::load_prev_cred(object_api.clone()).await.or_else(get_global_action_cred); - - Self { object_api, prev_cred } + fn decrypt_data(data: &[u8]) -> Result> { + let de = rustfs_crypto::decrypt_data(get_global_action_cred().unwrap_or_default().secret_key.as_bytes(), data)?; + Ok(de) } fn encrypt_data(data: &[u8]) -> Result> { @@ -173,65 +139,10 @@ impl ObjectStore { Ok(en) } - /// Decrypt data with credential fallback mechanism - /// First tries current credentials, then falls back to previous credentials if available - async fn decrypt_fallback(&self, data: &[u8], path: &str) -> Result> { - let current_cred = get_global_action_cred().unwrap_or_default(); - - // Try current credentials first - match rustfs_crypto::decrypt_data(current_cred.secret_key.as_bytes(), data) { - Ok(decrypted) => { - // Update persistent storage with current credentials for consistency - let _ = Self::save_prev_cred(self.object_api.clone(), &Some(current_cred)).await; - Ok(decrypted) - } - Err(_) => { - // Current credentials failed, try previous credentials - if let Some(ref prev_cred) = self.prev_cred { - match rustfs_crypto::decrypt_data(prev_cred.secret_key.as_bytes(), data) { - Ok(prev_decrypted) => { - warn!("Decryption succeeded with previous credentials, path: {}", path); - - // Re-encrypt with current credentials - match rustfs_crypto::encrypt_data(current_cred.secret_key.as_bytes(), &prev_decrypted) { - Ok(re_encrypted) => { - let _ = save_config(self.object_api.clone(), path, re_encrypted).await; - } - Err(e) => { - warn!("Failed to re-encrypt with current credentials: {}, path: {}", e, path); - } - } - - // Update persistent storage with current credentials - let _ = Self::save_prev_cred(self.object_api.clone(), &Some(current_cred)).await; - Ok(prev_decrypted) - } - Err(_) => { - // Both attempts failed - warn!("Decryption failed with both current and previous credentials, deleting config: {}", path); - let _ = self.delete_iam_config(path).await; - Err(Error::ConfigNotFound) - } - } - } else { - // No previous credentials available - warn!( - "Decryption failed with current credentials and no previous credentials available, deleting config: {}", - path - ); - let _ = self.delete_iam_config(path).await; - Err(Error::ConfigNotFound) - } - } - } - } - async fn load_iamconfig_bytes_with_metadata(&self, path: impl AsRef + Send) -> Result<(Vec, ObjectInfo)> { let (data, obj) = read_config_with_metadata(self.object_api.clone(), path.as_ref(), &ObjectOptions::default()).await?; - let decrypted_data = self.decrypt_fallback(&data, path.as_ref()).await?; - - Ok((decrypted_data, obj)) + Ok((Self::decrypt_data(&data)?, obj)) } async fn list_iam_config_items(&self, prefix: &str, ctx: CancellationToken, sender: Sender) { @@ -475,7 +386,15 @@ impl Store for ObjectStore { async fn load_iam_config(&self, path: impl AsRef + Send) -> Result { let mut data = read_config(self.object_api.clone(), path.as_ref()).await?; - data = self.decrypt_fallback(&data, path.as_ref()).await?; + data = match Self::decrypt_data(&data) { + Ok(v) => v, + Err(err) => { + warn!("delete the config file when decrypt failed failed: {}, path: {}", err, path.as_ref()); + // delete the config file when decrypt failed + let _ = self.delete_iam_config(path.as_ref()).await; + return Err(Error::ConfigNotFound); + } + }; Ok(serde_json::from_slice(&data)?) }