From 7ea163fbe112ea91a7af94312e3a60371a88f9fc Mon Sep 17 00:00:00 2001 From: weisd Date: Wed, 26 Mar 2025 14:21:43 +0800 Subject: [PATCH] update s3 api access check support anonymous --- e2e_test/src/reliant/node_interact_test.rs | 2 +- ecstore/src/bucket/metadata_sys.rs | 37 +-- ecstore/src/bucket/policy_sys.rs | 2 +- ecstore/src/bucket/versioning_sys.rs | 2 +- ecstore/src/store.rs | 2 +- policy/src/policy/action.rs | 10 +- rustfs/src/admin/handlers.rs | 16 +- rustfs/src/grpc.rs | 7 +- rustfs/src/storage/access.rs | 265 +++++++++++++-------- rustfs/src/storage/ecfs.rs | 20 +- 10 files changed, 220 insertions(+), 143 deletions(-) diff --git a/e2e_test/src/reliant/node_interact_test.rs b/e2e_test/src/reliant/node_interact_test.rs index 069bd448d..742b925df 100644 --- a/e2e_test/src/reliant/node_interact_test.rs +++ b/e2e_test/src/reliant/node_interact_test.rs @@ -122,7 +122,7 @@ async fn walk_dir() -> Result<(), Box> { println!("{}", resp.error_info.unwrap_or("".to_string())); } let entry = serde_json::from_str::(&resp.meta_cache_entry) - .map_err(|e| common::error::Error::from_string(format!("Unexpected response: {:?}", response))) + .map_err(|_e| common::error::Error::from_string(format!("Unexpected response: {:?}", response))) .unwrap(); out.write_obj(&entry).await.unwrap(); } diff --git a/ecstore/src/bucket/metadata_sys.rs b/ecstore/src/bucket/metadata_sys.rs index 9d18700bc..b3a7be99a 100644 --- a/ecstore/src/bucket/metadata_sys.rs +++ b/ecstore/src/bucket/metadata_sys.rs @@ -42,94 +42,99 @@ pub async fn init_bucket_metadata_sys(api: Arc, buckets: Vec) { } // panic if not init -pub(super) fn get_bucket_metadata_sys() -> Arc> { - GLOBAL_BucketMetadataSys.get().unwrap().clone() +pub(super) fn get_bucket_metadata_sys() -> Result>> { + if let Some(sys) = GLOBAL_BucketMetadataSys.get() { + Ok(sys.clone()) + } else { + Err(Error::msg("GLOBAL_BucketMetadataSys not init")) + } } -pub async fn set_bucket_metadata(bucket: String, bm: BucketMetadata) { - let sys = get_bucket_metadata_sys(); +pub async fn set_bucket_metadata(bucket: String, bm: BucketMetadata) -> Result<()> { + let sys = get_bucket_metadata_sys()?; let lock = sys.write().await; lock.set(bucket, Arc::new(bm)).await; + Ok(()) } pub(crate) async fn get(bucket: &str) -> Result> { - let sys = get_bucket_metadata_sys(); + let sys = get_bucket_metadata_sys()?; let lock = sys.read().await; lock.get(bucket).await } pub async fn update(bucket: &str, config_file: &str, data: Vec) -> Result { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let mut bucket_meta_sys = bucket_meta_sys_lock.write().await; bucket_meta_sys.update(bucket, config_file, data).await } pub async fn delete(bucket: &str, config_file: &str) -> Result { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let mut bucket_meta_sys = bucket_meta_sys_lock.write().await; bucket_meta_sys.delete(bucket, config_file).await } pub async fn get_tagging_config(bucket: &str) -> Result<(Tagging, OffsetDateTime)> { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.get_tagging_config(bucket).await } pub async fn get_lifecycle_config(bucket: &str) -> Result<(BucketLifecycleConfiguration, OffsetDateTime)> { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.get_lifecycle_config(bucket).await } pub async fn get_sse_config(bucket: &str) -> Result<(ServerSideEncryptionConfiguration, OffsetDateTime)> { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.get_sse_config(bucket).await } pub async fn get_object_lock_config(bucket: &str) -> Result<(ObjectLockConfiguration, OffsetDateTime)> { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.get_object_lock_config(bucket).await } pub async fn get_replication_config(bucket: &str) -> Result<(ReplicationConfiguration, OffsetDateTime)> { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.get_replication_config(bucket).await } pub async fn get_notification_config(bucket: &str) -> Result> { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.get_notification_config(bucket).await } pub async fn get_versioning_config(bucket: &str) -> Result<(VersioningConfiguration, OffsetDateTime)> { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.get_versioning_config(bucket).await } pub async fn get_config_from_disk(bucket: &str) -> Result { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.get_config_from_disk(bucket).await } pub async fn created_at(bucket: &str) -> Result { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.read().await; bucket_meta_sys.created_at(bucket).await diff --git a/ecstore/src/bucket/policy_sys.rs b/ecstore/src/bucket/policy_sys.rs index e5682c180..2a505a8bb 100644 --- a/ecstore/src/bucket/policy_sys.rs +++ b/ecstore/src/bucket/policy_sys.rs @@ -19,7 +19,7 @@ impl PolicySys { args.is_owner } pub async fn get(bucket: &str) -> Result { - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.write().await; let (cfg, _) = bucket_meta_sys.get_bucket_policy(bucket).await?; diff --git a/ecstore/src/bucket/versioning_sys.rs b/ecstore/src/bucket/versioning_sys.rs index 64141f5fa..465498592 100644 --- a/ecstore/src/bucket/versioning_sys.rs +++ b/ecstore/src/bucket/versioning_sys.rs @@ -61,7 +61,7 @@ impl BucketVersioningSys { return Ok(VersioningConfiguration::default()); } - let bucket_meta_sys_lock = get_bucket_metadata_sys(); + let bucket_meta_sys_lock = get_bucket_metadata_sys()?; let bucket_meta_sys = bucket_meta_sys_lock.write().await; let (cfg, _) = bucket_meta_sys.get_versioning_config(bucket).await?; diff --git a/ecstore/src/store.rs b/ecstore/src/store.rs index 40e376aeb..84c6da013 100644 --- a/ecstore/src/store.rs +++ b/ecstore/src/store.rs @@ -1323,7 +1323,7 @@ impl StorageAPI for ECStore { meta.save().await.map_err(|e| to_object_err(e, vec![bucket]))?; - set_bucket_metadata(bucket.to_string(), meta).await; + set_bucket_metadata(bucket.to_string(), meta).await?; Ok(()) } diff --git a/policy/src/policy/action.rs b/policy/src/policy/action.rs index 7ce762f95..e152e89b7 100644 --- a/policy/src/policy/action.rs +++ b/policy/src/policy/action.rs @@ -47,7 +47,7 @@ impl PartialEq for ActionSet { } } -#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Debug)] +#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Debug, Copy)] #[serde(try_from = "&str", untagged)] pub enum Action { S3Action(S3Action), @@ -105,7 +105,7 @@ impl TryFrom<&str> for Action { } } -#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, EnumString, IntoStaticStr, Debug)] +#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, EnumString, IntoStaticStr, Debug, Copy)] #[cfg_attr(test, derive(Default))] #[serde(try_from = "&str", into = "&str")] pub enum S3Action { @@ -232,7 +232,7 @@ pub enum S3Action { PutObjectFanOutAction, } -#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, EnumString, IntoStaticStr, Debug)] +#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, EnumString, IntoStaticStr, Debug, Copy)] #[serde(try_from = "&str", into = "&str")] pub enum AdminAction { #[strum(serialize = "admin:*")] @@ -263,11 +263,11 @@ pub enum AdminAction { CreateServiceAccountAdminAction, } -#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, EnumString, IntoStaticStr, Debug)] +#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, EnumString, IntoStaticStr, Debug, Copy)] #[serde(try_from = "&str", into = "&str")] pub enum StsAction {} -#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, EnumString, IntoStaticStr, Debug)] +#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, EnumString, IntoStaticStr, Debug, Copy)] #[serde(try_from = "&str", into = "&str")] pub enum KmsAction { #[strum(serialize = "kms:*")] diff --git a/rustfs/src/admin/handlers.rs b/rustfs/src/admin/handlers.rs index e5de35749..3a53de3c9 100644 --- a/rustfs/src/admin/handlers.rs +++ b/rustfs/src/admin/handlers.rs @@ -1,12 +1,12 @@ use super::router::Operation; use crate::storage::error::to_s3_error; +use ::policy::policy::action::{Action, S3Action}; +use ::policy::policy::resource::Resource; +use ::policy::policy::statement::BPStatement; +use ::policy::policy::{ActionSet, BucketPolicy, Effect, ResourceSet}; use bytes::Bytes; use common::error::Error as ec_Error; use ecstore::admin_server_info::get_server_info; -use ecstore::bucket::policy::action::{Action, ActionSet}; -use ecstore::bucket::policy::bucket_policy::{BPStatement, BucketPolicy}; -use ecstore::bucket::policy::effect::Effect; -use ecstore::bucket::policy::resource::{Resource, ResourceSet}; use ecstore::global::GLOBAL_ALlHealState; use ecstore::heal::data_usage::load_data_usage_from_backend; use ecstore::heal::heal_commands::HealOpts; @@ -74,16 +74,16 @@ impl Operation for AccountInfoHandler { // test policy let mut s3_all_act = HashSet::with_capacity(1); - s3_all_act.insert(Action::AllActions); + s3_all_act.insert(Action::S3Action(S3Action::AllActions)); let mut all_res = HashSet::with_capacity(1); - all_res.insert(Resource::new("*")); + all_res.insert(Resource::S3("*".to_string())); let bucket_policy = BucketPolicy { - id: "".to_owned(), + id: "".into(), version: "2012-10-17".to_owned(), statements: vec![BPStatement { - sid: "".to_owned(), + sid: "".into(), effect: Effect::Allow, actions: ActionSet(s3_all_act.clone()), resources: ResourceSet(all_res), diff --git a/rustfs/src/grpc.rs b/rustfs/src/grpc.rs index 5c8e1012f..c17879159 100644 --- a/rustfs/src/grpc.rs +++ b/rustfs/src/grpc.rs @@ -2078,7 +2078,12 @@ impl Node for NodeService { match load_bucket_metadata(store, &bucket).await { Ok(meta) => { - metadata_sys::set_bucket_metadata(bucket, meta).await; + if let Err(err) = metadata_sys::set_bucket_metadata(bucket, meta).await { + return Ok(tonic::Response::new(LoadBucketMetadataResponse { + success: false, + error_info: Some(err.to_string()), + })); + }; Ok(tonic::Response::new(LoadBucketMetadataResponse { success: true, error_info: None, diff --git a/rustfs/src/storage/access.rs b/rustfs/src/storage/access.rs index 5d3300dd1..0e1562cad 100644 --- a/rustfs/src/storage/access.rs +++ b/rustfs/src/storage/access.rs @@ -1,9 +1,10 @@ use super::ecfs::FS; use crate::auth::{check_key_valid, get_condition_values}; +use ecstore::bucket::policy_sys::PolicySys; use iam::error::Error as IamError; use policy::auth; use policy::policy::action::{Action, S3Action}; -use policy::policy::Args; +use policy::policy::{Args, BucketPolicyArgs}; use s3s::access::{S3Access, S3AccessContext}; use s3s::{dto::*, s3_error, S3Error, S3ErrorCode, S3Request, S3Result}; use std::collections::HashMap; @@ -11,45 +12,117 @@ use std::collections::HashMap; #[allow(dead_code)] #[derive(Default, Clone)] pub(crate) struct ReqInfo { - pub cred: auth::Credentials, + pub cred: Option, pub is_owner: bool, pub bucket: Option, pub object: Option, pub version_id: Option, } -pub async fn authorize_request(req: &mut S3Request, actions: Vec) -> S3Result<()> { - let Ok(iam_store) = iam::get() else { - return Err(S3Error::with_message( - S3ErrorCode::InternalError, - format!("check_key_valid {:?}", IamError::IamSysNotInitialized), - )); - }; - +pub async fn authorize_request(req: &mut S3Request, action: Action) -> S3Result<()> { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); - let default_claims = HashMap::new(); - let claims = req_info.cred.claims.as_ref().unwrap_or(&default_claims); - let conditions = get_condition_values(&req.headers, &req_info.cred); - - for action in actions { - let args = &Args { - account: &req_info.cred.access_key, - groups: &req_info.cred.groups, - action, - bucket: req_info.bucket.as_deref().unwrap_or(""), - conditions: &conditions, - is_owner: req_info.is_owner, - object: req_info.object.as_deref().unwrap_or(""), - claims, - deny_only: false, + if let Some(cred) = &req_info.cred { + let Ok(iam_store) = iam::get() else { + return Err(S3Error::with_message( + S3ErrorCode::InternalError, + format!("authorize_request {:?}", IamError::IamSysNotInitialized), + )); }; - if !iam_store.is_allowed(args).await { - return Err(s3_error!(AccessDenied, "Access Denied")); + + let default_claims = HashMap::new(); + let claims = cred.claims.as_ref().unwrap_or(&default_claims); + let conditions = get_condition_values(&req.headers, cred); + + if action != Action::S3Action(S3Action::DeleteObjectAction) + && req_info.version_id.is_some() + && iam_store + .is_allowed(&Args { + account: &cred.access_key, + groups: &cred.groups, + action: Action::S3Action(S3Action::DeleteObjectVersionAction), + bucket: req_info.bucket.as_deref().unwrap_or(""), + conditions: &conditions, + is_owner: req_info.is_owner, + object: req_info.object.as_deref().unwrap_or(""), + claims, + deny_only: false, + }) + .await + { + return Ok(()); + } + + if iam_store + .is_allowed(&Args { + account: &cred.access_key, + groups: &cred.groups, + action, + bucket: req_info.bucket.as_deref().unwrap_or(""), + conditions: &conditions, + is_owner: req_info.is_owner, + object: req_info.object.as_deref().unwrap_or(""), + claims, + deny_only: false, + }) + .await + { + return Ok(()); + } + + if action == Action::S3Action(S3Action::ListBucketVersionsAction) + && iam_store + .is_allowed(&Args { + account: &cred.access_key, + groups: &cred.groups, + action: Action::S3Action(S3Action::ListBucketAction), + bucket: req_info.bucket.as_deref().unwrap_or(""), + conditions: &conditions, + is_owner: req_info.is_owner, + object: req_info.object.as_deref().unwrap_or(""), + claims, + deny_only: false, + }) + .await + { + return Ok(()); + } + } else { + let conditions = get_condition_values(&req.headers, &auth::Credentials::default()); + + if action != Action::S3Action(S3Action::ListAllMyBucketsAction) { + if PolicySys::is_allowed(&BucketPolicyArgs { + bucket: req_info.bucket.as_deref().unwrap_or(""), + action, + is_owner: false, + account: "", + groups: &None, + conditions: &conditions, + object: req_info.object.as_deref().unwrap_or(""), + }) + .await + { + return Ok(()); + } + + if action == Action::S3Action(S3Action::ListBucketVersionsAction) + && PolicySys::is_allowed(&BucketPolicyArgs { + bucket: req_info.bucket.as_deref().unwrap_or(""), + action: Action::S3Action(S3Action::ListBucketAction), + is_owner: false, + account: "", + groups: &None, + conditions: &conditions, + object: "", + }) + .await + { + return Ok(()); + } } } - Ok(()) + Err(s3_error!(AccessDenied, "Access Denied")) } #[async_trait::async_trait] @@ -81,12 +154,13 @@ impl S3Access for FS { // // cx.extensions_mut(), // ); - let Some(input_cred) = cx.credentials() else { - return Err(s3_error!(UnauthorizedAccess, "Signature is required")); + let (cred, is_owner) = if let Some(input_cred) = cx.credentials() { + let (cred, is_owner) = check_key_valid(cx.headers(), &input_cred.access_key).await?; + (Some(cred), is_owner) + } else { + (None, false) }; - let (cred, is_owner) = check_key_valid(cx.headers(), &input_cred.access_key).await?; - let req_info = ReqInfo { cred, is_owner, @@ -108,17 +182,11 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::CreateBucketAction)]).await?; + authorize_request(req, Action::S3Action(S3Action::CreateBucketAction)).await?; if req.input.object_lock_enabled_for_bucket.is_some_and(|v| v) { - authorize_request( - req, - vec![ - Action::S3Action(S3Action::PutBucketObjectLockConfigurationAction), - Action::S3Action(S3Action::PutBucketVersioningAction), - ], - ) - .await?; + authorize_request(req, Action::S3Action(S3Action::PutBucketObjectLockConfigurationAction)).await?; + authorize_request(req, Action::S3Action(S3Action::PutBucketVersioningAction)).await?; } Ok(()) @@ -156,7 +224,7 @@ impl S3Access for FS { req_info.object = Some(src_key); req_info.version_id = version_id; - authorize_request(req, vec![Action::S3Action(S3Action::GetObjectAction)]).await?; + authorize_request(req, Action::S3Action(S3Action::GetObjectAction)).await?; } let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); @@ -165,7 +233,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::PutObjectAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutObjectAction)).await } /// Checks whether the CreateMultipartUpload request has accesses to the resources. @@ -182,10 +250,10 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::DeleteBucketAction)]).await?; + authorize_request(req, Action::S3Action(S3Action::DeleteBucketAction)).await?; if req.input.force_delete.is_some_and(|v| v) { - authorize_request(req, vec![Action::S3Action(S3Action::ForceDeleteBucketAction)]).await?; + authorize_request(req, Action::S3Action(S3Action::ForceDeleteBucketAction)).await?; } Ok(()) } @@ -207,7 +275,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketCorsAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketCorsAction)).await } /// Checks whether the DeleteBucketEncryption request has accesses to the resources. @@ -217,7 +285,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketEncryptionAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketEncryptionAction)).await } /// Checks whether the DeleteBucketIntelligentTieringConfiguration request has accesses to the resources. @@ -247,7 +315,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketLifecycleAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketLifecycleAction)).await } /// Checks whether the DeleteBucketMetricsConfiguration request has accesses to the resources. @@ -274,7 +342,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::DeleteBucketPolicyAction)]).await + authorize_request(req, Action::S3Action(S3Action::DeleteBucketPolicyAction)).await } /// Checks whether the DeleteBucketReplication request has accesses to the resources. @@ -284,7 +352,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutReplicationConfigurationAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutReplicationConfigurationAction)).await } /// Checks whether the DeleteBucketTagging request has accesses to the resources. @@ -294,7 +362,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketTaggingAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketTaggingAction)).await } /// Checks whether the DeleteBucketWebsite request has accesses to the resources. @@ -313,7 +381,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::DeleteObjectAction)]).await + authorize_request(req, Action::S3Action(S3Action::DeleteObjectAction)).await } /// Checks whether the DeleteObjectTagging request has accesses to the resources. @@ -325,7 +393,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::DeleteObjectTaggingAction)]).await + authorize_request(req, Action::S3Action(S3Action::DeleteObjectTaggingAction)).await } /// Checks whether the DeleteObjects request has accesses to the resources. @@ -359,7 +427,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketPolicyAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketPolicyAction)).await } /// Checks whether the GetBucketAnalyticsConfiguration request has accesses to the resources. @@ -379,7 +447,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketCorsAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketCorsAction)).await } /// Checks whether the GetBucketEncryption request has accesses to the resources. @@ -389,7 +457,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketEncryptionAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketEncryptionAction)).await } /// Checks whether the GetBucketIntelligentTieringConfiguration request has accesses to the resources. @@ -422,7 +490,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketLifecycleAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketLifecycleAction)).await } /// Checks whether the GetBucketLocation request has accesses to the resources. @@ -432,7 +500,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketLocationAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketLocationAction)).await } /// Checks whether the GetBucketLogging request has accesses to the resources. @@ -459,7 +527,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketNotificationAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketNotificationAction)).await } /// Checks whether the GetBucketOwnershipControls request has accesses to the resources. @@ -476,7 +544,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketPolicyAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketPolicyAction)).await } /// Checks whether the GetBucketPolicyStatus request has accesses to the resources. @@ -486,7 +554,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketPolicyStatusAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketPolicyStatusAction)).await } /// Checks whether the GetBucketReplication request has accesses to the resources. @@ -496,7 +564,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetReplicationConfigurationAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetReplicationConfigurationAction)).await } /// Checks whether the GetBucketRequestPayment request has accesses to the resources. @@ -513,7 +581,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketTaggingAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketTaggingAction)).await } /// Checks whether the GetBucketVersioning request has accesses to the resources. @@ -523,7 +591,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketVersioningAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketVersioningAction)).await } /// Checks whether the GetBucketWebsite request has accesses to the resources. @@ -542,7 +610,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::GetObjectAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetObjectAction)).await } /// Checks whether the GetObjectAcl request has accesses to the resources. @@ -554,7 +622,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketPolicyAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketPolicyAction)).await } /// Checks whether the GetObjectAttributes request has accesses to the resources. @@ -566,16 +634,15 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - let mut actions = Vec::new(); if req.input.version_id.is_some() { - actions.push(Action::S3Action(S3Action::GetObjectVersionAttributesAction)); - actions.push(Action::S3Action(S3Action::GetObjectVersionAction)); + authorize_request(req, Action::S3Action(S3Action::GetObjectVersionAttributesAction)).await?; + authorize_request(req, Action::S3Action(S3Action::GetObjectVersionAction)).await?; } else { - actions.push(Action::S3Action(S3Action::GetObjectAttributesAction)); - actions.push(Action::S3Action(S3Action::GetObjectAction)); + authorize_request(req, Action::S3Action(S3Action::GetObjectAttributesAction)).await?; + authorize_request(req, Action::S3Action(S3Action::GetObjectAction)).await?; } - authorize_request(req, actions).await + Ok(()) } /// Checks whether the GetObjectLegalHold request has accesses to the resources. @@ -587,7 +654,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::GetObjectLegalHoldAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetObjectLegalHoldAction)).await } /// Checks whether the GetObjectLockConfiguration request has accesses to the resources. @@ -597,7 +664,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetBucketObjectLockConfigurationAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetBucketObjectLockConfigurationAction)).await } /// Checks whether the GetObjectRetention request has accesses to the resources. @@ -609,7 +676,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::GetObjectRetentionAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetObjectRetentionAction)).await } /// Checks whether the GetObjectTagging request has accesses to the resources. @@ -621,7 +688,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::GetObjectTaggingAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetObjectTaggingAction)).await } /// Checks whether the GetObjectTorrent request has accesses to the resources. @@ -645,7 +712,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::ListBucketAction)]).await + authorize_request(req, Action::S3Action(S3Action::ListBucketAction)).await } /// Checks whether the HeadObject request has accesses to the resources. @@ -657,7 +724,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::GetObjectAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetObjectAction)).await } /// Checks whether the ListBucketAnalyticsConfigurations request has accesses to the resources. @@ -715,7 +782,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::ListBucketMultipartUploadsAction)]).await + authorize_request(req, Action::S3Action(S3Action::ListBucketMultipartUploadsAction)).await } /// Checks whether the ListObjectVersions request has accesses to the resources. @@ -732,7 +799,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::ListBucketAction)]).await + authorize_request(req, Action::S3Action(S3Action::ListBucketAction)).await } /// Checks whether the ListObjectsV2 request has accesses to the resources. @@ -742,7 +809,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::ListBucketAction)]).await + authorize_request(req, Action::S3Action(S3Action::ListBucketAction)).await } /// Checks whether the ListParts request has accesses to the resources. @@ -769,7 +836,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketPolicyAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketPolicyAction)).await } /// Checks whether the PutBucketAnalyticsConfiguration request has accesses to the resources. @@ -789,7 +856,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketCorsAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketCorsAction)).await } /// Checks whether the PutBucketEncryption request has accesses to the resources. @@ -799,7 +866,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketEncryptionAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketEncryptionAction)).await } /// Checks whether the PutBucketIntelligentTieringConfiguration request has accesses to the resources. @@ -832,7 +899,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketLifecycleAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketLifecycleAction)).await } /// Checks whether the PutBucketLogging request has accesses to the resources. @@ -859,7 +926,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketNotificationAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketNotificationAction)).await } /// Checks whether the PutBucketOwnershipControls request has accesses to the resources. @@ -876,7 +943,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketPolicyAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketPolicyAction)).await } /// Checks whether the PutBucketReplication request has accesses to the resources. @@ -886,7 +953,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutReplicationConfigurationAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutReplicationConfigurationAction)).await } /// Checks whether the PutBucketRequestPayment request has accesses to the resources. @@ -903,7 +970,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketTaggingAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketTaggingAction)).await } /// Checks whether the PutBucketVersioning request has accesses to the resources. @@ -913,7 +980,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketVersioningAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketVersioningAction)).await } /// Checks whether the PutBucketWebsite request has accesses to the resources. @@ -932,7 +999,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::PutObjectAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutObjectAction)).await } /// Checks whether the PutObjectAcl request has accesses to the resources. @@ -944,7 +1011,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketPolicyAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketPolicyAction)).await } /// Checks whether the PutObjectLegalHold request has accesses to the resources. @@ -956,7 +1023,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::PutObjectLegalHoldAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutObjectLegalHoldAction)).await } /// Checks whether the PutObjectLockConfiguration request has accesses to the resources. @@ -966,7 +1033,7 @@ impl S3Access for FS { let req_info = req.extensions.get_mut::().expect("ReqInfo not found"); req_info.bucket = Some(req.input.bucket.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutBucketObjectLockConfigurationAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutBucketObjectLockConfigurationAction)).await } /// Checks whether the PutObjectRetention request has accesses to the resources. @@ -978,7 +1045,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::PutObjectRetentionAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutObjectRetentionAction)).await } /// Checks whether the PutObjectTagging request has accesses to the resources. @@ -990,7 +1057,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::PutObjectTaggingAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutObjectTaggingAction)).await } /// Checks whether the PutPublicAccessBlock request has accesses to the resources. @@ -1009,7 +1076,7 @@ impl S3Access for FS { req_info.object = Some(req.input.key.clone()); req_info.version_id = req.input.version_id.clone(); - authorize_request(req, vec![Action::S3Action(S3Action::RestoreObjectAction)]).await + authorize_request(req, Action::S3Action(S3Action::RestoreObjectAction)).await } /// Checks whether the SelectObjectContent request has accesses to the resources. @@ -1020,7 +1087,7 @@ impl S3Access for FS { req_info.bucket = Some(req.input.bucket.clone()); req_info.object = Some(req.input.key.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::GetObjectAction)]).await + authorize_request(req, Action::S3Action(S3Action::GetObjectAction)).await } /// Checks whether the UploadPart request has accesses to the resources. @@ -1031,7 +1098,7 @@ impl S3Access for FS { req_info.bucket = Some(req.input.bucket.clone()); req_info.object = Some(req.input.key.clone()); - authorize_request(req, vec![Action::S3Action(S3Action::PutObjectAction)]).await + authorize_request(req, Action::S3Action(S3Action::PutObjectAction)).await } /// Checks whether the UploadPartCopy request has accesses to the resources. diff --git a/rustfs/src/storage/ecfs.rs b/rustfs/src/storage/ecfs.rs index 2504fd477..8687ef29c 100644 --- a/rustfs/src/storage/ecfs.rs +++ b/rustfs/src/storage/ecfs.rs @@ -15,7 +15,6 @@ use ecstore::bucket::metadata::BUCKET_TAGGING_CONFIG; use ecstore::bucket::metadata::BUCKET_VERSIONING_CONFIG; use ecstore::bucket::metadata::OBJECT_LOCK_CONFIG; use ecstore::bucket::metadata_sys; -use ecstore::bucket::policy::bucket_policy::BucketPolicy; use ecstore::bucket::policy_sys::PolicySys; use ecstore::bucket::tagging::decode_tags; use ecstore::bucket::tagging::encode_tags; @@ -43,6 +42,8 @@ use lazy_static::lazy_static; use log::warn; use policy::policy::action::Action; use policy::policy::action::S3Action; +use policy::policy::BucketPolicy; +use policy::policy::Validator; use s3s::dto::*; use s3s::s3_error; use s3s::S3Error; @@ -559,7 +560,7 @@ impl S3 for FS { let mut req = req; - if authorize_request(&mut req, vec![Action::S3Action(S3Action::ListAllMyBucketsAction)]) + if authorize_request(&mut req, Action::S3Action(S3Action::ListAllMyBucketsAction)) .await .is_err() { @@ -569,10 +570,10 @@ impl S3 for FS { req_info.bucket = Some(info.name.clone()); futures::executor::block_on(async { - authorize_request(&mut req, vec![Action::S3Action(S3Action::ListBucketAction)]) + authorize_request(&mut req, Action::S3Action(S3Action::ListBucketAction)) .await .is_ok() - || authorize_request(&mut req, vec![Action::S3Action(S3Action::GetBucketLocationAction)]) + || authorize_request(&mut req, Action::S3Action(S3Action::GetBucketLocationAction)) .await .is_ok() }) @@ -1265,18 +1266,17 @@ impl S3 for FS { // warn!("input policy {}", &policy); - let cfg = BucketPolicy::unmarshal(policy.as_bytes()).map_err(to_s3_error)?; + let cfg: BucketPolicy = + serde_json::from_str(&policy).map_err(|e| s3_error!(InvalidArgument, "parse policy faild {:?}", e))?; - // warn!("parse policy {:?}", &cfg); - - if let Err(err) = cfg.validate(&bucket) { + if let Err(err) = cfg.is_valid() { warn!("put_bucket_policy err input {:?}, {:?}", &policy, err); return Err(s3_error!(InvalidPolicyDocument)); } - let data = cfg.marshal_msg().map_err(to_s3_error)?; + let data = serde_json::to_vec(&cfg).map_err(|e| s3_error!(InternalError, "parse policy faild {:?}", e))?; - metadata_sys::update(&bucket, BUCKET_POLICY_CONFIG, data.into()) + metadata_sys::update(&bucket, BUCKET_POLICY_CONFIG, data) .await .map_err(to_s3_error)?;