fix(iam): sync user cache on load-user notifications (#2104)

This commit is contained in:
安正超
2026-03-09 09:36:02 +08:00
committed by GitHub
parent a02c354ef5
commit 9d03029959
2 changed files with 52 additions and 6 deletions

View File

@@ -1728,6 +1728,15 @@ where
}
let u = m[name].clone();
match user_type {
UserType::Sts => {
Cache::add_or_update(&self.cache.sts_accounts, name, &u, OffsetDateTime::now_utc());
}
UserType::Reg | UserType::Svc => {
Cache::add_or_update(&self.cache.users, name, &u, OffsetDateTime::now_utc());
}
UserType::None => {}
}
match user_type {
UserType::Sts => {
@@ -1752,7 +1761,7 @@ where
return Ok(());
}
Cache::add_or_update(&self.cache.sts_policies, name, &m[name], OffsetDateTime::now_utc());
Cache::add_or_update(&self.cache.user_policies, name, &m[name], OffsetDateTime::now_utc());
}
UserType::Svc => {

View File

@@ -1083,7 +1083,16 @@ mod tests {
Err(Error::InvalidArgument)
}
async fn load_user(&self, _name: &str, _user_type: UserType, _m: &mut HashMap<String, UserIdentity>) -> Result<()> {
async fn load_user(&self, name: &str, user_type: UserType, m: &mut HashMap<String, UserIdentity>) -> Result<()> {
if user_type == UserType::Reg && name == "notify-user" {
let user = UserIdentity::from(Credentials {
access_key: name.to_string(),
secret_key: "notify-user-secret".to_string(),
status: ACCOUNT_ON.to_string(),
..Default::default()
});
m.insert(name.to_string(), user);
}
Ok(())
}
@@ -1148,11 +1157,14 @@ mod tests {
async fn load_mapped_policy(
&self,
_name: &str,
_user_type: UserType,
_is_group: bool,
_m: &mut HashMap<String, MappedPolicy>,
name: &str,
user_type: UserType,
is_group: bool,
m: &mut HashMap<String, MappedPolicy>,
) -> Result<()> {
if user_type == UserType::Reg && !is_group && name == "notify-user" {
m.insert(name.to_string(), MappedPolicy::new("readwrite"));
}
Ok(())
}
@@ -1247,4 +1259,29 @@ mod tests {
"STS temp credentials with no groups in args should still be allowed via parent user's group policy (readwrite)"
);
}
/// Regression test for cross-node IAM notifications:
/// `load_user` must populate user cache, and regular-user mapped policy must be written to
/// `user_policies` (not `sts_policies`), otherwise list-users and bucket-scoped user listing
/// may miss users on follower nodes.
#[tokio::test]
async fn test_load_user_notification_populates_user_and_policy_caches() {
let store = StsGroupsFallbackMockStore;
let cache_manager = IamCache::new(store).await;
let iam_sys = IamSys::new(cache_manager);
iam_sys.load_user("notify-user", UserType::Reg).await.unwrap();
let users = iam_sys.list_users().await.unwrap();
assert!(
users.contains_key("notify-user"),
"regular user loaded via notification must appear in list_users cache view"
);
let bucket_users = iam_sys.list_bucket_users("notification-regression-bucket").await.unwrap();
assert!(
bucket_users.contains_key("notify-user"),
"regular user mapped policy must be written to user_policies for bucket user listing"
);
}
}