ecstore update bucket policy

This commit is contained in:
weisd
2025-03-26 11:39:14 +08:00
parent d91429c5cf
commit ab31be8d46
17 changed files with 8 additions and 2318 deletions

1
Cargo.lock generated
View File

@@ -1920,6 +1920,7 @@ dependencies = [
"path-absolutize",
"path-clean",
"pin-project-lite",
"policy",
"protos",
"rand 0.8.5",
"reed-solomon-erasure",

View File

@@ -16,6 +16,7 @@ backon.workspace = true
blake2 = "0.10.6"
bytes.workspace = true
common.workspace = true
policy.workspace = true
chrono.workspace = true
glob = "0.3.2"
thiserror.workspace = true

View File

@@ -1,9 +1,9 @@
use super::policy::bucket_policy::BucketPolicy;
use super::{quota::BucketQuota, target::BucketTargets};
use super::object_lock::ObjectLockApi;
use super::versioning::VersioningApi;
use byteorder::{BigEndian, ByteOrder, LittleEndian};
use policy::policy::BucketPolicy;
use rmp_serde::Serializer as rmpSerializer;
use s3s::dto::{
BucketLifecycleConfiguration, NotificationConfiguration, ObjectLockConfiguration, ReplicationConfiguration,

View File

@@ -13,6 +13,7 @@ use crate::store::ECStore;
use crate::utils::xml::deserialize;
use common::error::{Error, Result};
use futures::future::join_all;
use policy::policy::BucketPolicy;
use s3s::dto::{
BucketLifecycleConfiguration, NotificationConfiguration, ObjectLockConfiguration, ReplicationConfiguration,
ServerSideEncryptionConfiguration, Tagging, VersioningConfiguration,
@@ -22,7 +23,6 @@ use tokio::sync::RwLock;
use tracing::{error, warn};
use super::metadata::{load_bucket_metadata, BucketMetadata};
use super::policy::bucket_policy::BucketPolicy;
use super::quota::BucketQuota;
use super::target::BucketTargets;

View File

@@ -2,7 +2,6 @@ pub mod error;
pub mod metadata;
pub mod metadata_sys;
pub mod object_lock;
pub mod policy;
pub mod policy_sys;
mod quota;
pub mod tagging;

View File

@@ -1,605 +0,0 @@
use crate::{bucket::policy::condition::keyname::ALL_SUPPORT_KEYS, utils};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use std::{
collections::{HashMap, HashSet},
str::FromStr,
vec,
};
use super::condition::{
key::{Key, KeySet},
keyname::{KeyName, COMMOM_KEYS},
};
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)]
pub struct ActionSet(pub HashSet<Action>);
impl ActionSet {
pub fn is_match(&self, act: &Action) -> bool {
for item in self.0.iter() {
if item.is_match(act) {
return true;
}
if item == &Action::GetObjectVersion && act == &Action::GetObjectVersion {
return true;
}
}
false
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl AsRef<HashSet<Action>> for ActionSet {
fn as_ref(&self) -> &HashSet<Action> {
&self.0
}
}
// TODO:: 使用字符串
// 定义Action枚举类型
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Default, Hash)]
pub enum Action {
#[serde(rename = "s3:AbortMultipartUpload")]
AbortMultipartUpload,
#[serde(rename = "s3:CreateBucket")]
CreateBucket,
#[serde(rename = "s3:DeleteBucket")]
DeleteBucket,
#[serde(rename = "s3:ForceDeleteBucket")]
ForceDeleteBucket,
#[serde(rename = "s3:DeleteBucketPolicy")]
DeleteBucketPolicy,
#[serde(rename = "s3:DeleteBucketCors")]
DeleteBucketCors,
#[serde(rename = "s3:DeleteObject")]
DeleteObject,
#[serde(rename = "s3:GetBucketLocation")]
GetBucketLocation,
#[serde(rename = "s3:GetBucketNotification")]
GetBucketNotification,
#[serde(rename = "s3:GetBucketPolicy")]
GetBucketPolicy,
#[serde(rename = "s3:GetBucketCors")]
GetBucketCors,
#[serde(rename = "s3:GetObject")]
GetObject,
#[serde(rename = "s3:GetObjectAttributes")]
GetObjectAttributes,
#[serde(rename = "s3:HeadBucket")]
HeadBucket,
#[serde(rename = "s3:ListAllMyBuckets")]
ListAllMyBuckets,
#[serde(rename = "s3:ListBucket")]
ListBucket,
#[serde(rename = "s3:GetBucketPolicyStatus")]
GetBucketPolicyStatus,
#[serde(rename = "s3:ListBucketVersions")]
ListBucketVersions,
#[serde(rename = "s3:ListBucketMultipartUploads")]
ListBucketMultipartUploads,
#[serde(rename = "s3:ListenNotification")]
ListenNotification,
#[serde(rename = "s3:ListenBucketNotification")]
ListenBucketNotification,
#[serde(rename = "s3:ListMultipartUploadParts")]
ListMultipartUploadParts,
#[serde(rename = "s3:PutLifecycleConfiguration")]
PutLifecycleConfiguration,
#[serde(rename = "s3:GetLifecycleConfiguration")]
GetLifecycleConfiguration,
#[serde(rename = "s3:PutBucketNotification")]
PutBucketNotification,
#[serde(rename = "s3:PutBucketPolicy")]
PutBucketPolicy,
#[serde(rename = "s3:PutBucketCors")]
PutBucketCors,
#[serde(rename = "s3:PutObject")]
PutObject,
#[serde(rename = "s3:DeleteObjectVersion")]
DeleteObjectVersion,
#[serde(rename = "s3:DeleteObjectVersionTagging")]
DeleteObjectVersionTagging,
#[serde(rename = "s3:GetObjectVersion")]
GetObjectVersion,
#[serde(rename = "s3:GetObjectVersionAttributes")]
GetObjectVersionAttributes,
#[serde(rename = "s3:GetObjectVersionTagging")]
GetObjectVersionTagging,
#[serde(rename = "s3:PutObjectVersionTagging")]
PutObjectVersionTagging,
#[serde(rename = "s3:BypassGovernanceRetention")]
BypassGovernanceRetention,
#[serde(rename = "s3:PutObjectRetention")]
PutObjectRetention,
#[serde(rename = "s3:GetObjectRetention")]
GetObjectRetention,
#[serde(rename = "s3:GetObjectLegalHold")]
GetObjectLegalHold,
#[serde(rename = "s3:PutObjectLegalHold")]
PutObjectLegalHold,
#[serde(rename = "s3:GetBucketObjectLockConfiguration")]
GetBucketObjectLockConfiguration,
#[serde(rename = "s3:PutBucketObjectLockConfiguration")]
PutBucketObjectLockConfiguration,
#[serde(rename = "s3:GetBucketTagging")]
GetBucketTagging,
#[serde(rename = "s3:PutBucketTagging")]
PutBucketTagging,
#[serde(rename = "s3:GetObjectTagging")]
GetObjectTagging,
#[serde(rename = "s3:PutObjectTagging")]
PutObjectTagging,
#[serde(rename = "s3:DeleteObjectTagging")]
DeleteObjectTagging,
#[serde(rename = "s3:PutBucketEncryption")]
PutBucketEncryption,
#[serde(rename = "s3:GetBucketEncryption")]
GetBucketEncryption,
#[serde(rename = "s3:PutBucketVersioning")]
PutBucketVersioning,
#[serde(rename = "s3:GetBucketVersioning")]
GetBucketVersioning,
#[serde(rename = "s3:PutReplicationConfiguration")]
PutReplicationConfiguration,
#[serde(rename = "s3:GetReplicationConfiguration")]
GetReplicationConfiguration,
#[serde(rename = "s3:ReplicateObject")]
ReplicateObject,
#[serde(rename = "s3:ReplicateDelete")]
ReplicateDelete,
#[serde(rename = "s3:ReplicateTags")]
ReplicateTags,
#[serde(rename = "s3:GetObjectVersionForReplication")]
GetObjectVersionForReplication,
#[serde(rename = "s3:RestoreObject")]
RestoreObject,
#[serde(rename = "s3:ResetBucketReplicationState")]
ResetBucketReplicationState,
#[serde(rename = "s3:PutObjectFanOut")]
PutObjectFanOut,
#[default]
#[serde(rename = "s3:*")]
AllActions,
}
lazy_static! {
#[derive(Debug)]
static ref SUPPORT_OBJCET_ACTIONS: HashSet<Action> = {
let mut h = HashSet::new();
h.insert(Action::AllActions);
h.insert(Action::AbortMultipartUpload);
h.insert(Action::DeleteObject);
h.insert(Action::GetObject);
h.insert(Action::ListMultipartUploadParts);
h.insert(Action::PutObject);
h.insert(Action::BypassGovernanceRetention);
h.insert(Action::PutObjectRetention);
h.insert(Action::GetObjectRetention);
h.insert(Action::PutObjectLegalHold);
h.insert(Action::GetObjectLegalHold);
h.insert(Action::GetObjectTagging);
h.insert(Action::PutObjectTagging);
h.insert(Action::DeleteObjectTagging);
h.insert(Action::GetObjectVersion);
h.insert(Action::GetObjectVersionTagging);
h.insert(Action::DeleteObjectVersion);
h.insert(Action::DeleteObjectVersionTagging);
h.insert(Action::PutObjectVersionTagging);
h.insert(Action::ReplicateObject);
h.insert(Action::ReplicateDelete);
h.insert(Action::ReplicateTags);
h.insert(Action::GetObjectVersionForReplication);
h.insert(Action::RestoreObject);
h.insert(Action::ResetBucketReplicationState);
h.insert(Action::PutObjectFanOut);
h.insert(Action::GetObjectAttributes);
h.insert(Action::GetObjectVersionAttributes);
h
};
}
impl Action {
pub fn is_object_action(&self) -> bool {
for act in SUPPORT_OBJCET_ACTIONS.iter() {
if self.is_match(act) {
return true;
}
}
false
}
pub fn is_match(&self, a: &Action) -> bool {
utils::wildcard::match_pattern(self.clone().as_str(), a.clone().as_str())
}
fn as_str(&self) -> &'static str {
match self {
Action::AbortMultipartUpload => "s3:AbortMultipartUpload",
Action::CreateBucket => "s3:CreateBucket",
Action::DeleteBucket => "s3:DeleteBucket",
Action::ForceDeleteBucket => "s3:ForceDeleteBucket",
Action::DeleteBucketPolicy => "s3:DeleteBucketPolicy",
Action::DeleteBucketCors => "s3:DeleteBucketCors",
Action::DeleteObject => "s3:DeleteObject",
Action::GetBucketLocation => "s3:GetBucketLocation",
Action::GetBucketNotification => "s3:GetBucketNotification",
Action::GetBucketPolicy => "s3:GetBucketPolicy",
Action::GetBucketCors => "s3:GetBucketCors",
Action::GetObject => "s3:GetObject",
Action::GetObjectAttributes => "s3:GetObjectAttributes",
Action::HeadBucket => "s3:HeadBucket",
Action::ListAllMyBuckets => "s3:ListAllMyBuckets",
Action::ListBucket => "s3:ListBucket",
Action::GetBucketPolicyStatus => "s3:GetBucketPolicyStatus",
Action::ListBucketVersions => "s3:ListBucketVersions",
Action::ListBucketMultipartUploads => "s3:ListBucketMultipartUploads",
Action::ListenNotification => "s3:ListenNotification",
Action::ListenBucketNotification => "s3:ListenBucketNotification",
Action::ListMultipartUploadParts => "s3:ListMultipartUploadParts",
Action::PutLifecycleConfiguration => "s3:PutLifecycleConfiguration",
Action::GetLifecycleConfiguration => "s3:GetLifecycleConfiguration",
Action::PutBucketNotification => "s3:PutBucketNotification",
Action::PutBucketPolicy => "s3:PutBucketPolicy",
Action::PutBucketCors => "s3:PutBucketCors",
Action::PutObject => "s3:PutObject",
Action::DeleteObjectVersion => "s3:DeleteObjectVersion",
Action::DeleteObjectVersionTagging => "s3:DeleteObjectVersionTagging",
Action::GetObjectVersion => "s3:GetObjectVersion",
Action::GetObjectVersionAttributes => "s3:GetObjectVersionAttributes",
Action::GetObjectVersionTagging => "s3:GetObjectVersionTagging",
Action::PutObjectVersionTagging => "s3:PutObjectVersionTagging",
Action::BypassGovernanceRetention => "s3:BypassGovernanceRetention",
Action::PutObjectRetention => "s3:PutObjectRetention",
Action::GetObjectRetention => "s3:GetObjectRetention",
Action::GetObjectLegalHold => "s3:GetObjectLegalHold",
Action::PutObjectLegalHold => "s3:PutObjectLegalHold",
Action::GetBucketObjectLockConfiguration => "s3:GetBucketObjectLockConfiguration",
Action::PutBucketObjectLockConfiguration => "s3:PutBucketObjectLockConfiguration",
Action::GetBucketTagging => "s3:GetBucketTagging",
Action::PutBucketTagging => "s3:PutBucketTagging",
Action::GetObjectTagging => "s3:GetObjectTagging",
Action::PutObjectTagging => "s3:PutObjectTagging",
Action::DeleteObjectTagging => "s3:DeleteObjectTagging",
Action::PutBucketEncryption => "s3:PutEncryptionConfiguration",
Action::GetBucketEncryption => "s3:GetEncryptionConfiguration",
Action::PutBucketVersioning => "s3:PutBucketVersioning",
Action::GetBucketVersioning => "s3:GetBucketVersioning",
Action::PutReplicationConfiguration => "s3:GetReplicationConfiguration",
Action::GetReplicationConfiguration => "s3:PutReplicationConfiguration",
Action::ReplicateObject => "s3:ReplicateObject",
Action::ReplicateDelete => "s3:ReplicateDelete",
Action::ReplicateTags => "s3:ReplicateTags",
Action::GetObjectVersionForReplication => "s3:GetObjectVersionForReplication",
Action::RestoreObject => "s3:RestoreObject",
Action::ResetBucketReplicationState => "s3:ResetBucketReplicationState",
Action::PutObjectFanOut => "s3:PutObjectFanOut",
Action::AllActions => "s3:*",
}
}
// pub fn from_str(s: &str) -> Option<Self> {
// match s {
// "s3:AbortMultipartUpload" => Some(Action::AbortMultipartUpload),
// "s3:CreateBucket" => Some(Action::CreateBucket),
// "s3:DeleteBucket" => Some(Action::DeleteBucket),
// "s3:ForceDeleteBucket" => Some(Action::ForceDeleteBucket),
// "s3:DeleteBucketPolicy" => Some(Action::DeleteBucketPolicy),
// "s3:DeleteBucketCors" => Some(Action::DeleteBucketCors),
// "s3:DeleteObject" => Some(Action::DeleteObject),
// "s3:GetBucketLocation" => Some(Action::GetBucketLocation),
// "s3:GetBucketNotification" => Some(Action::GetBucketNotification),
// "s3:GetBucketPolicy" => Some(Action::GetBucketPolicy),
// "s3:GetBucketCors" => Some(Action::GetBucketCors),
// "s3:GetObject" => Some(Action::GetObject),
// "s3:GetObjectAttributes" => Some(Action::GetObjectAttributes),
// "s3:HeadBucket" => Some(Action::HeadBucket),
// "s3:ListAllMyBuckets" => Some(Action::ListAllMyBuckets),
// "s3:ListBucket" => Some(Action::ListBucket),
// "s3:GetBucketPolicyStatus" => Some(Action::GetBucketPolicyStatus),
// "s3:ListBucketVersions" => Some(Action::ListBucketVersions),
// "s3:ListBucketMultipartUploads" => Some(Action::ListBucketMultipartUploads),
// "s3:ListenNotification" => Some(Action::ListenNotification),
// "s3:ListenBucketNotification" => Some(Action::ListenBucketNotification),
// "s3:ListMultipartUploadParts" => Some(Action::ListMultipartUploadParts),
// "s3:PutLifecycleConfiguration" => Some(Action::PutLifecycleConfiguration),
// "s3:GetLifecycleConfiguration" => Some(Action::GetLifecycleConfiguration),
// "s3:PutBucketNotification" => Some(Action::PutBucketNotification),
// "s3:PutBucketPolicy" => Some(Action::PutBucketPolicy),
// "s3:PutBucketCors" => Some(Action::PutBucketCors),
// "s3:PutObject" => Some(Action::PutObject),
// "s3:DeleteObjectVersion" => Some(Action::DeleteObjectVersion),
// "s3:DeleteObjectVersionTagging" => Some(Action::DeleteObjectVersionTagging),
// "s3:GetObjectVersion" => Some(Action::GetObjectVersion),
// "s3:GetObjectVersionAttributes" => Some(Action::GetObjectVersionAttributes),
// "s3:GetObjectVersionTagging" => Some(Action::GetObjectVersionTagging),
// "s3:PutObjectVersionTagging" => Some(Action::PutObjectVersionTagging),
// "s3:BypassGovernanceRetention" => Some(Action::BypassGovernanceRetention),
// "s3:PutObjectRetention" => Some(Action::PutObjectRetention),
// "s3:GetObjectRetention" => Some(Action::GetObjectRetention),
// "s3:GetObjectLegalHold" => Some(Action::GetObjectLegalHold),
// "s3:PutObjectLegalHold" => Some(Action::PutObjectLegalHold),
// "s3:GetBucketObjectLockConfiguration" => Some(Action::GetBucketObjectLockConfiguration),
// "s3:PutBucketObjectLockConfiguration" => Some(Action::PutBucketObjectLockConfiguration),
// "s3:GetBucketTagging" => Some(Action::GetBucketTagging),
// "s3:PutBucketTagging" => Some(Action::PutBucketTagging),
// "s3:GetObjectTagging" => Some(Action::GetObjectTagging),
// "s3:PutObjectTagging" => Some(Action::PutObjectTagging),
// "s3:DeleteObjectTagging" => Some(Action::DeleteObjectTagging),
// "s3:PutEncryptionConfiguration" => Some(Action::PutBucketEncryption),
// "s3:GetEncryptionConfiguration" => Some(Action::GetBucketEncryption),
// "s3:PutBucketVersioning" => Some(Action::PutBucketVersioning),
// "s3:GetBucketVersioning" => Some(Action::GetBucketVersioning),
// "s3:PutReplicationConfiguration" => Some(Action::PutReplicationConfiguration),
// "s3:GetReplicationConfiguration" => Some(Action::GetReplicationConfiguration),
// "s3:ReplicateObject" => Some(Action::ReplicateObject),
// "s3:ReplicateDelete" => Some(Action::ReplicateDelete),
// "s3:ReplicateTags" => Some(Action::ReplicateTags),
// "s3:GetObjectVersionForReplication" => Some(Action::GetObjectVersionForReplication),
// "s3:RestoreObject" => Some(Action::RestoreObject),
// "s3:ResetBucketReplicationState" => Some(Action::ResetBucketReplicationState),
// "s3:PutObjectFanOut" => Some(Action::PutObjectFanOut),
// "s3:*" => Some(Action::AllActions),
// _ => None,
// }
// }
}
impl FromStr for Action {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"s3:AbortMultipartUpload" => Ok(Action::AbortMultipartUpload),
"s3:CreateBucket" => Ok(Action::CreateBucket),
"s3:DeleteBucket" => Ok(Action::DeleteBucket),
"s3:ForceDeleteBucket" => Ok(Action::ForceDeleteBucket),
"s3:DeleteBucketPolicy" => Ok(Action::DeleteBucketPolicy),
"s3:DeleteBucketCors" => Ok(Action::DeleteBucketCors),
"s3:DeleteObject" => Ok(Action::DeleteObject),
"s3:GetBucketLocation" => Ok(Action::GetBucketLocation),
"s3:GetBucketNotification" => Ok(Action::GetBucketNotification),
"s3:GetBucketPolicy" => Ok(Action::GetBucketPolicy),
"s3:GetBucketCors" => Ok(Action::GetBucketCors),
"s3:GetObject" => Ok(Action::GetObject),
"s3:GetObjectAttributes" => Ok(Action::GetObjectAttributes),
"s3:HeadBucket" => Ok(Action::HeadBucket),
"s3:ListAllMyBuckets" => Ok(Action::ListAllMyBuckets),
"s3:ListBucket" => Ok(Action::ListBucket),
"s3:GetBucketPolicyStatus" => Ok(Action::GetBucketPolicyStatus),
"s3:ListBucketVersions" => Ok(Action::ListBucketVersions),
"s3:ListBucketMultipartUploads" => Ok(Action::ListBucketMultipartUploads),
"s3:ListenNotification" => Ok(Action::ListenNotification),
"s3:ListenBucketNotification" => Ok(Action::ListenBucketNotification),
"s3:ListMultipartUploadParts" => Ok(Action::ListMultipartUploadParts),
"s3:PutLifecycleConfiguration" => Ok(Action::PutLifecycleConfiguration),
"s3:GetLifecycleConfiguration" => Ok(Action::GetLifecycleConfiguration),
"s3:PutBucketNotification" => Ok(Action::PutBucketNotification),
"s3:PutBucketPolicy" => Ok(Action::PutBucketPolicy),
"s3:PutBucketCors" => Ok(Action::PutBucketCors),
"s3:PutObject" => Ok(Action::PutObject),
"s3:DeleteObjectVersion" => Ok(Action::DeleteObjectVersion),
"s3:DeleteObjectVersionTagging" => Ok(Action::DeleteObjectVersionTagging),
"s3:GetObjectVersion" => Ok(Action::GetObjectVersion),
"s3:GetObjectVersionAttributes" => Ok(Action::GetObjectVersionAttributes),
"s3:GetObjectVersionTagging" => Ok(Action::GetObjectVersionTagging),
"s3:PutObjectVersionTagging" => Ok(Action::PutObjectVersionTagging),
"s3:BypassGovernanceRetention" => Ok(Action::BypassGovernanceRetention),
"s3:PutObjectRetention" => Ok(Action::PutObjectRetention),
"s3:GetObjectRetention" => Ok(Action::GetObjectRetention),
"s3:GetObjectLegalHold" => Ok(Action::GetObjectLegalHold),
"s3:PutObjectLegalHold" => Ok(Action::PutObjectLegalHold),
"s3:GetBucketObjectLockConfiguration" => Ok(Action::GetBucketObjectLockConfiguration),
"s3:PutBucketObjectLockConfiguration" => Ok(Action::PutBucketObjectLockConfiguration),
"s3:GetBucketTagging" => Ok(Action::GetBucketTagging),
"s3:PutBucketTagging" => Ok(Action::PutBucketTagging),
"s3:GetObjectTagging" => Ok(Action::GetObjectTagging),
"s3:PutObjectTagging" => Ok(Action::PutObjectTagging),
"s3:DeleteObjectTagging" => Ok(Action::DeleteObjectTagging),
"s3:PutEncryptionConfiguration" => Ok(Action::PutBucketEncryption),
"s3:GetEncryptionConfiguration" => Ok(Action::GetBucketEncryption),
"s3:PutBucketVersioning" => Ok(Action::PutBucketVersioning),
"s3:GetBucketVersioning" => Ok(Action::GetBucketVersioning),
"s3:PutReplicationConfiguration" => Ok(Action::PutReplicationConfiguration),
"s3:GetReplicationConfiguration" => Ok(Action::GetReplicationConfiguration),
"s3:ReplicateObject" => Ok(Action::ReplicateObject),
"s3:ReplicateDelete" => Ok(Action::ReplicateDelete),
"s3:ReplicateTags" => Ok(Action::ReplicateTags),
"s3:GetObjectVersionForReplication" => Ok(Action::GetObjectVersionForReplication),
"s3:RestoreObject" => Ok(Action::RestoreObject),
"s3:ResetBucketReplicationState" => Ok(Action::ResetBucketReplicationState),
"s3:PutObjectFanOut" => Ok(Action::PutObjectFanOut),
"s3:*" => Ok(Action::AllActions),
_ => Err(()),
}
}
}
pub struct ActionConditionKeyMap(HashMap<Action, KeySet>);
impl ActionConditionKeyMap {
pub fn lookup(&self, action: &Action) -> KeySet {
let common_keys: Vec<Key> = COMMOM_KEYS.iter().map(|v| v.to_key()).collect();
let mut merged_keys = KeySet::from_keys(&common_keys);
for (act, key) in self.0.iter() {
if action.is_match(act) {
merged_keys.merge(key);
}
}
merged_keys
}
}
lazy_static! {
pub static ref IAMActionConditionKeyMap: ActionConditionKeyMap = create_action_condition_key_map();
}
fn create_action_condition_key_map() -> ActionConditionKeyMap {
let common_keys: Vec<Key> = COMMOM_KEYS.iter().map(|v| v.to_key()).collect();
let all_support_keys: Vec<Key> = ALL_SUPPORT_KEYS.iter().map(|v| v.to_key()).collect();
let mut map = HashMap::new();
map.insert(Action::AllActions, KeySet::from_keys(&all_support_keys));
map.insert(Action::AbortMultipartUpload, KeySet::from_keys(&common_keys));
map.insert(Action::CreateBucket, KeySet::from_keys(&common_keys));
let mut delete_obj_keys = common_keys.clone();
delete_obj_keys.push(KeyName::S3VersionID.to_key());
map.insert(Action::DeleteObject, KeySet::from_keys(&delete_obj_keys));
map.insert(Action::GetBucketLocation, KeySet::from_keys(&common_keys));
map.insert(Action::GetBucketPolicyStatus, KeySet::from_keys(&common_keys));
let mut get_obj_keys = common_keys.clone();
get_obj_keys.extend(vec![
KeyName::S3XAmzServerSideEncryption.to_key(),
KeyName::S3XAmzServerSideEncryptionCustomerAlgorithm.to_key(),
KeyName::S3XAmzServerSideEncryptionAwsKmsKeyID.to_key(),
KeyName::S3VersionID.to_key(),
KeyName::ExistingObjectTag.to_key(),
]);
map.insert(Action::DeleteObject, KeySet::from_keys(&get_obj_keys));
map.insert(Action::HeadBucket, KeySet::from_keys(&common_keys));
let mut get_obj_attr_keys = common_keys.clone();
get_obj_attr_keys.push(KeyName::ExistingObjectTag.to_key());
map.insert(Action::DeleteObject, KeySet::from_keys(&get_obj_attr_keys));
let mut get_obj_ver_attr_keys = common_keys.clone();
get_obj_ver_attr_keys.extend(vec![KeyName::S3VersionID.to_key(), KeyName::ExistingObjectTag.to_key()]);
map.insert(Action::DeleteObject, KeySet::from_keys(&get_obj_ver_attr_keys));
map.insert(Action::ListAllMyBuckets, KeySet::from_keys(&common_keys));
let mut list_bucket_keys = common_keys.clone();
list_bucket_keys.extend(vec![
KeyName::S3Prefix.to_key(),
KeyName::S3Delimiter.to_key(),
KeyName::S3MaxKeys.to_key(),
]);
map.insert(Action::ListBucket, KeySet::from_keys(&list_bucket_keys));
map.insert(Action::ListBucketVersions, KeySet::from_keys(&list_bucket_keys));
map.insert(Action::ListBucketMultipartUploads, KeySet::from_keys(&common_keys));
map.insert(Action::ListenNotification, KeySet::from_keys(&common_keys));
map.insert(Action::ListenBucketNotification, KeySet::from_keys(&common_keys));
map.insert(Action::ListMultipartUploadParts, KeySet::from_keys(&common_keys));
let mut put_obj_keys = common_keys.clone();
put_obj_keys.extend(vec![
KeyName::S3XAmzCopySource.to_key(),
KeyName::S3XAmzServerSideEncryption.to_key(),
KeyName::S3XAmzServerSideEncryptionCustomerAlgorithm.to_key(),
KeyName::S3XAmzServerSideEncryptionAwsKmsKeyID.to_key(),
KeyName::S3XAmzMetadataDirective.to_key(),
KeyName::S3XAmzStorageClass.to_key(),
KeyName::S3VersionID.to_key(),
KeyName::S3ObjectLockRetainUntilDate.to_key(),
KeyName::S3ObjectLockMode.to_key(),
KeyName::S3ObjectLockLegalHold.to_key(),
KeyName::RequestObjectTagKeys.to_key(),
KeyName::RequestObjectTag.to_key(),
]);
map.insert(Action::PutObject, KeySet::from_keys(&put_obj_keys));
let mut put_obj_retention_keys = common_keys.clone();
put_obj_retention_keys.extend(vec![
KeyName::S3XAmzServerSideEncryption.to_key(),
KeyName::S3XAmzServerSideEncryptionCustomerAlgorithm.to_key(),
KeyName::S3XAmzServerSideEncryptionAwsKmsKeyID.to_key(),
KeyName::S3ObjectLockRemainingRetentionDays.to_key(),
KeyName::S3ObjectLockRetainUntilDate.to_key(),
KeyName::S3ObjectLockMode.to_key(),
KeyName::S3VersionID.to_key(),
]);
map.insert(Action::PutObjectRetention, KeySet::from_keys(&put_obj_retention_keys));
let mut get_obj_retention_keys = common_keys.clone();
get_obj_retention_keys.extend(vec![
KeyName::S3XAmzServerSideEncryption.to_key(),
KeyName::S3XAmzServerSideEncryptionCustomerAlgorithm.to_key(),
KeyName::S3XAmzServerSideEncryptionAwsKmsKeyID.to_key(),
KeyName::S3VersionID.to_key(),
]);
map.insert(Action::GetObjectRetention, KeySet::from_keys(&get_obj_retention_keys));
let mut put_obj_hold_keys = common_keys.clone();
put_obj_hold_keys.extend(vec![
KeyName::S3XAmzServerSideEncryption.to_key(),
KeyName::S3XAmzServerSideEncryptionCustomerAlgorithm.to_key(),
KeyName::S3XAmzServerSideEncryptionAwsKmsKeyID.to_key(),
KeyName::S3ObjectLockLegalHold.to_key(),
KeyName::S3VersionID.to_key(),
]);
map.insert(Action::PutObjectLegalHold, KeySet::from_keys(&put_obj_hold_keys));
map.insert(Action::GetObjectLegalHold, KeySet::from_keys(&common_keys));
let mut bypass_governance_retention_keys = common_keys.clone();
bypass_governance_retention_keys.extend(vec![
KeyName::S3VersionID.to_key(),
KeyName::S3ObjectLockRemainingRetentionDays.to_key(),
KeyName::S3ObjectLockRetainUntilDate.to_key(),
KeyName::S3ObjectLockMode.to_key(),
KeyName::S3ObjectLockLegalHold.to_key(),
KeyName::RequestObjectTagKeys.to_key(),
KeyName::RequestObjectTag.to_key(),
]);
map.insert(Action::BypassGovernanceRetention, KeySet::from_keys(&bypass_governance_retention_keys));
map.insert(Action::GetBucketObjectLockConfiguration, KeySet::from_keys(&common_keys));
map.insert(Action::PutBucketObjectLockConfiguration, KeySet::from_keys(&common_keys));
map.insert(Action::GetBucketTagging, KeySet::from_keys(&common_keys));
let mut put_bucket_tagging_keys = common_keys.clone();
put_bucket_tagging_keys.extend(vec![KeyName::RequestObjectTagKeys.to_key(), KeyName::RequestObjectTag.to_key()]);
map.insert(Action::PutBucketTagging, KeySet::from_keys(&put_bucket_tagging_keys));
let mut put_object_tagging_keys = common_keys.clone();
put_object_tagging_keys.extend(vec![
KeyName::S3VersionID.to_key(),
KeyName::ExistingObjectTag.to_key(),
KeyName::RequestObjectTagKeys.to_key(),
KeyName::RequestObjectTag.to_key(),
]);
map.insert(Action::PutObjectTagging, KeySet::from_keys(&put_object_tagging_keys));
let mut get_object_tagging_keys = common_keys.clone();
get_object_tagging_keys.extend(vec![KeyName::S3VersionID.to_key(), KeyName::ExistingObjectTag.to_key()]);
map.insert(Action::GetObjectTagging, KeySet::from_keys(&get_object_tagging_keys));
map.insert(Action::DeleteObjectTagging, KeySet::from_keys(&get_object_tagging_keys));
map.insert(Action::PutObjectVersionTagging, KeySet::from_keys(&put_object_tagging_keys));
map.insert(Action::GetObjectVersionTagging, KeySet::from_keys(&get_object_tagging_keys));
map.insert(Action::GetObjectVersion, KeySet::from_keys(&get_object_tagging_keys));
let mut delete_object_version_keys = common_keys.clone();
delete_object_version_keys.extend(vec![KeyName::S3VersionID.to_key()]);
map.insert(Action::DeleteObjectVersion, KeySet::from_keys(&delete_object_version_keys));
map.insert(Action::DeleteObjectVersionTagging, KeySet::from_keys(&get_object_tagging_keys));
map.insert(Action::GetReplicationConfiguration, KeySet::from_keys(&common_keys));
map.insert(Action::PutReplicationConfiguration, KeySet::from_keys(&common_keys));
map.insert(Action::ReplicateObject, KeySet::from_keys(&get_object_tagging_keys));
map.insert(Action::ReplicateDelete, KeySet::from_keys(&get_object_tagging_keys));
map.insert(Action::ReplicateTags, KeySet::from_keys(&get_object_tagging_keys));
map.insert(Action::GetObjectVersionForReplication, KeySet::from_keys(&get_object_tagging_keys));
map.insert(Action::RestoreObject, KeySet::from_keys(&common_keys));
map.insert(Action::ResetBucketReplicationState, KeySet::from_keys(&common_keys));
map.insert(Action::PutObjectFanOut, KeySet::from_keys(&common_keys));
ActionConditionKeyMap(map)
}

View File

@@ -1,259 +0,0 @@
use common::error::{Error, Result};
// use rmp_serde::Serializer as rmpSerializer;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::{
action::{Action, ActionSet, IAMActionConditionKeyMap},
condition::function::Functions,
effect::Effect,
principal::Principal,
resource::ResourceSet,
};
const DEFAULT_VERSION: &str = "2012-10-17";
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
pub struct BucketPolicyArgs {
pub account_name: String,
pub groups: Vec<String>,
pub action: Action,
pub bucket_name: String,
pub condition_values: HashMap<String, Vec<String>>,
pub is_owner: bool,
pub object_name: String,
}
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)]
#[serde(rename_all = "PascalCase", default)]
pub struct BPStatement {
#[serde(rename = "Sid")]
pub sid: String,
#[serde(rename = "Effect")]
pub effect: Effect,
#[serde(rename = "Principal")]
pub principal: Principal,
#[serde(rename = "Action")]
pub actions: ActionSet,
#[serde(rename = "NotAction", skip_serializing_if = "ActionSet::is_empty")]
pub not_actions: ActionSet,
#[serde(rename = "Resource", skip_serializing_if = "ResourceSet::is_empty")]
pub resources: ResourceSet,
#[serde(rename = "Condition", skip_serializing_if = "Functions::is_empty")]
pub conditions: Functions,
}
impl BPStatement {
// pub fn equals(&self, other: &BPStatement) -> bool {
// if self.effect != other.effect {
// return false;
// }
// if !self.principal.equals(other.principal) {
// return false;
// }
// if !self.actions.equals(other.actions) {
// return false;
// }
// if !self.not_actions.equals(other.not_actions) {
// return false;
// }
// if !self.resources.equals(other.resources) {
// return false;
// }
// if !self.conditions.equals(other.conditions) {
// return false;
// }
// true
// }
pub fn validate(&self, bucket: &str) -> Result<()> {
self.is_valid()?;
self.resources.validate_bucket(bucket)
}
pub fn is_valid(&self) -> Result<()> {
if !self.effect.is_valid() {
return Err(Error::msg(format!("invalid Effect {:?}", self.effect)));
}
if !self.principal.is_valid() {
return Err(Error::msg(format!("invalid Principal {:?}", self.principal)));
}
if self.actions.is_empty() && self.not_actions.is_empty() {
return Err(Error::msg("Action must not be empty"));
}
if self.resources.as_ref().is_empty() {
return Err(Error::msg("Resource must not be empty"));
}
for act in self.actions.as_ref() {
if act.is_object_action() {
if !self.resources.object_resource_exists() {
return Err(Error::msg(format!(
"unsupported object Resource found {:?} for action {:?}",
self.resources, act
)));
}
} else if !self.resources.bucket_resource_exists() {
return Err(Error::msg(format!(
"unsupported bucket Resource found {:?} for action {:?}",
self.resources, act
)));
}
let key_diff = self.conditions.keys().difference(&IAMActionConditionKeyMap.lookup(act));
if !key_diff.is_empty() {
return Err(Error::msg(format!(
"unsupported condition keys '{:?}' used for action '{:?}'",
key_diff, act
)));
}
}
Ok(())
}
fn is_allowed(&self, args: &BucketPolicyArgs) -> bool {
let check = || -> bool {
if !self.principal.is_match(&args.account_name) {
return false;
}
if (!self.actions.is_match(&args.action) && !self.actions.is_empty()) || self.not_actions.is_match(&args.action) {
return false;
}
let mut resource = args.bucket_name.clone();
if !args.object_name.is_empty() {
if !args.object_name.starts_with('/') {
resource.push('/');
}
resource.push_str(&args.object_name);
}
if !self.resources.is_match(&resource, &args.condition_values) {
return false;
}
self.conditions.evaluate(&args.condition_values)
};
self.effect.is_allowed(check())
}
}
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
// #[serde(rename_all = "PascalCase", default)]
pub struct BucketPolicy {
#[serde(rename = "ID", default)]
pub id: String,
#[serde(rename = "Version")]
pub version: String,
#[serde(rename = "Statement")]
pub statements: Vec<BPStatement>,
}
impl BucketPolicy {
pub fn is_allowed(&self, args: &BucketPolicyArgs) -> bool {
for statement in self.statements.iter() {
if statement.effect == Effect::Deny && !statement.is_allowed(args) {
return false;
}
}
if args.is_owner {
return true;
}
for statement in self.statements.iter() {
if statement.effect == Effect::Allow && statement.is_allowed(args) {
return true;
}
}
false
}
pub fn validate(&self, bucket: &str) -> Result<()> {
self.is_valid()?;
for statement in self.statements.iter() {
statement.validate(bucket)?;
}
Ok(())
}
pub fn is_valid(&self) -> Result<()> {
if self.version.as_str() != DEFAULT_VERSION && self.version.is_empty() {
return Err(Error::msg(format!("invalid version {}", self.version)));
}
for statement in self.statements.iter() {
statement.is_valid()?;
}
Ok(())
}
pub fn is_empty(&self) -> bool {
self.statements.is_empty()
}
pub fn marshal_msg(&self) -> Result<String> {
let buf = serde_json::to_string(self)?;
Ok(buf)
// let mut buf = Vec::new();
// self.serialize(&mut rmpSerializer::new(&mut buf).with_struct_map())?;
// Ok(buf)
}
pub fn unmarshal(buf: &[u8]) -> Result<Self> {
let mut p = serde_json::from_slice::<BucketPolicy>(buf)?;
p.drop_duplicate_statements();
Ok(p)
// let t: BucketPolicy = rmp_serde::from_slice(buf)?;
// Ok(t)
}
fn drop_duplicate_statements(&mut self) {
let mut dups = HashMap::new();
for v in self.statements.iter() {
if let Ok(data) = serde_json::to_string(self) {
dups.insert(data, v);
}
}
let mut news = Vec::new();
for (_, v) in dups {
news.push(v.clone());
}
self.statements = news;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bucket_policy() {
let json = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Resource\":[\"arn:aws:s3:::dada\"],\"Sid\":\"\"},{\"Action\":[\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\"],\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Resource\":[\"arn:aws:s3:::dada/*\"],\"Sid\":\"sdf\"}]}";
let a = BucketPolicy::unmarshal(json.to_string().as_bytes()).unwrap();
println!("{:?}", a);
let j = a.marshal_msg();
println!("{:?}", j);
println!("{:?}", json);
}
}

View File

@@ -1,304 +0,0 @@
use super::{
key::{Key, KeySet},
keyname::KeyName,
name::Name,
};
use serde::{
de::{MapAccess, Visitor},
ser::SerializeMap,
Deserialize, Serialize,
};
use std::{
collections::{HashMap, HashSet},
fmt::{self, Debug, Display},
marker::PhantomData,
};
// 定义ValueSet类型
pub type ValueSet = HashSet<String>;
// 定义Function trait
pub trait FunctionApi: 'static + Send + Sync {
// evaluate方法
fn evaluate(&self, values: &HashMap<String, Vec<String>>) -> bool;
// key方法
fn key(&self) -> Key;
// name方法
fn name(&self) -> Name;
// String方法
fn to_string(&self) -> String;
// to_map方法
fn to_map(&self) -> HashMap<Key, ValueSet>;
fn clone_box(&self) -> Box<dyn FunctionApi>;
}
// #[derive(Debug, Deserialize, Serialize, Clone)]
// pub enum Function {
// Test(TestFunction),
// }
// impl FunctionApi for Function {
// // evaluate方法
// fn evaluate(&self, values: &HashMap<String, Vec<String>>) -> bool {
// match self {
// Function::Test(f) => f.evaluate(values),
// }
// }
// // key方法
// fn key(&self) -> Key {
// match self {
// Function::Test(f) => f.key(),
// }
// }
// // name方法
// fn name(&self) -> Name {
// match self {
// Function::Test(f) => f.name(),
// }
// }
// // String方法
// fn to_string(&self) -> String {
// match self {
// Function::Test(f) => f.to_string(),
// }
// }
// // to_map方法
// fn to_map(&self) -> HashMap<Key, ValueSet> {
// match self {
// Function::Test(f) => f.to_map(),
// }
// }
// fn clone_box(&self) -> Box<dyn FunctionApi> {
// match self {
// Function::Test(f) => f.clone_box(),
// }
// }
// }
// 定义Functions类型
#[derive(Default)]
pub struct Functions(Vec<Box<dyn FunctionApi>>);
impl Functions {
pub fn evaluate(&self, values: &HashMap<String, Vec<String>>) -> bool {
for f in self.0.iter() {
if f.evaluate(values) {
return true;
}
}
false
}
pub fn keys(&self) -> KeySet {
let mut set = KeySet::new();
for f in self.0.iter() {
set.add(f.key())
}
set
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl Debug for Functions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let funs: Vec<String> = self.0.iter().map(|v| v.to_string()).collect();
f.debug_list().entries(funs.iter()).finish()
}
}
impl Display for Functions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let funs: Vec<String> = self.0.iter().map(|v| v.to_string()).collect();
write!(f, "{:?}", funs)
}
}
impl Clone for Functions {
fn clone(&self) -> Self {
let mut list = Vec::new();
for v in self.0.iter() {
list.push(v.clone_box())
}
Functions(list)
}
}
impl PartialEq for Functions {
fn eq(&self, other: &Self) -> bool {
if self.0.len() != other.0.len() {
return false;
}
for v in self.0.iter() {
let s = v.to_string();
let mut found = false;
for o in other.0.iter() {
if s == o.to_string() {
found = true;
break;
}
}
if !found {
return false;
}
}
true
}
}
impl Eq for Functions {}
type FunctionsMap = HashMap<String, HashMap<String, ValueSet>>;
impl Serialize for Functions {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut nm: FunctionsMap = HashMap::new();
for f in self.0.iter() {
let fname = f.name().to_string();
if !nm.contains_key(&fname) {
nm.insert(fname.clone(), HashMap::new());
}
for (k, v) in f.to_map() {
if let Some(hm) = nm.get_mut(&fname) {
hm.insert(k.to_string(), v);
}
}
}
let mut map = serializer.serialize_map(Some(nm.len()))?;
for (k, v) in nm.iter() {
map.serialize_entry(k, v)?;
}
map.end()
}
}
struct MyMapVisitor {
marker: PhantomData<fn() -> FunctionsMap>,
}
impl MyMapVisitor {
fn new() -> Self {
MyMapVisitor { marker: PhantomData }
}
}
// This is the trait that Deserializers are going to be driving. There
// is one method for each type of data that our type knows how to
// deserialize from. There are many other methods that are not
// implemented here, for example deserializing from integers or strings.
// By default those methods will return an error, which makes sense
// because we cannot deserialize a MyMap from an integer or string.
impl<'de> Visitor<'de> for MyMapVisitor {
// The type that our Visitor is going to produce.
type Value = FunctionsMap;
// Format a message stating what data this Visitor expects to receive.
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a very special map")
}
// Deserialize MyMap from an abstract "map" provided by the
// Deserializer. The MapAccess input is a callback provided by
// the Deserializer to let us see each entry in the map.
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = FunctionsMap::with_capacity(access.size_hint().unwrap_or(0));
// While there are entries remaining in the input, add them
// into our map.
while let Some((key, value)) = access.next_entry()? {
map.insert(key, value);
}
Ok(map)
}
}
// This is the trait that informs Serde how to deserialize MyMap.
impl<'de> Deserialize<'de> for Functions {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
// Instantiate our Visitor and ask the Deserializer to drive
// it over the input data, resulting in an instance of MyMap.
let map = deserializer.deserialize_map(MyMapVisitor::new())?;
for (key, vals) in map.iter() {
println!("functions key {}, vals {:?}", key, vals);
}
// TODO: FIXME: create functions from name
Ok(Functions(Vec::new()))
}
}
// impl<'de> Deserialize<'de> for Functions {
// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
// where
// D: serde::Deserializer<'de>,
// {
// todo!()
// }
// }
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
pub struct TestFunction {}
impl FunctionApi for TestFunction {
// evaluate方法
fn evaluate(&self, _values: &HashMap<String, Vec<String>>) -> bool {
true
}
// key方法
fn key(&self) -> Key {
Key {
name: KeyName::JWTPrefUsername,
variable: "".to_string(),
}
}
// name方法
fn name(&self) -> Name {
Name::StringEquals
}
// String方法
fn to_string(&self) -> String {
Name::StringEquals.to_string()
}
// to_map方法
fn to_map(&self) -> HashMap<Key, ValueSet> {
HashMap::new()
}
fn clone_box(&self) -> Box<dyn FunctionApi> {
Box::new(self.clone())
}
}

View File

@@ -1,155 +0,0 @@
use super::keyname::{KeyName, ALL_SUPPORT_KEYS};
use common::error::Error;
use serde::{Deserialize, Serialize};
use std::{collections::HashSet, fmt, str::FromStr};
// 定义Key结构体
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Key {
pub name: KeyName,
pub variable: String,
}
impl Key {
pub fn new(name: KeyName, variable: String) -> Self {
Key { name, variable }
}
// IsValid - checks if key is valid or not.
fn is_valid(&self) -> bool {
ALL_SUPPORT_KEYS.iter().any(|supported| self.name == *supported)
}
// Is - checks if this key has the same key name or not.
pub fn is(&self, name: &KeyName) -> bool {
self.name == *name
}
// VarName - returns variable key name, such as "${aws:username}"
pub fn var_name(&self) -> String {
self.name.var_name()
}
// Name - returns key name which is stripped value of prefixes "aws:" and "s3:"
pub fn name(&self) -> String {
if !self.variable.is_empty() {
format!("{}{}", self.name.name(), self.variable)
} else {
self.name.name().to_string()
}
}
}
impl FromStr for Key {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (name, variable) = if let Some(pos) = s.find('/') {
(&s[..pos], &s[pos + 1..])
} else {
(s, "")
};
let keyname = KeyName::from_str(name)?;
let key = Key {
name: keyname,
variable: variable.to_string(),
};
if key.is_valid() {
Ok(key)
} else {
Err(Error::msg(format!("invalid condition key '{}'", s)))
}
}
}
impl Serialize for Key {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.to_string().as_str())
}
}
impl<'de> Deserialize<'de> for Key {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
Key::from_str(s.as_str()).map_err(serde::de::Error::custom)
}
}
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.variable.is_empty() {
write!(f, "{}/{}", self.name.as_str(), self.variable)
} else {
write!(f, "{}", self.name)
}
}
}
#[derive(Debug, Default)]
pub struct KeySet(HashSet<Key>);
impl KeySet {
pub fn new() -> Self {
KeySet(HashSet::new())
}
// Add - add a key to key set
pub fn add(&mut self, key: Key) {
self.0.insert(key);
}
// Merge merges two key sets, duplicates are overwritten
pub fn merge(&mut self, other: &KeySet) {
for key in &other.0 {
self.add(key.clone());
}
}
// Match matches the input key name with current keySet
pub fn match_key(&self, key: &Key) -> bool {
self.0.contains(key)
}
// Difference - returns a key set contains difference of two keys
pub fn difference(&self, other: &KeySet) -> KeySet {
let mut result = KeySet::default();
for key in &self.0 {
if !other.match_key(key) {
result.add(key.clone());
}
}
result
}
// IsEmpty - returns whether key set is empty or not
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
// ToSlice - returns slice of keys
fn to_slice(&self) -> Vec<Key> {
self.0.iter().cloned().collect()
}
// NewKeySet - returns new KeySet contains given keys
pub fn from_keys(keys: &Vec<Key>) -> KeySet {
let mut set = KeySet::default();
for key in keys {
set.add(key.clone());
}
set
}
}
impl fmt::Display for KeySet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.to_slice())
}
}

View File

@@ -1,475 +0,0 @@
use core::fmt;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use common::error::Error;
use super::key::Key;
// 定义KeyName枚举类型
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum KeyName {
// S3XAmzCopySource - key representing x-amz-copy-source HTTP header applicable to PutObject API only.
S3XAmzCopySource, // KeyName = "s3:x-amz-copy-source"
// S3XAmzServerSideEncryption - key representing x-amz-server-side-encryption HTTP header applicable
// to PutObject API only.
S3XAmzServerSideEncryption, // KeyName = "s3:x-amz-server-side-encryption"
// S3XAmzServerSideEncryptionCustomerAlgorithm - key representing
// x-amz-server-side-encryption-customer-algorithm HTTP header applicable to PutObject API only.
S3XAmzServerSideEncryptionCustomerAlgorithm, // KeyName = "s3:x-amz-server-side-encryption-customer-algorithm"
// S3XAmzMetadataDirective - key representing x-amz-metadata-directive HTTP header applicable to
// PutObject API only.
S3XAmzMetadataDirective, // KeyName = "s3:x-amz-metadata-directive"
// S3XAmzContentSha256 - set a static content-sha256 for all calls for a given action.
S3XAmzContentSha256, // KeyName = "s3:x-amz-content-sha256"
// S3XAmzStorageClass - key representing x-amz-storage-class HTTP header applicable to PutObject API
// only.
S3XAmzStorageClass, // KeyName = "s3:x-amz-storage-class"
// S3XAmzServerSideEncryptionAwsKmsKeyID - key representing x-amz-server-side-encryption-aws-kms-key-id
// HTTP header for S3 API calls
S3XAmzServerSideEncryptionAwsKmsKeyID, // KeyName = "s3:x-amz-server-side-encryption-aws-kms-key-id"
// S3LocationConstraint - key representing LocationConstraint XML tag of CreateBucket API only.
S3LocationConstraint, // KeyName = "s3:LocationConstraint"
// S3Prefix - key representing prefix query parameter of ListBucket API only.
S3Prefix, // KeyName = "s3:prefix"
// S3Delimiter - key representing delimiter query parameter of ListBucket API only.
S3Delimiter, // KeyName = "s3:delimiter"
// S3VersionID - Enables you to limit the permission for the
// s3:PutObjectVersionTagging action to a specific object version.
S3VersionID, // KeyName = "s3:versionid"
// S3MaxKeys - key representing max-keys query parameter of ListBucket API only.
S3MaxKeys, // KeyName = "s3:max-keys"
// S3ObjectLockRemainingRetentionDays - key representing object-lock-remaining-retention-days
// Enables enforcement of an object relative to the remaining retention days, you can set
// minimum and maximum allowable retention periods for a bucket using a bucket policy.
// This key are specific for s3:PutObjectRetention API.
S3ObjectLockRemainingRetentionDays, // KeyName = "s3:object-lock-remaining-retention-days"
// S3ObjectLockMode - key representing object-lock-mode
// Enables enforcement of the specified object retention mode
S3ObjectLockMode, // KeyName = "s3:object-lock-mode"
// S3ObjectLockRetainUntilDate - key representing object-lock-retain-util-date
// Enables enforcement of a specific retain-until-date
S3ObjectLockRetainUntilDate, // KeyName = "s3:object-lock-retain-until-date"
// S3ObjectLockLegalHold - key representing object-local-legal-hold
// Enables enforcement of the specified object legal hold status
S3ObjectLockLegalHold, // KeyName = "s3:object-lock-legal-hold"
// AWSReferer - key representing Referer header of any API.
AWSReferer, // KeyName = "aws:Referer"
// AWSSourceIP - key representing client's IP address (not intermittent proxies) of any API.
AWSSourceIP, // KeyName = "aws:SourceIp"
// AWSUserAgent - key representing UserAgent header for any API.
AWSUserAgent, // KeyName = "aws:UserAgent"
// AWSSecureTransport - key representing if the clients request is authenticated or not.
AWSSecureTransport, // KeyName = "aws:SecureTransport"
// AWSCurrentTime - key representing the current time.
AWSCurrentTime, // KeyName = "aws:CurrentTime"
// AWSEpochTime - key representing the current epoch time.
AWSEpochTime, // KeyName = "aws:EpochTime"
// AWSPrincipalType - user principal type currently supported values are "User" and "Anonymous".
AWSPrincipalType, // KeyName = "aws:principaltype"
// AWSUserID - user unique ID, in RustFS this value is same as your user Access Key.
AWSUserID, // KeyName = "aws:userid"
// AWSUsername - user friendly name, in RustFS this value is same as your user Access Key.
AWSUsername, // KeyName = "aws:username"
// AWSGroups - groups for any authenticating Access Key.
AWSGroups, // KeyName = "ss"
// S3SignatureVersion - identifies the version of AWS Signature that you want to support for authenticated requests.
S3SignatureVersion, // KeyName = "s3:signatureversion"
// S3SignatureAge - identifies the maximum age of presgiend URL allowed
S3SignatureAge, // KeyName = "s3:signatureAge"
// S3AuthType - optionally use this condition key to restrict incoming requests to use a specific authentication method.
S3AuthType, // KeyName = "s3:authType"
// Refer https://docs.aws.amazon.com/AmazonS3/latest/userguide/tagging-and-policies.html
ExistingObjectTag, // KeyName = "s3:ExistingObjectTag"
RequestObjectTagKeys, // KeyName = "s3:RequestObjectTagKeys"
RequestObjectTag, // KeyName = "s3:RequestObjectTag"
// JWTSub - JWT subject claim substitution.
JWTSub, //KeyName = "jwt:sub"
// JWTIss issuer claim substitution.
JWTIss, //KeyName = "jwt:iss"
// JWTAud audience claim substitution.
JWTAud, //KeyName = "jwt:aud"
// JWTJti JWT unique identifier claim substitution.
JWTJti, //KeyName = "jwt:jti"
JWTUpn, //KeyName = "jwt:upn"
JWTName, //KeyName = "jwt:name"
JWTGroups, //KeyName = "jwt:groups"
JWTGivenName, //KeyName = "jwt:given_name"
JWTFamilyName, //KeyName = "jwt:family_name"
JWTMiddleName, //KeyName = "jwt:middle_name"
JWTNickName, //KeyName = "jwt:nickname"
JWTPrefUsername, //KeyName = "jwt:preferred_username"
JWTProfile, //KeyName = "jwt:profile"
JWTPicture, //KeyName = "jwt:picture"
JWTWebsite, //KeyName = "jwt:website"
JWTEmail, //KeyName = "jwt:email"
JWTGender, //KeyName = "jwt:gender"
JWTBirthdate, //KeyName = "jwt:birthdate"
JWTPhoneNumber, //KeyName = "jwt:phone_number"
JWTAddress, //KeyName = "jwt:address"
JWTScope, //KeyName = "jwt:scope"
JWTClientID, //KeyName = "jwt:client_id"
// LDAPUser - LDAP username, this value is equal to your authenticating LDAP user DN.
LDAPUser, // KeyName = "ldap:user"
// LDAPUsername - LDAP username, is the authenticated simple user.
LDAPUsername, // KeyName = "ldap:username"
// LDAPGroups - LDAP groups, this value is equal LDAP Group DNs for the authenticating user.
LDAPGroups, // KeyName = "ldap:groups"
// STSDurationSeconds - Duration seconds condition for STS policy
STSDurationSeconds, // KeyName = "sts:DurationSeconds"
// SVCDurationSeconds - Duration seconds condition for Admin policy
SVCDurationSeconds, // KeyName = "svc:DurationSeconds"
Undefined,
}
lazy_static! {
pub static ref JWTKEYS: Vec<KeyName> = {
vec![
KeyName::JWTSub,
KeyName::JWTIss,
KeyName::JWTAud,
KeyName::JWTJti,
KeyName::JWTName,
KeyName::JWTUpn,
KeyName::JWTGroups,
KeyName::JWTGivenName,
KeyName::JWTFamilyName,
KeyName::JWTMiddleName,
KeyName::JWTNickName,
KeyName::JWTPrefUsername,
KeyName::JWTProfile,
KeyName::JWTPicture,
KeyName::JWTWebsite,
KeyName::JWTEmail,
KeyName::JWTGender,
KeyName::JWTBirthdate,
KeyName::JWTPhoneNumber,
KeyName::JWTAddress,
KeyName::JWTScope,
KeyName::JWTClientID,
]
};
pub static ref ALL_SUPPORT_KEYS: Vec<KeyName> = {
vec![
KeyName::S3SignatureVersion,
KeyName::S3AuthType,
KeyName::S3SignatureAge,
KeyName::S3XAmzCopySource,
KeyName::S3XAmzServerSideEncryption,
KeyName::S3XAmzServerSideEncryptionCustomerAlgorithm,
KeyName::S3XAmzMetadataDirective,
KeyName::S3XAmzStorageClass,
KeyName::S3XAmzServerSideEncryptionAwsKmsKeyID,
KeyName::S3XAmzContentSha256,
KeyName::S3LocationConstraint,
KeyName::S3Prefix,
KeyName::S3Delimiter,
KeyName::S3MaxKeys,
KeyName::S3VersionID,
KeyName::S3ObjectLockRemainingRetentionDays,
KeyName::S3ObjectLockMode,
KeyName::S3ObjectLockLegalHold,
KeyName::S3ObjectLockRetainUntilDate,
KeyName::AWSReferer,
KeyName::AWSSourceIP,
KeyName::AWSUserAgent,
KeyName::AWSSecureTransport,
KeyName::AWSCurrentTime,
KeyName::AWSEpochTime,
KeyName::AWSPrincipalType,
KeyName::AWSUserID,
KeyName::AWSUsername,
KeyName::AWSGroups,
KeyName::LDAPUser,
KeyName::LDAPUsername,
KeyName::LDAPGroups,
KeyName::RequestObjectTag,
KeyName::ExistingObjectTag,
KeyName::RequestObjectTagKeys,
KeyName::JWTSub,
KeyName::JWTIss,
KeyName::JWTAud,
KeyName::JWTJti,
KeyName::JWTName,
KeyName::JWTUpn,
KeyName::JWTGroups,
KeyName::JWTGivenName,
KeyName::JWTFamilyName,
KeyName::JWTMiddleName,
KeyName::JWTNickName,
KeyName::JWTPrefUsername,
KeyName::JWTProfile,
KeyName::JWTPicture,
KeyName::JWTWebsite,
KeyName::JWTEmail,
KeyName::JWTGender,
KeyName::JWTBirthdate,
KeyName::JWTPhoneNumber,
KeyName::JWTAddress,
KeyName::JWTScope,
KeyName::JWTClientID,
KeyName::STSDurationSeconds,
KeyName::SVCDurationSeconds,
]
};
pub static ref COMMOM_KEYS: Vec<KeyName> = {
let mut keys = vec![
KeyName::S3SignatureVersion,
KeyName::S3AuthType,
KeyName::S3SignatureAge,
KeyName::S3XAmzContentSha256,
KeyName::S3LocationConstraint,
KeyName::AWSReferer,
KeyName::AWSSourceIP,
KeyName::AWSUserAgent,
KeyName::AWSSecureTransport,
KeyName::AWSCurrentTime,
KeyName::AWSEpochTime,
KeyName::AWSPrincipalType,
KeyName::AWSUserID,
KeyName::AWSUsername,
KeyName::AWSGroups,
KeyName::LDAPUser,
KeyName::LDAPUsername,
KeyName::LDAPGroups,
];
keys.extend(JWTKEYS.iter().cloned());
keys
};
pub static ref ALL_SUPPORT_ADMIN_KEYS: Vec<KeyName> = {
let mut keys = vec![
KeyName::AWSReferer,
KeyName::AWSSourceIP,
KeyName::AWSUserAgent,
KeyName::AWSSecureTransport,
KeyName::AWSCurrentTime,
KeyName::AWSEpochTime,
KeyName::AWSPrincipalType,
KeyName::AWSUserID,
KeyName::AWSUsername,
KeyName::AWSGroups,
KeyName::LDAPUser,
KeyName::LDAPUsername,
KeyName::LDAPGroups,
KeyName::SVCDurationSeconds,
];
keys.extend(JWTKEYS.iter().cloned());
keys
};
pub static ref ALL_SUPPORT_STS_KEYS: Vec<KeyName> = vec![KeyName::STSDurationSeconds];
}
// 实现KeyName枚举的方法
impl KeyName {
pub fn name(&self) -> &str {
let name = self.as_str();
if name.starts_with("aws:") {
name.trim_start_matches("aws:")
} else if name.starts_with("jwt:") {
name.trim_start_matches("jwt:")
} else if name.starts_with("ldap:") {
name.trim_start_matches("ldap:")
} else if name.starts_with("sts:") {
name.trim_start_matches("sts:")
} else if name.starts_with("svc:") {
name.trim_start_matches("svc:")
} else {
name.trim_start_matches("s3:")
}
}
// Name方法返回键名的名称
pub fn as_str(&self) -> &str {
match self {
KeyName::S3XAmzCopySource => "s3:x-amz-copy-source",
KeyName::S3XAmzServerSideEncryption => "s3:x-amz-server-side-encryption",
KeyName::S3XAmzServerSideEncryptionCustomerAlgorithm => "s3:x-amz-server-side-encryption-customer-algorithm",
KeyName::S3XAmzMetadataDirective => "s3:x-amz-metadata-directive",
KeyName::S3XAmzContentSha256 => "s3:x-amz-content-sha256",
KeyName::S3XAmzStorageClass => "s3:x-amz-storage-class",
KeyName::S3XAmzServerSideEncryptionAwsKmsKeyID => "s3:x-amz-server-side-encryption-aws-kms-key-id",
KeyName::S3LocationConstraint => "s3:LocationConstraint",
KeyName::S3Prefix => "s3:prefix",
KeyName::S3Delimiter => "s3:delimiter",
KeyName::S3VersionID => "s3:versionid",
KeyName::S3MaxKeys => "s3:max-keys",
KeyName::S3ObjectLockRemainingRetentionDays => "s3:object-lock-remaining-retention-days",
KeyName::S3ObjectLockMode => "s3:object-lock-mode",
KeyName::S3ObjectLockRetainUntilDate => "s3:object-lock-retain-until-date",
KeyName::S3ObjectLockLegalHold => "s3:object-lock-legal-hold",
KeyName::AWSReferer => "aws:Referer",
KeyName::AWSSourceIP => "aws:SourceIp",
KeyName::AWSUserAgent => "aws:UserAgent",
KeyName::AWSSecureTransport => "aws:SecureTransport",
KeyName::AWSCurrentTime => "aws:CurrentTime",
KeyName::AWSEpochTime => "aws:EpochTime",
KeyName::AWSPrincipalType => "aws:principaltype",
KeyName::AWSUserID => "aws:userid",
KeyName::AWSUsername => "aws:username",
KeyName::AWSGroups => "ss",
KeyName::S3SignatureVersion => "s3:signatureversion",
KeyName::S3SignatureAge => "s3:signatureAge",
KeyName::S3AuthType => "s3:authType",
KeyName::ExistingObjectTag => "s3:ExistingObjectTag",
KeyName::RequestObjectTagKeys => "s3:RequestObjectTagKeys",
KeyName::RequestObjectTag => "s3:RequestObjectTag",
KeyName::JWTSub => "jwt:sub",
KeyName::JWTIss => "jwt:iss",
KeyName::JWTAud => "jwt:aud",
KeyName::JWTJti => "jwt:jti",
KeyName::JWTUpn => "jwt:upn",
KeyName::JWTName => "jwt:name",
KeyName::JWTGroups => "jwt:groups",
KeyName::JWTGivenName => "jwt:given_name",
KeyName::JWTFamilyName => "jwt:family_name",
KeyName::JWTMiddleName => "jwt:middle_name",
KeyName::JWTNickName => "jwt:nickname",
KeyName::JWTPrefUsername => "jwt:preferred_username",
KeyName::JWTProfile => "jwt:profile",
KeyName::JWTPicture => "jwt:picture",
KeyName::JWTWebsite => "jwt:website",
KeyName::JWTEmail => "jwt:email",
KeyName::JWTGender => "jwt:gender",
KeyName::JWTBirthdate => "jwt:birthdate",
KeyName::JWTPhoneNumber => "jwt:phone_number",
KeyName::JWTAddress => "jwt:address",
KeyName::JWTScope => "jwt:scope",
KeyName::JWTClientID => "jwt:client_id",
KeyName::LDAPUser => "ldap:user",
KeyName::LDAPUsername => "ldap:username",
KeyName::LDAPGroups => "ldap:groups",
KeyName::STSDurationSeconds => "sts:DurationSeconds",
KeyName::SVCDurationSeconds => "svc:DurationSeconds",
KeyName::Undefined => "",
}
}
// VarName方法返回变量键名例如 "${aws:username}"
pub fn var_name(&self) -> String {
format!("${{{}}}", self.name())
}
// ToKey方法从名称创建键
pub fn to_key(&self) -> Key {
Key::new(self.clone(), "".to_string())
}
}
impl fmt::Display for KeyName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl FromStr for KeyName {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"s3:x-amz-copy-source" => Ok(KeyName::S3XAmzCopySource),
"s3:x-amz-server-side-encryption" => Ok(KeyName::S3XAmzServerSideEncryption),
"s3:x-amz-server-side-encryption-customer-algorithm" => Ok(KeyName::S3XAmzServerSideEncryptionCustomerAlgorithm),
"s3:x-amz-metadata-directive" => Ok(KeyName::S3XAmzMetadataDirective),
"s3:x-amz-content-sha256" => Ok(KeyName::S3XAmzContentSha256),
"s3:x-amz-storage-class" => Ok(KeyName::S3XAmzStorageClass),
"s3:x-amz-server-side-encryption-aws-kms-key-id" => Ok(KeyName::S3XAmzServerSideEncryptionAwsKmsKeyID),
"s3:LocationConstraint" => Ok(KeyName::S3LocationConstraint),
"s3:prefix" => Ok(KeyName::S3Prefix),
"s3:delimiter" => Ok(KeyName::S3Delimiter),
"s3:versionid" => Ok(KeyName::S3VersionID),
"s3:max-keys" => Ok(KeyName::S3MaxKeys),
"s3:object-lock-remaining-retention-days" => Ok(KeyName::S3ObjectLockRemainingRetentionDays),
"s3:object-lock-mode" => Ok(KeyName::S3ObjectLockMode),
"s3:object-lock-retain-until-date" => Ok(KeyName::S3ObjectLockRetainUntilDate),
"s3:object-lock-legal-hold" => Ok(KeyName::S3ObjectLockLegalHold),
"aws:Referer" => Ok(KeyName::AWSReferer),
"aws:SourceIp" => Ok(KeyName::AWSSourceIP),
"aws:UserAgent" => Ok(KeyName::AWSUserAgent),
"aws:SecureTransport" => Ok(KeyName::AWSSecureTransport),
"aws:CurrentTime" => Ok(KeyName::AWSCurrentTime),
"aws:EpochTime" => Ok(KeyName::AWSEpochTime),
"aws:principaltype" => Ok(KeyName::AWSPrincipalType),
"aws:userid" => Ok(KeyName::AWSUserID),
"aws:username" => Ok(KeyName::AWSUsername),
"aws:groups" => Ok(KeyName::AWSGroups),
"s3:signatureversion" => Ok(KeyName::S3SignatureVersion),
"s3:signatureAge" => Ok(KeyName::S3SignatureAge),
"s3:authType" => Ok(KeyName::S3AuthType),
"s3:ExistingObjectTag" => Ok(KeyName::ExistingObjectTag),
"s3:RequestObjectTagKeys" => Ok(KeyName::RequestObjectTagKeys),
"s3:RequestObjectTag" => Ok(KeyName::RequestObjectTag),
"jwt:sub" => Ok(KeyName::JWTSub),
"jwt:iss" => Ok(KeyName::JWTIss),
"jwt:aud" => Ok(KeyName::JWTAud),
"jwt:jti" => Ok(KeyName::JWTJti),
"jwt:upn" => Ok(KeyName::JWTUpn),
"jwt:name" => Ok(KeyName::JWTName),
"jwt:groups" => Ok(KeyName::JWTGroups),
"jwt:given_name" => Ok(KeyName::JWTGivenName),
"jwt:family_name" => Ok(KeyName::JWTFamilyName),
"jwt:middle_name" => Ok(KeyName::JWTMiddleName),
"jwt:nickname" => Ok(KeyName::JWTNickName),
"jwt:preferred_username" => Ok(KeyName::JWTPrefUsername),
"jwt:profile" => Ok(KeyName::JWTProfile),
"jwt:picture" => Ok(KeyName::JWTPicture),
"jwt:website" => Ok(KeyName::JWTWebsite),
"jwt:email" => Ok(KeyName::JWTEmail),
"jwt:gender" => Ok(KeyName::JWTGender),
"jwt:birthdate" => Ok(KeyName::JWTBirthdate),
"jwt:phone_number" => Ok(KeyName::JWTPhoneNumber),
"jwt:address" => Ok(KeyName::JWTAddress),
"jwt:scope" => Ok(KeyName::JWTScope),
"jwt:client_id" => Ok(KeyName::JWTClientID),
"ldap:user" => Ok(KeyName::LDAPUser),
"ldap:username" => Ok(KeyName::LDAPUsername),
"ldap:groups" => Ok(KeyName::LDAPGroups),
"sts:DurationSeconds" => Ok(KeyName::STSDurationSeconds),
"svc:DurationSeconds" => Ok(KeyName::SVCDurationSeconds),
_ => Err(Error::msg(format!("keyname not found: {}", s))),
}
}
}

View File

@@ -1,4 +0,0 @@
pub mod function;
pub mod key;
pub mod keyname;
pub mod name;

View File

@@ -1,75 +0,0 @@
// 定义Name枚举类型
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Name {
StringEquals,
StringNotEquals,
StringEqualsIgnoreCase,
StringNotEqualsIgnoreCase,
StringLike,
StringNotLike,
BinaryEquals,
IpAddress,
NotIpAddress,
Null,
Bool,
NumericEquals,
NumericNotEquals,
NumericLessThan,
NumericLessThanEquals,
NumericGreaterThan,
NumericGreaterThanIfExists,
NumericGreaterThanEquals,
DateEquals,
DateNotEquals,
DateLessThan,
DateLessThanEquals,
DateGreaterThan,
DateGreaterThanEquals,
ForAllValues,
ForAnyValue,
}
impl Name {
pub fn as_str(&self) -> &'static str {
match self {
Name::StringEquals => "StringEquals",
Name::StringNotEquals => "StringNotEquals",
Name::StringEqualsIgnoreCase => "StringEqualsIgnoreCase",
Name::StringNotEqualsIgnoreCase => "StringNotEqualsIgnoreCase",
Name::StringLike => "StringLike",
Name::StringNotLike => "StringNotLike",
Name::BinaryEquals => "BinaryEquals",
Name::IpAddress => "IpAddress",
Name::NotIpAddress => "NotIpAddress",
Name::Null => "Null",
Name::Bool => "Bool",
Name::NumericEquals => "NumericEquals",
Name::NumericNotEquals => "NumericNotEquals",
Name::NumericLessThan => "NumericLessThan",
Name::NumericLessThanEquals => "NumericLessThanEquals",
Name::NumericGreaterThan => "NumericGreaterThan",
Name::NumericGreaterThanIfExists => "NumericGreaterThanIfExists",
Name::NumericGreaterThanEquals => "NumericGreaterThanEquals",
Name::DateEquals => "DateEquals",
Name::DateNotEquals => "DateNotEquals",
Name::DateLessThan => "DateLessThan",
Name::DateLessThanEquals => "DateLessThanEquals",
Name::DateGreaterThan => "DateGreaterThan",
Name::DateGreaterThanEquals => "DateGreaterThanEquals",
Name::ForAllValues => "ForAllValues",
Name::ForAnyValue => "ForAnyValue",
}
}
}
// impl ToString for Name {
// fn to_string(&self) -> String {
// self.as_str().to_string()
// }
// }
impl std::fmt::Display for Name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}

View File

@@ -1,40 +0,0 @@
use serde::{Deserialize, Serialize};
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)]
#[serde(rename_all = "PascalCase")]
pub enum Effect {
#[default]
Allow,
Deny,
}
impl Effect {
pub fn is_allowed(self, b: bool) -> bool {
if self == Effect::Allow {
b
} else {
!b
}
}
pub fn is_valid(self) -> bool {
match self {
Effect::Allow => true,
Effect::Deny => true,
}
}
}
// 实现从字符串解析Effect的功能
impl FromStr for Effect {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Allow" => Ok(Effect::Allow),
"Deny" => Ok(Effect::Deny),
_ => Err(()),
}
}
}

View File

@@ -1,103 +0,0 @@
// use std::collections::HashMap;
// use action::Action;
// use s3s_policy::model::{Effect, Policy, Principal, PrincipalRule, Statement};
// use serde::{Deserialize, Serialize};
// use tower::ready_cache::cache::Equivalent;
// use crate::utils::wildcard;
pub mod action;
pub mod bucket_policy;
pub mod condition;
pub mod effect;
pub mod principal;
pub mod resource;
// #[derive(Debug, Deserialize, Serialize, Default, Clone)]
// pub struct BucketPolicyArgs {
// pub account_name: String,
// pub groups: Vec<String>,
// pub action: Action,
// pub bucket_name: String,
// pub condition_values: HashMap<String, Vec<String>>,
// pub is_owner: bool,
// pub object_name: String,
// }
// pub trait AllowApi {
// fn is_allowed(&self, args: &BucketPolicyArgs) -> bool;
// }
// pub trait MatchApi {
// fn is_match(&self, found: &str) -> bool;
// }
// impl AllowApi for Policy {
// fn is_allowed(&self, args: &BucketPolicyArgs) -> bool {
// for statement in self.statement.as_slice().iter() {
// if statement.effect == Effect::Deny {
// if !statement.is_allowed(args) {
// return false;
// }
// }
// }
// false
// }
// }
// impl AllowApi for Statement {
// fn is_allowed(&self, args: &BucketPolicyArgs) -> bool {
// let check = || -> bool {
// if let Some(principal) = &self.principal {
// if !principal.is_match(&args.account_name) {
// return false;
// }
// }
// false
// };
// self.effect.is_allowed(check())
// }
// }
// impl MatchApi for PrincipalRule {
// fn is_match(&self, found: &str) -> bool {
// match self {
// PrincipalRule::Principal(principal) => match principal {
// Principal::Wildcard => return true,
// Principal::Map(index_map) => {
// if let Some(keys) = index_map.get("AWS") {
// for key in keys.as_slice() {
// if wildcard::match_simple(key, found) {
// return true;
// }
// }
// }
// return false;
// }
// },
// PrincipalRule::NotPrincipal(principal) => match principal {
// Principal::Wildcard => return true,
// Principal::Map(index_map) => todo!(),
// },
// }
// false
// }
// }
// trait EffectApi {
// fn is_allowed(&self, b: bool) -> bool;
// }
// impl EffectApi for Effect {
// fn is_allowed(&self, b: bool) -> bool {
// if self == &Effect::Allow {
// b
// } else {
// !b
// }
// }
// }

View File

@@ -1,25 +0,0 @@
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use crate::utils;
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
#[serde(rename_all = "PascalCase", default)]
pub struct Principal {
#[serde(rename = "AWS")]
aws: HashSet<String>,
}
impl Principal {
pub fn is_valid(&self) -> bool {
!self.aws.is_empty()
}
pub fn is_match(&self, parincipal: &str) -> bool {
for pattern in self.aws.iter() {
if utils::wildcard::match_simple(pattern, parincipal) {
return true;
}
}
false
}
}

View File

@@ -1,263 +0,0 @@
use crate::{
bucket::policy::condition::keyname::COMMOM_KEYS,
utils::{self, wildcard},
};
use common::error::{Error, Result};
use core::fmt;
use serde::{Deserialize, Serialize};
use std::{
collections::{HashMap, HashSet},
str::FromStr,
};
// 定义ResourceARNType枚举类型
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, Default)]
pub enum ResourceARNType {
#[default]
UnknownARN,
ResourceARNS3,
ResourceARNKMS,
}
impl fmt::Display for ResourceARNType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ResourceARNType::UnknownARN => write!(f, ""),
ResourceARNType::ResourceARNS3 => write!(f, "{}", RESOURCE_ARN_PREFIX),
ResourceARNType::ResourceARNKMS => write!(f, "{}", RESOURCE_ARN_KMS_PREFIX),
}
}
}
// 定义资源ARN前缀
const RESOURCE_ARN_PREFIX: &str = "arn:aws:s3:::";
const RESOURCE_ARN_KMS_PREFIX: &str = "arn:rustfs:kms::::";
// 定义Resource结构体
#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
pub struct Resource {
pattern: String,
rtype: ResourceARNType,
}
impl Resource {
pub fn new(pattern: &str) -> Self {
Self {
pattern: pattern.to_owned(),
rtype: ResourceARNType::ResourceARNS3,
}
}
pub fn validate_bucket(&self, bucket: &str) -> Result<()> {
self.validate()?;
if !wildcard::match_pattern(&self.pattern, bucket)
&& !wildcard::match_as_pattern_prefix(&self.pattern, format!("{}/", bucket).as_str())
{
return Err(Error::msg("bucket name does not match"));
}
Ok(())
}
pub fn validate(&self) -> Result<()> {
if !self.is_valid() {
Err(Error::msg("invalid resource"))
} else {
Ok(())
}
}
pub fn is_valid(&self) -> bool {
if self.rtype == ResourceARNType::UnknownARN {
return false;
}
if self.is_s3() && self.pattern.starts_with('/') {
return false;
}
if self.is_kms() && self.pattern.as_bytes().iter().any(|&v| v == b'/' || v == b'\\' || v == b'.') {
return false;
}
!self.pattern.is_empty()
}
pub fn is_s3(&self) -> bool {
self.rtype == ResourceARNType::ResourceARNS3
}
pub fn is_kms(&self) -> bool {
self.rtype == ResourceARNType::ResourceARNKMS
}
pub fn is_bucket_pattern(&self) -> bool {
!self.pattern.contains('/') || self.pattern.eq("*")
}
pub fn is_object_pattern(&self) -> bool {
self.pattern.contains('/') || self.pattern.contains('*')
}
pub fn is_match(&self, res: &str, condition_values: &HashMap<String, Vec<String>>) -> bool {
let mut pattern = res.to_string();
if !condition_values.is_empty() {
for key in COMMOM_KEYS.iter() {
if let Some(vals) = condition_values.get(key.name()) {
if let Some(v0) = vals.first() {
pattern = pattern.replace(key.name(), v0);
}
}
}
}
let cp = utils::path::clean(res);
if cp != "." && cp == pattern {
return true;
}
wildcard::match_pattern(&pattern, res)
}
}
impl fmt::Display for Resource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{}", self.rtype, self.pattern)
}
}
impl FromStr for Resource {
type Err = serde_json::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.starts_with(RESOURCE_ARN_PREFIX) {
let pattern = {
if let Some(val) = s.strip_prefix(RESOURCE_ARN_PREFIX) {
val.to_string()
} else {
s.to_string()
}
};
Ok(Self {
rtype: ResourceARNType::ResourceARNS3,
pattern,
})
} else if s.starts_with(RESOURCE_ARN_KMS_PREFIX) {
let pattern = {
if let Some(val) = s.strip_prefix(RESOURCE_ARN_KMS_PREFIX) {
val.to_string()
} else {
s.to_string()
}
};
Ok(Self {
rtype: ResourceARNType::ResourceARNS3,
pattern,
})
} else {
Ok(Self {
rtype: ResourceARNType::UnknownARN,
pattern: "".to_string(),
})
}
}
}
impl Serialize for Resource {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.to_string().as_str())
}
}
impl<'de> Deserialize<'de> for Resource {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Visitor;
#[allow(clippy::needless_lifetimes)]
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = Resource;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("string resource")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match Resource::from_str(value) {
Ok(res) => Ok(res),
Err(_) => Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self)),
}
}
}
deserializer.deserialize_any(Visitor)
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(transparent)]
pub struct ResourceSet(pub HashSet<Resource>);
impl ResourceSet {
pub fn validate_bucket(&self, bucket: &str) -> Result<()> {
for res in self.0.iter() {
res.validate_bucket(bucket)?;
}
Ok(())
}
pub fn is_match(&self, res: &str, condition_values: &HashMap<String, Vec<String>>) -> bool {
for item in self.0.iter() {
if item.is_match(res, condition_values) {
return true;
}
}
false
}
pub fn object_resource_exists(&self) -> bool {
for res in self.0.iter() {
if res.is_object_pattern() {
return true;
}
}
false
}
pub fn bucket_resource_exists(&self) -> bool {
for res in self.0.iter() {
if res.is_bucket_pattern() {
return true;
}
}
false
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl AsRef<HashSet<Resource>> for ResourceSet {
fn as_ref(&self) -> &HashSet<Resource> {
&self.0
}
}
// impl Serialize for ResourceSet {
// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
// where
// S: serde::Serializer,
// {
// let ress: Vec<Resource> = self.0.iter().cloned().collect();
// serializer.collect_seq(ress)
// }
// }
// impl<'de> Deserialize<'de> for ResourceSet {
// fn deserialize<D>(deserializer: D) -> Result<ResourceSet, D::Error>
// where
// D: Deserializer<'de>,
// {
// let vec: Vec<Resource> = Deserialize::deserialize(deserializer)?;
// let ha: HashSet<Resource> = vec.into_iter().collect();
// Ok(ResourceSet(ha))
// }
// }

View File

@@ -1,16 +1,13 @@
use super::{
error::BucketMetadataError,
metadata_sys::get_bucket_metadata_sys,
policy::bucket_policy::{BucketPolicy, BucketPolicyArgs},
};
use super::{error::BucketMetadataError, metadata_sys::get_bucket_metadata_sys};
use common::error::Result;
use policy::policy::{BucketPolicy, BucketPolicyArgs};
use tracing::warn;
pub struct PolicySys {}
impl PolicySys {
pub async fn is_allowed(args: &BucketPolicyArgs) -> bool {
match Self::get(&args.bucket_name).await {
pub async fn is_allowed(args: &BucketPolicyArgs<'_>) -> bool {
match Self::get(args.bucket).await {
Ok(cfg) => return cfg.is_allowed(args),
Err(err) => {
if !BucketMetadataError::BucketPolicyNotFound.is(&err) {