mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-21 03:46:37 +00:00
fix: fix bucket policy principal parsing to support * and {AWS: *} fo… (#1354)
Co-authored-by: loverustfs <hello@rustfs.com>
This commit is contained in:
@@ -13,17 +13,67 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use super::{Validator, utils::wildcard};
|
use super::{Validator, utils::wildcard};
|
||||||
use crate::error::{Error, Result};
|
use crate::error::Error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Serialize;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Default, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "PascalCase", default)]
|
#[serde(rename_all = "PascalCase", default)]
|
||||||
pub struct Principal {
|
pub struct Principal {
|
||||||
#[serde(rename = "AWS")]
|
#[serde(rename = "AWS")]
|
||||||
aws: HashSet<String>,
|
aws: HashSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum PrincipalFormat {
|
||||||
|
Wildcard(String),
|
||||||
|
AwsObject(PrincipalAwsObject),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct PrincipalAwsObject {
|
||||||
|
#[serde(rename = "AWS")]
|
||||||
|
aws: AwsValues,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum AwsValues {
|
||||||
|
Single(String),
|
||||||
|
Multiple(HashSet<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for Principal {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let format = PrincipalFormat::deserialize(deserializer)?;
|
||||||
|
match format {
|
||||||
|
PrincipalFormat::Wildcard(s) => {
|
||||||
|
if s == "*" {
|
||||||
|
Ok(Principal {
|
||||||
|
aws: HashSet::from(["*".to_string()]),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(serde::de::Error::custom(format!(
|
||||||
|
"invalid wildcard principal value: expected \"*\", got \"{}\"",
|
||||||
|
s
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrincipalFormat::AwsObject(obj) => {
|
||||||
|
let aws = match obj.aws {
|
||||||
|
AwsValues::Single(s) => HashSet::from([s]),
|
||||||
|
AwsValues::Multiple(set) => set,
|
||||||
|
};
|
||||||
|
Ok(Principal { aws })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Principal {
|
impl Principal {
|
||||||
pub fn is_match(&self, parincipal: &str) -> bool {
|
pub fn is_match(&self, parincipal: &str) -> bool {
|
||||||
for pattern in self.aws.iter() {
|
for pattern in self.aws.iter() {
|
||||||
@@ -37,10 +87,35 @@ impl Principal {
|
|||||||
|
|
||||||
impl Validator for Principal {
|
impl Validator for Principal {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn is_valid(&self) -> Result<()> {
|
fn is_valid(&self) -> Result<(), Error> {
|
||||||
if self.aws.is_empty() {
|
if self.aws.is_empty() {
|
||||||
return Err(Error::other("Principal is empty"));
|
return Err(Error::other("Principal is empty"));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use serde_json;
|
||||||
|
use test_case::test_case;
|
||||||
|
|
||||||
|
#[test_case(r#""*""#, true ; "wildcard_string")]
|
||||||
|
#[test_case(r#"{"AWS": "*"}"#, true ; "aws_object_single_string")]
|
||||||
|
#[test_case(r#"{"AWS": ["*"]}"#, true ; "aws_object_array")]
|
||||||
|
#[test_case(r#""invalid""#, false ; "invalid_string")]
|
||||||
|
#[test_case(r#""""#, false ; "empty_string")]
|
||||||
|
#[test_case(r#"{"Other": "*"}"#, false ; "wrong_field")]
|
||||||
|
#[test_case(r#"{}"#, false ; "empty_object")]
|
||||||
|
fn test_principal_parsing(json: &str, should_succeed: bool) {
|
||||||
|
let result = match serde_json::from_str::<Principal>(json) {
|
||||||
|
Ok(principal) => {
|
||||||
|
assert!(principal.aws.contains("*"));
|
||||||
|
should_succeed
|
||||||
|
}
|
||||||
|
Err(_) => !should_succeed,
|
||||||
|
};
|
||||||
|
assert!(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user