scratchstack_aspen/condition/
arn.rs1use {
2 super::variant::Variant,
3 crate::{eval::regex_from_glob, serutil::StringLikeList, AspenError, Context, PolicyVersion},
4 log::trace,
5 scratchstack_arn::Arn,
6 scratchstack_aws_principal::SessionValue,
7 std::str::FromStr,
8};
9
10#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
11#[repr(u8)]
12pub enum ArnCmp {
13 Equals = 0,
14 Like = 4,
15}
16
17impl ArnCmp {
18 pub(super) fn display_name(&self, variant: &Variant) -> &'static str {
19 ARN_DISPLAY_NAMES[*self as usize | variant.as_usize()]
20 }
21}
22
23const ARN_DISPLAY_NAMES: [&str; 8] = [
28 "ArnEquals",
29 "ArnEqualsIfExists",
30 "ArnNotEquals",
31 "ArnNotEqualsIfExists",
32 "ArnLike",
33 "ArnLikeIfExists",
34 "ArnNotLike",
35 "ArnNotLikeIfExists",
36];
37
38pub(super) fn arn_match(
39 context: &Context,
40 pv: PolicyVersion,
41 allowed: &StringLikeList<String>,
42 value: &SessionValue,
43 _cmp: ArnCmp, variant: Variant,
45) -> Result<bool, AspenError> {
46 match value {
47 SessionValue::Null => Ok(variant.if_exists()),
48 SessionValue::String(value) => {
49 match Arn::from_str(value) {
50 Err(_) => {
51 Ok(variant.negated())
54 }
55 Ok(value) => {
56 for el in allowed.iter() {
57 let parts = el.splitn(6, ':').collect::<Vec<&str>>();
58 if parts.len() != 6 || parts[0] != "arn" {
59 continue;
60 }
61
62 let partition = regex_from_glob(parts[1], false);
63 let service = regex_from_glob(parts[2], false);
64 let region = regex_from_glob(parts[3], false);
65 let account_id = regex_from_glob(parts[4], false);
66 let resource = context.matcher(parts[5], pv, false)?;
67
68 trace!(
69 "partition={} service={} region={} account_id={} resource={}",
70 partition,
71 service,
72 region,
73 account_id,
74 resource
75 );
76 trace!("value={}", value);
77
78 let is_match = partition.is_match(value.partition())
79 && service.is_match(value.service())
80 && region.is_match(value.region())
81 && account_id.is_match(value.account_id())
82 && resource.is_match(value.resource());
83 if is_match != variant.negated() {
84 return Ok(true);
85 }
86 }
87
88 Ok(false)
89 }
90 }
91 }
92 _ => Ok(false),
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use {super::ArnCmp, pretty_assertions::assert_eq};
99
100 #[test_log::test]
101 fn test_clone() {
102 assert_eq!(ArnCmp::Equals.clone(), ArnCmp::Equals);
103 assert_eq!(ArnCmp::Like.clone(), ArnCmp::Like);
104 }
105}