mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-28 07:57:01 +00:00
fix(auth): align ListBuckets discovery with IAM policies (#5746)
This commit is contained in:
@@ -16,7 +16,12 @@
|
||||
|
||||
use super::storage_api::bucket_usecase::ECStore;
|
||||
use super::storage_api::bucket_usecase::StorageObjectInfo as ObjectInfo;
|
||||
use super::storage_api::bucket_usecase::access::{ReqInfo, authorize_request, bucket_config_mutation_incarnation, req_info_ref};
|
||||
#[cfg(test)]
|
||||
use super::storage_api::bucket_usecase::access::ReqInfo;
|
||||
use super::storage_api::bucket_usecase::access::{
|
||||
authorize_request, bucket_config_mutation_incarnation, log_list_buckets_iam_implicit_deny,
|
||||
prepare_list_buckets_iam_authorization, req_info_ref,
|
||||
};
|
||||
#[cfg(test)]
|
||||
use super::storage_api::bucket_usecase::bucket::target::BucketTarget;
|
||||
use super::storage_api::bucket_usecase::bucket::{
|
||||
@@ -70,7 +75,6 @@ use crate::auth::get_condition_values_with_client_info;
|
||||
use crate::error::ApiError;
|
||||
use crate::server::RemoteAddr;
|
||||
use crate::storage::storage_api::lock_bucket_targets_metadata;
|
||||
use futures::StreamExt;
|
||||
use http::StatusCode;
|
||||
use metrics::counter;
|
||||
use rustfs_config::RUSTFS_REGION;
|
||||
@@ -1388,55 +1392,31 @@ impl DefaultBucketUsecase {
|
||||
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
|
||||
};
|
||||
|
||||
let mut req = req;
|
||||
|
||||
if req.credentials.as_ref().is_none_or(|cred| cred.access_key.is_empty()) {
|
||||
return Err(S3Error::with_message(S3ErrorCode::AccessDenied, "Access Denied"));
|
||||
}
|
||||
|
||||
// The ListAllMyBuckets probe and the per-bucket probes cloned from this
|
||||
// request treat denial as an expected filter outcome (issue #5740).
|
||||
if let Some(req_info) = req.extensions.get_mut::<ReqInfo>() {
|
||||
req_info.suppress_denial_log = true;
|
||||
}
|
||||
|
||||
let bucket_infos = if let Err(e) = authorize_request(&mut req, Action::S3Action(S3Action::ListAllMyBucketsAction)).await {
|
||||
if e.code() != &S3ErrorCode::AccessDenied {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
let mut list_bucket_infos = store.list_bucket(&BucketOptions::default()).await.map_err(ApiError::from)?;
|
||||
|
||||
list_bucket_infos = futures::stream::iter(list_bucket_infos)
|
||||
.filter_map(|info| async {
|
||||
let mut req_clone = req.clone();
|
||||
let Some(req_info) = req_clone.extensions.get_mut::<ReqInfo>() else {
|
||||
debug!(bucket = %info.name, "ReqInfo missing in extensions, skipping bucket authorization");
|
||||
return None;
|
||||
};
|
||||
req_info.bucket = Some(info.name.clone());
|
||||
|
||||
if authorize_request(&mut req_clone, Action::S3Action(S3Action::ListBucketAction))
|
||||
.await
|
||||
.is_ok()
|
||||
|| authorize_request(&mut req_clone, Action::S3Action(S3Action::GetBucketLocationAction))
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
Some(info)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
if list_bucket_infos.is_empty() {
|
||||
return Err(S3Error::with_message(S3ErrorCode::AccessDenied, "Access Denied"));
|
||||
}
|
||||
list_bucket_infos
|
||||
} else {
|
||||
let iam_authorization = prepare_list_buckets_iam_authorization(&req).await?;
|
||||
let bucket_infos = if iam_authorization.is_allowed("", S3Action::ListAllMyBucketsAction).await {
|
||||
store.list_bucket(&BucketOptions::default()).await.map_err(ApiError::from)?
|
||||
} else {
|
||||
log_list_buckets_iam_implicit_deny(&req)?;
|
||||
let bucket_infos = store.list_bucket(&BucketOptions::default()).await.map_err(ApiError::from)?;
|
||||
let mut visible_bucket_infos = Vec::new();
|
||||
for info in bucket_infos {
|
||||
if iam_authorization.is_allowed(&info.name, S3Action::ListBucketAction).await
|
||||
|| iam_authorization
|
||||
.is_allowed(&info.name, S3Action::GetBucketLocationAction)
|
||||
.await
|
||||
{
|
||||
visible_bucket_infos.push(info);
|
||||
}
|
||||
}
|
||||
|
||||
if visible_bucket_infos.is_empty() {
|
||||
return Err(ApiError::access_denied().into());
|
||||
}
|
||||
visible_bucket_infos
|
||||
};
|
||||
|
||||
Ok(S3Response::new(build_list_buckets_output(&bucket_infos)))
|
||||
|
||||
Reference in New Issue
Block a user