rustfs_policy/policy/
statement.rs1use super::{
16 ActionSet, Args, BucketPolicyArgs, Effect, Error as IamError, Functions, ID, Principal, ResourceSet, Validator,
17 action::Action,
18};
19use crate::error::{Error, Result};
20use serde::{Deserialize, Serialize};
21
22#[derive(Serialize, Deserialize, Clone, Default, Debug)]
23pub struct Statement {
24 #[serde(rename = "Sid", default)]
25 pub sid: ID,
26 #[serde(rename = "Effect")]
27 pub effect: Effect,
28 #[serde(rename = "Action")]
29 pub actions: ActionSet,
30 #[serde(rename = "NotAction", default)]
31 pub not_actions: ActionSet,
32 #[serde(rename = "Resource", default)]
33 pub resources: ResourceSet,
34 #[serde(rename = "NotResource", default)]
35 pub not_resources: ResourceSet,
36 #[serde(rename = "Condition", default)]
37 pub conditions: Functions,
38}
39
40impl Statement {
41 fn is_kms(&self) -> bool {
42 for act in self.actions.iter() {
43 if matches!(act, Action::KmsAction(_)) {
44 return true;
45 }
46 }
47
48 false
49 }
50
51 fn is_admin(&self) -> bool {
52 for act in self.actions.iter() {
53 if matches!(act, Action::AdminAction(_)) {
54 return true;
55 }
56 }
57
58 false
59 }
60
61 fn is_sts(&self) -> bool {
62 for act in self.actions.iter() {
63 if matches!(act, Action::StsAction(_)) {
64 return true;
65 }
66 }
67
68 false
69 }
70
71 pub fn is_allowed(&self, args: &Args) -> bool {
72 let check = 'c: {
73 if (!self.actions.is_match(&args.action) && !self.actions.is_empty()) || self.not_actions.is_match(&args.action) {
74 break 'c false;
75 }
76
77 let mut resource = String::from(args.bucket);
78 if !args.object.is_empty() {
79 if !args.object.starts_with('/') {
80 resource.push('/');
81 }
82
83 resource.push_str(args.object);
84 } else {
85 resource.push('/');
86 }
87
88 if self.is_kms() && (resource == "/" || self.resources.is_empty()) {
89 break 'c self.conditions.evaluate(args.conditions);
90 }
91
92 if !self.resources.is_match(&resource, args.conditions) && !self.is_admin() && !self.is_sts() {
93 break 'c false;
94 }
95
96 self.conditions.evaluate(args.conditions)
97 };
98
99 self.effect.is_allowed(check)
100 }
101}
102
103impl Validator for Statement {
104 type Error = Error;
105 fn is_valid(&self) -> Result<()> {
106 self.effect.is_valid()?;
107 self.sid.is_valid()?;
109
110 if self.actions.is_empty() && self.not_actions.is_empty() {
111 return Err(IamError::NonAction.into());
112 }
113
114 if self.resources.is_empty() {
115 return Err(IamError::NonResource.into());
116 }
117
118 self.actions.is_valid()?;
119 self.not_actions.is_valid()?;
120 self.resources.is_valid()?;
121
122 Ok(())
123 }
124}
125
126impl PartialEq for Statement {
127 fn eq(&self, other: &Self) -> bool {
128 self.effect == other.effect
129 && self.actions == other.actions
130 && self.not_actions == other.not_actions
131 && self.resources == other.resources
132 && self.conditions == other.conditions
133 }
134}
135
136#[derive(Debug, Deserialize, Serialize, Default, Clone)]
137#[serde(rename_all = "PascalCase", default)]
138pub struct BPStatement {
139 #[serde(rename = "Sid", default)]
140 pub sid: ID,
141 #[serde(rename = "Effect")]
142 pub effect: Effect,
143 #[serde(rename = "Principal")]
144 pub principal: Principal,
145 #[serde(rename = "Action")]
146 pub actions: ActionSet,
147 #[serde(rename = "NotAction", default)]
148 pub not_actions: ActionSet,
149 #[serde(rename = "Resource", default)]
150 pub resources: ResourceSet,
151 #[serde(rename = "NotResource", default)]
152 pub not_resources: ResourceSet,
153 #[serde(rename = "Condition", default)]
154 pub conditions: Functions,
155}
156
157impl BPStatement {
158 pub fn is_allowed(&self, args: &BucketPolicyArgs) -> bool {
159 let check = 'c: {
160 if !self.principal.is_match(args.account) {
161 break 'c false;
162 }
163
164 if (!self.actions.is_match(&args.action) && !self.actions.is_empty()) || self.not_actions.is_match(&args.action) {
165 break 'c false;
166 }
167
168 let mut resource = String::from(args.bucket);
169 if !args.object.is_empty() {
170 if !args.object.starts_with('/') {
171 resource.push('/');
172 }
173
174 resource.push_str(args.object);
175 } else {
176 resource.push('/');
177 }
178
179 if !self.resources.is_empty() && !self.resources.is_match(&resource, args.conditions) {
180 break 'c false;
181 }
182
183 if !self.not_resources.is_empty() && self.not_resources.is_match(&resource, args.conditions) {
184 break 'c false;
185 }
186
187 self.conditions.evaluate(args.conditions)
188 };
189
190 self.effect.is_allowed(check)
191 }
192}
193
194impl Validator for BPStatement {
195 type Error = Error;
196 fn is_valid(&self) -> Result<()> {
197 self.effect.is_valid()?;
198 self.sid.is_valid()?;
200
201 self.principal.is_valid()?;
202
203 if self.actions.is_empty() && self.not_actions.is_empty() {
204 return Err(IamError::NonAction.into());
205 }
206
207 if self.resources.is_empty() {
208 return Err(IamError::NonResource.into());
209 }
210
211 self.actions.is_valid()?;
212 self.not_actions.is_valid()?;
213 self.resources.is_valid()?;
214
215 Ok(())
216 }
217}