diff --git a/rustfs/src/storage/access.rs b/rustfs/src/storage/access.rs index 2a0bd7683..8d674d807 100644 --- a/rustfs/src/storage/access.rs +++ b/rustfs/src/storage/access.rs @@ -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, 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(req: &mut S3Request, action: Action) -> S3Result<()> { let remote_addr = req.extensions.get::().map(|a| a.0); + let req_info = req.extensions.get_mut::().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) -> S3Result<()> { - Ok(()) + async fn delete_objects(&self, req: &mut S3Request) -> S3Result<()> { + let req_info = req.extensions.get_mut::().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. diff --git a/rustfs/src/storage/ecfs.rs b/rustfs/src/storage/ecfs.rs index e7f4bfb63..80808ab30 100644 --- a/rustfs/src/storage/ecfs.rs +++ b/rustfs/src/storage/ecfs.rs @@ -1502,9 +1502,13 @@ impl S3 for FS { /// Delete multiple objects #[instrument(level = "debug", skip(self, req))] - async fn delete_objects(&self, req: S3Request) -> S3Result> { + async fn delete_objects(&self, mut req: S3Request) -> S3Result> { 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::().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()),