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)?;