fix(auth): preserve IAMAuth clone and correct missing-key error (#2123)

This commit is contained in:
安正超
2026-03-11 21:59:12 +08:00
committed by GitHub
parent df57f0c033
commit aa84d34bf8
3 changed files with 44 additions and 21 deletions

View File

@@ -21,7 +21,6 @@ use matchit::Params;
use rustfs_common::heal_channel::HealOpts;
use rustfs_config::MAX_HEAL_REQUEST_SIZE;
use rustfs_ecstore::bucket::utils::is_valid_object_prefix;
use rustfs_ecstore::error::StorageError;
use rustfs_ecstore::store_utils::is_reserved_or_invalid_bucket;
use rustfs_utils::path::path_join;
use s3s::{Body, S3Request, S3Response, S3Result, s3_error};
@@ -141,8 +140,7 @@ impl Operation for HealHandler {
#[derive(Default)]
struct HealResp {
resp_bytes: Vec<u8>,
_api_err: Option<StorageError>,
_err_body: String,
api_err: Option<String>,
}
let heal_path = path_join(&[PathBuf::from(hip.bucket.clone()), PathBuf::from(hip.obj_prefix.clone())]);
@@ -156,7 +154,6 @@ impl Operation for HealHandler {
spawn(async move {
match rustfs_common::heal_channel::query_heal_status(heal_path_str, client_token).await {
Ok(_) => {
// TODO: Get actual response from channel
let _ = tx_clone
.send(HealResp {
resp_bytes: vec![],
@@ -167,7 +164,7 @@ impl Operation for HealHandler {
Err(e) => {
let _ = tx_clone
.send(HealResp {
_api_err: Some(StorageError::other(e)),
api_err: Some(e),
..Default::default()
})
.await;
@@ -181,7 +178,6 @@ impl Operation for HealHandler {
spawn(async move {
match rustfs_common::heal_channel::cancel_heal_task(heal_path_str).await {
Ok(_) => {
// TODO: Get actual response from channel
let _ = tx_clone
.send(HealResp {
resp_bytes: vec![],
@@ -192,7 +188,7 @@ impl Operation for HealHandler {
Err(e) => {
let _ = tx_clone
.send(HealResp {
_api_err: Some(StorageError::other(e)),
api_err: Some(e),
..Default::default()
})
.await;
@@ -229,7 +225,7 @@ impl Operation for HealHandler {
// Error - send error response
let _ = tx_clone
.send(HealResp {
_api_err: Some(StorageError::other(e)),
api_err: Some(e),
..Default::default()
})
.await;
@@ -239,7 +235,12 @@ impl Operation for HealHandler {
}
match rx.recv().await {
Some(result) => Ok(S3Response::new((StatusCode::OK, Body::from(result.resp_bytes)))),
Some(result) => {
if let Some(api_err) = result.api_err {
return Err(s3_error!(InternalError, "{api_err}"));
}
Ok(S3Response::new((StatusCode::OK, Body::from(result.resp_bytes))))
}
None => Ok(S3Response::new((StatusCode::INTERNAL_SERVER_ERROR, Body::from(vec![])))),
}
}

View File

@@ -85,6 +85,7 @@ fn test_register_routes_cover_representative_admin_paths() {
assert_route(&router, Method::GET, &admin_path("/v3/rebalance/status"));
assert_route(&router, Method::POST, &admin_path("/v3/heal/test-bucket"));
assert_route(&router, Method::POST, &admin_path("/v3/heal/test-bucket/prefix"));
assert_route(&router, Method::POST, &admin_path("/v3/background-heal/status"));
assert_route(&router, Method::GET, &admin_path("/v3/tier"));
assert_route(&router, Method::POST, &admin_path("/v3/tier/clear"));

View File

@@ -91,26 +91,32 @@ pub enum AuthType {
StreamingUnsignedTrailer,
}
#[derive(Debug)]
pub struct IAMAuth {
simple_auth: SimpleAuth,
access_key: String,
secret_key: SecretKey,
}
impl Clone for IAMAuth {
fn clone(&self) -> Self {
// Since SimpleAuth doesn't implement Clone, we create a new one
// This is a simplified implementation - in a real scenario, you might need
// to store the credentials separately to properly clone
Self {
simple_auth: SimpleAuth::new(),
simple_auth: SimpleAuth::from_single(self.access_key.clone(), self.secret_key.clone()),
access_key: self.access_key.clone(),
secret_key: self.secret_key.clone(),
}
}
}
impl IAMAuth {
pub fn new(ak: impl Into<String>, sk: impl Into<SecretKey>) -> Self {
let simple_auth = SimpleAuth::from_single(ak, sk);
Self { simple_auth }
let access_key = ak.into();
let secret_key = sk.into();
let simple_auth = SimpleAuth::from_single(access_key.clone(), secret_key.clone());
Self {
simple_auth,
access_key,
secret_key,
}
}
}
@@ -143,6 +149,10 @@ impl S3Auth for IAMAuth {
return Ok(SecretKey::from(String::new()));
}
if access_key == self.access_key {
return Ok(self.secret_key.clone());
}
if let Ok(key) = self.simple_auth.get_secret_key(access_key).await {
return Ok(key);
}
@@ -264,17 +274,19 @@ pub async fn check_key_valid(session_token: &str, access_key: &str) -> S3Result<
.map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("check claims failed1 {e}")))?;
if !ok {
if let Some(u) = u
&& u.credentials.status == "off"
{
let Some(u) = u else {
return Err(s3_error!(InvalidAccessKeyId, "check key failed"));
};
if u.credentials.status == "off" {
return Err(s3_error!(InvalidRequest, "ErrAccessKeyDisabled"));
}
return Err(s3_error!(InvalidRequest, "ErrAccessKeyDisabled"));
return Err(s3_error!(InvalidRequest, "check key failed"));
}
let Some(u) = u else {
return Err(s3_error!(InvalidRequest, "check key failed"));
return Err(s3_error!(InvalidAccessKeyId, "check key failed"));
};
cred = u.credentials;
@@ -899,6 +911,15 @@ mod tests {
assert_eq!(size_of_val(&iam_auth), size_of::<IAMAuth>());
}
#[tokio::test]
async fn test_iam_auth_clone_preserves_bootstrap_secret() {
let iam_auth = IAMAuth::new("test-ak", SecretKey::from("test-sk"));
let cloned = iam_auth.clone();
let secret = cloned.get_secret_key("test-ak").await;
assert!(secret.is_ok());
}
#[tokio::test]
async fn test_iam_auth_get_secret_key_empty_access_key() {
let iam_auth = IAMAuth::new("test-ak", SecretKey::from("test-sk"));