1use std::cmp::Ordering;
2use std::collections::HashSet;
3use std::fmt::{Display, Formatter};
4use std::hash::{Hash, Hasher};
5
6#[derive(Debug, Clone)]
7pub enum AuthorizationExpression {
8 ConjunctionOf(Vec<AuthorizationExpression>),
10 DisjunctionOf(Vec<AuthorizationExpression>),
12 AccessToken(String),
14 Nil
16}
17
18impl Hash for AuthorizationExpression {
19 fn hash<H: Hasher>(&self, state: &mut H) {
20 match self {
21 AuthorizationExpression::ConjunctionOf(nodes) => {
22 let mut sorted = nodes.clone();
23 sorted.sort();
24 state.write_u8(0);
25 sorted.hash(state);
26 }
27 AuthorizationExpression::DisjunctionOf(nodes) => {
28 let mut sorted = nodes.clone();
29 sorted.sort();
30 state.write_u8(1);
31 sorted.hash(state);
32 }
33 AuthorizationExpression::AccessToken(token) => {
34 state.write_u8(2);
35 token.hash(state);
36 }
37 AuthorizationExpression::Nil => {
38 state.write_u8(3);
39 }
40 }
41 }
42}
43
44impl Ord for AuthorizationExpression {
45 fn cmp(&self, other: &Self) -> Ordering {
46 match (self, other) {
47 (AuthorizationExpression::ConjunctionOf(a), AuthorizationExpression::DisjunctionOf(b)) => a.cmp(b),
48 (AuthorizationExpression::DisjunctionOf(a), AuthorizationExpression::ConjunctionOf(b)) => a.cmp(b),
49 (AuthorizationExpression::ConjunctionOf(a), AuthorizationExpression::ConjunctionOf(b)) => a.cmp(b),
50 (AuthorizationExpression::DisjunctionOf(a), AuthorizationExpression::DisjunctionOf(b)) => a.cmp(b),
51 (AuthorizationExpression::AccessToken(a), AuthorizationExpression::AccessToken(b)) => a.cmp(b),
52 (AuthorizationExpression::AccessToken(_), _) => Ordering::Greater,
53 (AuthorizationExpression::ConjunctionOf(_), AuthorizationExpression::AccessToken(_)) => Ordering::Less,
54 (AuthorizationExpression::DisjunctionOf(_), AuthorizationExpression::AccessToken(_)) => Ordering::Less,
55 (_, AuthorizationExpression::AccessToken(_)) => Ordering::Less,
56 (_, AuthorizationExpression::Nil) => Ordering::Equal,
57 (AuthorizationExpression::Nil, _) => Ordering::Equal
58 }
59 }
60}
61
62impl PartialOrd for AuthorizationExpression {
63 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
64 Some(self.cmp(other))
65 }
66}
67
68impl Eq for AuthorizationExpression {}
69
70impl PartialEq for AuthorizationExpression {
71 fn eq(&self, other: &Self) -> bool {
72 match (self, other) {
73 (AuthorizationExpression::ConjunctionOf(a), AuthorizationExpression::ConjunctionOf(b)) => {
74 let self_set: HashSet<_> = a.iter().collect();
75 let other_set: HashSet<_> = b.iter().collect();
76 self_set == other_set
77 },
78 (AuthorizationExpression::DisjunctionOf(a), AuthorizationExpression::DisjunctionOf(b)) => {
79 let self_set: HashSet<_> = a.iter().collect();
80 let other_set: HashSet<_> = b.iter().collect();
81 self_set == other_set
82 },
83 (AuthorizationExpression::AccessToken(a), AuthorizationExpression::AccessToken(b)) => a == b,
84 (AuthorizationExpression::Nil, AuthorizationExpression::Nil) => true,
85 _ => false,
86 }
87 }
88}
89
90impl Display for AuthorizationExpression {
91 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
92 f.write_str(self.to_expression_str().as_str())
93 }
94}
95
96impl AuthorizationExpression {
97 pub fn from_json(json: &serde_json::Value) -> Result<Self, String> {
122 match json {
123 serde_json::Value::Object(obj) => {
124 if obj.contains_key("and") {
125 let and = obj.get("and").unwrap().as_array().unwrap();
126 let mut nodes = Vec::new();
127 for node in and {
128 nodes.push(AuthorizationExpression::from_json(node)?);
129 }
130 Ok(AuthorizationExpression::ConjunctionOf(nodes))
131 } else if obj.contains_key("or") {
132 let or = obj.get("or").unwrap().as_array().unwrap();
133 let mut nodes = Vec::new();
134 for node in or {
135 nodes.push(AuthorizationExpression::from_json(node)?);
136 }
137 Ok(AuthorizationExpression::DisjunctionOf(nodes))
138 } else {
139 Err("Invalid JSON object".to_string())
140 }
141 }
142 serde_json::Value::String(token) => Ok(AuthorizationExpression::AccessToken(token.to_string())),
143 _ => Err("Invalid JSON value".to_string()),
144 }
145 }
146
147 pub fn evaluate(&self, authorizations: &HashSet<String>) -> bool {
171 match self {
172 AuthorizationExpression::Nil => true,
173
174 AuthorizationExpression::ConjunctionOf(nodes) =>
175 nodes.iter().all(|node| node.evaluate(authorizations)),
176
177 AuthorizationExpression::DisjunctionOf(nodes) =>
178 nodes.iter().any(|node| node.evaluate(authorizations)),
179
180 AuthorizationExpression::AccessToken(token) => authorizations.contains(token),
181 }
182 }
183
184
185 pub fn to_json(&self) -> serde_json::Value {
200 match self {
201 AuthorizationExpression::Nil => serde_json::Value::Null,
202 AuthorizationExpression::ConjunctionOf(nodes) => {
203 let mut json = serde_json::json!({"and": []});
204 let and = json.as_object_mut().unwrap().get_mut("and").unwrap();
205 for node in nodes {
206 and.as_array_mut().unwrap().push(node.to_json());
207 }
208 json
209 }
210 AuthorizationExpression::DisjunctionOf(nodes) => {
211 let mut json = serde_json::json!({"or": []});
212 let or = json.as_object_mut().unwrap().get_mut("or").unwrap();
213 for node in nodes {
214 or.as_array_mut().unwrap().push(node.to_json());
215 }
216 json
217 }
218 AuthorizationExpression::AccessToken(token) => serde_json::json!(token),
219 }
220 }
221
222 pub fn to_json_str(&self) -> String {
238 self.to_json().to_string()
239 }
240
241 pub fn to_expression_str(&self) -> String {
265 match self {
267 AuthorizationExpression::Nil => String::new(),
268 AuthorizationExpression::ConjunctionOf(nodes) => {
269 let mut expression = String::new();
270 for node in nodes {
271 expression.push_str(&node.to_expression_str());
272 expression.push('&');
273 }
274 expression.pop();
275 expression
276 }
277 AuthorizationExpression::DisjunctionOf(nodes) => {
278 let mut expression = String::new();
279 for node in nodes {
280 expression.push_str(&node.to_expression_str());
281 expression.push('|');
282 }
283 expression.pop();
284 expression
285 }
286 AuthorizationExpression::AccessToken(token) => token.clone(),
287 }
288 }
289
290 pub fn normalize(&mut self) {
315 match self {
316 AuthorizationExpression::Nil => {},
317
318 AuthorizationExpression::ConjunctionOf(nodes) => {
319 nodes.sort();
320 nodes.dedup();
321 for node in nodes {
322 node.normalize();
323 }
324 }
325 AuthorizationExpression::DisjunctionOf(nodes) => {
326 nodes.sort();
327 nodes.dedup();
328 for node in nodes {
329 node.normalize();
330 }
331 }
332 AuthorizationExpression::AccessToken(_) => {}
333 }
334 }
335}
336
337#[cfg(test)]
339mod tests {
340 use super::*;
341
342 #[test]
343 fn some_basic_equality_and_ordering_tests() {
344 assert_eq!(AuthorizationExpression::AccessToken("A".to_string()), AuthorizationExpression::AccessToken("A".to_string()));
345 assert_ne!(AuthorizationExpression::AccessToken("A".to_string()), AuthorizationExpression::AccessToken("B".to_string()));
346
347 assert_eq!(AuthorizationExpression::ConjunctionOf(vec![
348 AuthorizationExpression::AccessToken("A".to_string()),
349 AuthorizationExpression::AccessToken("B".to_string()),
350 ]), AuthorizationExpression::ConjunctionOf(vec![
351 AuthorizationExpression::AccessToken("B".to_string()),
352 AuthorizationExpression::AccessToken("A".to_string()),
353 ]));
354
355 assert_eq!(AuthorizationExpression::DisjunctionOf(vec![
356 AuthorizationExpression::AccessToken("A".to_string()),
357 AuthorizationExpression::AccessToken("B".to_string()),
358 ]), AuthorizationExpression::DisjunctionOf(vec![
359 AuthorizationExpression::AccessToken("B".to_string()),
360 AuthorizationExpression::AccessToken("A".to_string()),
361 ]));
362 }
363
364 #[test]
365 fn new_expr_from_json() {
366 let json = serde_json::json!({
367 "and": [
368 "A",
369 {
370 "or": [
371 "B",
372 "C"
373 ]
374 }
375 ]
376 });
377 let expr = AuthorizationExpression::from_json(&json).unwrap();
378 assert_eq!(expr, AuthorizationExpression::ConjunctionOf(vec![
379 AuthorizationExpression::AccessToken("A".to_string()),
380 AuthorizationExpression::DisjunctionOf(vec![
381 AuthorizationExpression::AccessToken("B".to_string()),
382 AuthorizationExpression::AccessToken("C".to_string()),
383 ]),
384 ]));
385 }
386
387 #[test]
388 fn test_normalize1() {
389 let mut expr = AuthorizationExpression::ConjunctionOf(vec![
390 AuthorizationExpression::AccessToken("B".to_string()),
391 AuthorizationExpression::AccessToken("A".to_string()),
392 AuthorizationExpression::AccessToken("B".to_string()),
393 AuthorizationExpression::AccessToken("B".to_string()),
394 AuthorizationExpression::DisjunctionOf(vec![
395 AuthorizationExpression::AccessToken("C".to_string()),
396 AuthorizationExpression::AccessToken("D".to_string()),
397 AuthorizationExpression::AccessToken("D".to_string()),
398 AuthorizationExpression::AccessToken("D".to_string()),
399 AuthorizationExpression::AccessToken("D".to_string()),
400 AuthorizationExpression::AccessToken("D".to_string()),
401 ]),
402 ]);
403
404 expr.normalize();
405
406 assert_eq!(expr, AuthorizationExpression::ConjunctionOf(vec![
407 AuthorizationExpression::AccessToken("B".to_string()),
408 AuthorizationExpression::AccessToken("A".to_string()),
409 AuthorizationExpression::DisjunctionOf(vec![
410 AuthorizationExpression::AccessToken("D".to_string()),
411 AuthorizationExpression::AccessToken("C".to_string()),
412 ]),
413 ]));
414 }
415}