mirror of
https://github.com/rustfs/rustfs.git
synced 2026-01-17 01:30:33 +00:00
ecstore update bucket policy
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1920,6 +1920,7 @@ dependencies = [
|
||||
"path-absolutize",
|
||||
"path-clean",
|
||||
"pin-project-lite",
|
||||
"policy",
|
||||
"protos",
|
||||
"rand 0.8.5",
|
||||
"reed-solomon-erasure",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
pub mod function;
|
||||
pub mod key;
|
||||
pub mod keyname;
|
||||
pub mod name;
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
// }
|
||||
// }
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user