auth_policy/
request.rs

1use std::collections::HashMap;
2
3/// Authorization request under evaluation.
4#[derive(Debug, Default, Clone)]
5pub struct Request {
6    action: String,
7    actor_attrs: HashMap<String, String>,
8    resource_attrs: HashMap<String, String>,
9    environment_attrs: HashMap<String, String>,
10}
11
12impl Request {
13    /// Create an empty request.
14    pub fn new() -> Self {
15        Self::default()
16    }
17
18    /// Set the action verb for the request.
19    pub fn action(mut self, action: impl Into<String>) -> Self {
20        self.action = action.into();
21        self
22    }
23
24    /// Add an attribute that belongs to the actor (subject) performing the request.
25    pub fn actor_attr(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
26        self.actor_attrs.insert(key.into(), value.into());
27        self
28    }
29
30    /// Add an attribute belonging to the resource being accessed.
31    pub fn resource_attr(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
32        self.resource_attrs.insert(key.into(), value.into());
33        self
34    }
35
36    /// Add an attribute describing the surrounding environment (time, IP, etc.).
37    pub fn environment_attr(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
38        self.environment_attrs.insert(key.into(), value.into());
39        self
40    }
41
42    /// Return the configured action, if any.
43    pub fn action_name(&self) -> &str {
44        &self.action
45    }
46
47    pub(crate) fn lookup(&self, namespace: &str, key: Option<&str>) -> Option<&str> {
48        match namespace {
49            "actor" => key.and_then(|k| self.actor_attrs.get(k)).map(String::as_str),
50            "resource" => key
51                .and_then(|k| self.resource_attrs.get(k))
52                .map(String::as_str),
53            "environment" => key
54                .and_then(|k| self.environment_attrs.get(k))
55                .map(String::as_str),
56            "action" => {
57                if let Some("name") | Some("id") = key {
58                    Some(self.action.as_str())
59                } else if key.is_none() {
60                    Some(self.action.as_str())
61                } else {
62                    None
63                }
64            }
65            _ => None,
66        }
67    }
68}