diff --git a/crates/ecstore/src/admin_server_info.rs b/crates/ecstore/src/admin_server_info.rs index 54f9b9814..9b159433c 100644 --- a/crates/ecstore/src/admin_server_info.rs +++ b/crates/ecstore/src/admin_server_info.rs @@ -162,8 +162,9 @@ pub async fn get_local_server_property() -> ServerProperties { let mut props = ServerProperties { endpoint: addr, - uptime: SystemTime::now() - .duration_since(*GLOBAL_BOOT_TIME.get().unwrap()) + uptime: GLOBAL_BOOT_TIME + .get() + .and_then(|boot_time| SystemTime::now().duration_since(*boot_time).ok()) .unwrap_or_default() .as_secs(), network, diff --git a/crates/ecstore/src/notification_sys.rs b/crates/ecstore/src/notification_sys.rs index 1df246d23..d6906cdbd 100644 --- a/crates/ecstore/src/notification_sys.rs +++ b/crates/ecstore/src/notification_sys.rs @@ -786,8 +786,9 @@ where fn offline_server_properties(host: &str, endpoints: &EndpointServerPools) -> ServerProperties { ServerProperties { - uptime: SystemTime::now() - .duration_since(*GLOBAL_BOOT_TIME.get().unwrap()) + uptime: GLOBAL_BOOT_TIME + .get() + .and_then(|boot_time| SystemTime::now().duration_since(*boot_time).ok()) .unwrap_or_default() .as_secs(), version: get_commit_id(), diff --git a/rustfs/src/admin/handlers/service_account.rs b/rustfs/src/admin/handlers/service_account.rs index 271ffc3ff..68e8c75d1 100644 --- a/rustfs/src/admin/handlers/service_account.rs +++ b/rustfs/src/admin/handlers/service_account.rs @@ -1018,7 +1018,9 @@ fn parse_list_access_keys_query(query: Option<&str>) -> ListAccessKeysQuery { for (key, value) in form_urlencoded::parse(query.as_bytes()) { match key.as_ref() { - "users" => parsed.users.push(value.into_owned()), + "users" if !value.is_empty() => { + parsed.users.push(value.into_owned()); + } "all" => parsed.all = parse_bool_param(value.as_ref()), "listType" => parsed.list_type = value.into_owned(), _ => {} @@ -1124,13 +1126,9 @@ impl Operation for ListAccessKeysBulk { } users } else { - let mut checked = Vec::new(); - for user in requested_users { - if iam_store.get_user(&user).await.is_some() { - checked.push(user); - } - } - checked + // Keep requested identities as-is. Some valid parent users (for example external + // identities) may not be persisted as regular IAM users, but can still own keys. + requested_users }; let (list_sts_keys, list_service_accounts) = match query.list_type.as_str() { @@ -1399,6 +1397,25 @@ mod tests { assert_eq!(query.list_type, ACCESS_KEY_LIST_SVCACC_ONLY); } + #[test] + fn list_access_keys_query_ignores_empty_users_values() { + let query = parse_list_access_keys_query(Some("users=&users=alice&users=&listType=all")); + + assert_eq!(query.users, vec!["alice".to_string()]); + assert!(!query.all); + assert_eq!(query.list_type, ACCESS_KEY_LIST_ALL); + } + + #[test] + fn list_access_keys_query_all_with_empty_users_does_not_conflict() { + let query = parse_list_access_keys_query(Some("users=&all=true&listType=all")); + + assert!(query.users.is_empty()); + assert!(query.all); + assert_eq!(query.list_type, ACCESS_KEY_LIST_ALL); + assert!(!query.all || query.users.is_empty()); + } + #[test] fn list_access_keys_query_defaults_to_all_list_type() { let query = ListAccessKeysQuery::default();