From af650716dac997201d38de1e85a24e3332d19d3f Mon Sep 17 00:00:00 2001 From: yxrxy <1532529704@qq.com> Date: Mon, 8 Dec 2025 21:15:04 +0800 Subject: [PATCH] feat: add is-admin user api (#1063) --- rustfs/src/admin/handlers.rs | 44 ++++++++++++++++++++++++++++++++++++ rustfs/src/admin/mod.rs | 10 ++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/rustfs/src/admin/handlers.rs b/rustfs/src/admin/handlers.rs index ddcfc7eb..878ad578 100644 --- a/rustfs/src/admin/handlers.rs +++ b/rustfs/src/admin/handlers.rs @@ -89,6 +89,14 @@ pub mod tier; pub mod trace; pub mod user; +#[derive(Debug, Serialize)] +#[serde(rename_all = "PascalCase")] +pub struct IsAdminResponse { + pub is_admin: bool, + pub access_key: String, + pub message: String, +} + #[allow(dead_code)] #[derive(Debug, Serialize, Default)] #[serde(rename_all = "PascalCase", default)] @@ -143,6 +151,42 @@ impl Operation for HealthCheckHandler { } } +pub struct IsAdminHandler {} +#[async_trait::async_trait] +impl Operation for IsAdminHandler { + async fn call(&self, req: S3Request, _params: Params<'_, '_>) -> S3Result> { + let Some(input_cred) = req.credentials else { + return Err(s3_error!(InvalidRequest, "get cred failed")); + }; + + let (_cred, _owner) = + check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &input_cred.access_key).await?; + + let access_key_to_check = input_cred.access_key.clone(); + + // Check if the user is admin by comparing with global credentials + let is_admin = if let Some(sys_cred) = get_global_action_cred() { + sys_cred.access_key == access_key_to_check + } else { + false + }; + + let response = IsAdminResponse { + is_admin, + access_key: access_key_to_check, + message: format!("User is {} an administrator", if is_admin { "" } else { "not" }), + }; + + let data = serde_json::to_vec(&response) + .map_err(|_e| S3Error::with_message(S3ErrorCode::InternalError, "parse IsAdminResponse failed"))?; + + let mut header = HeaderMap::new(); + header.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); + + Ok(S3Response::with_headers((StatusCode::OK, Body::from(data)), header)) + } +} + pub struct AccountInfoHandler {} #[async_trait::async_trait] impl Operation for AccountInfoHandler { diff --git a/rustfs/src/admin/mod.rs b/rustfs/src/admin/mod.rs index 4e9fcfb9..01d4942c 100644 --- a/rustfs/src/admin/mod.rs +++ b/rustfs/src/admin/mod.rs @@ -23,8 +23,8 @@ pub mod utils; mod console_test; use handlers::{ - GetReplicationMetricsHandler, HealthCheckHandler, ListRemoteTargetHandler, RemoveRemoteTargetHandler, SetRemoteTargetHandler, - bucket_meta, + GetReplicationMetricsHandler, HealthCheckHandler, IsAdminHandler, ListRemoteTargetHandler, RemoveRemoteTargetHandler, + SetRemoteTargetHandler, bucket_meta, event::{ListNotificationTargets, ListTargetsArns, NotificationTarget, RemoveNotificationTarget}, group, kms, kms_dynamic, kms_keys, policies, pools, profile::{TriggerProfileCPU, TriggerProfileMemory}, @@ -52,6 +52,12 @@ pub fn make_admin_route(console_enabled: bool) -> std::io::Result // 1 r.insert(Method::POST, "/", AdminOperation(&sts::AssumeRoleHandle {}))?; + r.insert( + Method::GET, + format!("{}{}", ADMIN_PREFIX, "/v3/is-admin").as_str(), + AdminOperation(&IsAdminHandler {}), + )?; + register_rpc_route(&mut r)?; register_user_route(&mut r)?;