Skip to main content

openauth_plugins/access/
control.rs

1use super::error::AccessError;
2use super::types::{AccessRequest, ResourceRequest, Role, Statements};
3use std::collections::{BTreeMap, BTreeSet};
4
5/// Access-control policy used to create validated roles.
6#[derive(Clone, Debug, Eq, PartialEq)]
7pub struct AccessControl {
8    statements: Statements,
9}
10
11impl AccessControl {
12    /// Create an access-control policy from base statements.
13    pub fn new(statements: Statements) -> Result<Self, AccessError> {
14        Ok(Self { statements })
15    }
16
17    /// Create a role after validating it against the base statements.
18    pub fn new_role(&self, statements: Statements) -> Result<Role, AccessError> {
19        self.validate_role_statements(&statements)?;
20        Ok(Role::new(statements))
21    }
22
23    /// Return the base statements for this access-control policy.
24    pub fn statements(&self) -> &Statements {
25        &self.statements
26    }
27
28    fn validate_role_statements(&self, statements: &Statements) -> Result<(), AccessError> {
29        for (resource, actions) in statements {
30            let allowed_actions =
31                self.statements
32                    .get(resource)
33                    .ok_or_else(|| AccessError::UnknownResource {
34                        resource: resource.clone(),
35                    })?;
36
37            for action in actions {
38                if !allowed_actions.contains(action) {
39                    return Err(AccessError::UnknownAction {
40                        resource: resource.clone(),
41                        action: action.clone(),
42                    });
43                }
44            }
45        }
46
47        Ok(())
48    }
49}
50
51/// Create an access-control policy from base statements.
52pub fn create_access_control(statements: Statements) -> Result<AccessControl, AccessError> {
53    AccessControl::new(statements)
54}
55
56/// Create a role directly from statements.
57pub fn role(statements: Statements) -> Role {
58    Role::new(statements)
59}
60
61/// Build resource-to-actions statements from iterable pairs.
62pub fn statements<I, R, A, S>(entries: I) -> Statements
63where
64    I: IntoIterator<Item = (R, A)>,
65    R: Into<String>,
66    A: IntoIterator<Item = S>,
67    S: Into<String>,
68{
69    entries
70        .into_iter()
71        .map(|(resource, actions)| {
72            (
73                resource.into(),
74                actions.into_iter().map(Into::into).collect::<BTreeSet<_>>(),
75            )
76        })
77        .collect::<BTreeMap<_, _>>()
78}
79
80/// Build an access request where each resource requires all listed actions.
81pub fn request<I, R, A, S>(entries: I) -> AccessRequest
82where
83    I: IntoIterator<Item = (R, A)>,
84    R: Into<String>,
85    A: IntoIterator<Item = S>,
86    S: Into<String>,
87{
88    entries
89        .into_iter()
90        .map(|(resource, actions)| (resource.into(), ResourceRequest::all(actions)))
91        .collect()
92}