feat:Permission verification for deleting versions (#1341)

Signed-off-by: GatewayJ <835269233@qq.com>
Co-authored-by: loverustfs <hello@rustfs.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
GatewayJ
2026-01-02 18:19:34 +08:00
committed by GitHub
parent 134e7e237c
commit cc916926ff
2 changed files with 32 additions and 7 deletions
+8 -3
View File
@@ -25,7 +25,7 @@ use s3s::{S3Error, S3ErrorCode, S3Request, S3Result, dto::*, s3_error};
use std::collections::HashMap;
#[allow(dead_code)]
#[derive(Default, Clone)]
#[derive(Default, Clone, Debug)]
pub(crate) struct ReqInfo {
pub cred: Option<rustfs_credentials::Credentials>,
pub is_owner: bool,
@@ -38,6 +38,7 @@ pub(crate) struct ReqInfo {
/// Authorizes the request based on the action and credentials.
pub async fn authorize_request<T>(req: &mut S3Request<T>, action: Action) -> S3Result<()> {
let remote_addr = req.extensions.get::<RemoteAddr>().map(|a| a.0);
let req_info = req.extensions.get_mut::<ReqInfo>().expect("ReqInfo not found");
if let Some(cred) = &req_info.cred {
@@ -426,8 +427,12 @@ impl S3Access for FS {
/// Checks whether the DeleteObjects request has accesses to the resources.
///
/// This method returns `Ok(())` by default.
async fn delete_objects(&self, _req: &mut S3Request<DeleteObjectsInput>) -> S3Result<()> {
Ok(())
async fn delete_objects(&self, req: &mut S3Request<DeleteObjectsInput>) -> S3Result<()> {
let req_info = req.extensions.get_mut::<ReqInfo>().expect("ReqInfo not found");
req_info.bucket = Some(req.input.bucket.clone());
req_info.object = None;
req_info.version_id = None;
authorize_request(req, Action::S3Action(S3Action::DeleteObjectAction)).await
}
/// Checks whether the DeletePublicAccessBlock request has accesses to the resources.
+24 -4
View File
@@ -1502,9 +1502,13 @@ impl S3 for FS {
/// Delete multiple objects
#[instrument(level = "debug", skip(self, req))]
async fn delete_objects(&self, req: S3Request<DeleteObjectsInput>) -> S3Result<S3Response<DeleteObjectsOutput>> {
async fn delete_objects(&self, mut req: S3Request<DeleteObjectsInput>) -> S3Result<S3Response<DeleteObjectsOutput>> {
let helper = OperationHelper::new(&req, EventName::ObjectRemovedDelete, "s3:DeleteObjects").suppress_event();
let DeleteObjectsInput { bucket, delete, .. } = req.input;
let (bucket, delete) = {
let bucket = req.input.bucket.clone();
let delete = req.input.delete.clone();
(bucket, delete)
};
if delete.objects.is_empty() || delete.objects.len() > 1000 {
return Err(S3Error::with_message(
@@ -1544,9 +1548,7 @@ impl S3 for FS {
let mut object_to_delete = Vec::new();
let mut object_to_delete_index = HashMap::new();
for (idx, object) in delete.objects.iter().enumerate() {
// TODO: check auth
if let Some(version_id) = object.version_id.clone() {
let _vid = match Uuid::parse_str(&version_id) {
Ok(v) => v,
@@ -1563,6 +1565,24 @@ impl S3 for FS {
};
};
{
let req_info = req.extensions.get_mut::<ReqInfo>().expect("ReqInfo not found");
req_info.bucket = Some(bucket.clone());
req_info.object = Some(object.key.clone());
req_info.version_id = object.version_id.clone();
}
let auth_res = authorize_request(&mut req, Action::S3Action(S3Action::DeleteObjectAction)).await;
if let Err(e) = auth_res {
delete_results[idx].error = Some(Error {
code: Some("AccessDenied".to_string()),
key: Some(object.key.clone()),
message: Some(e.to_string()),
version_id: object.version_id.clone(),
});
continue;
}
let mut object = ObjectToDelete {
object_name: object.key.clone(),
version_id: object.version_id.clone().map(|v| Uuid::parse_str(&v).unwrap()),