Skip to main content

openauth_plugins/access/
authorize.rs

1use super::error::AccessError;
2use super::types::{AccessRequest, Connector, ResourceRequest, Role};
3
4impl Role {
5    /// Authorize a request requiring every requested resource to pass.
6    pub fn authorize_all(&self, request: AccessRequest) -> Result<(), AccessError> {
7        self.authorize(request, Connector::And)
8    }
9
10    /// Authorize a request requiring at least one requested resource to pass.
11    pub fn authorize_any(&self, request: AccessRequest) -> Result<(), AccessError> {
12        self.authorize(request, Connector::Or)
13    }
14
15    /// Authorize a request against this role's statements.
16    pub fn authorize(
17        &self,
18        request: AccessRequest,
19        connector: Connector,
20    ) -> Result<(), AccessError> {
21        if request.is_empty() {
22            return Err(AccessError::EmptyRequest);
23        }
24
25        for (resource, resource_request) in request {
26            match self.authorize_resource(&resource, &resource_request) {
27                Ok(()) if connector == Connector::Or => return Ok(()),
28                Ok(()) => {}
29                Err(error) if connector == Connector::And => return Err(error),
30                Err(error @ AccessError::ResourceDenied { .. }) => return Err(error),
31                Err(_) => {}
32            }
33        }
34
35        if connector == Connector::Or {
36            Err(AccessError::NotAuthorized)
37        } else {
38            Ok(())
39        }
40    }
41
42    fn authorize_resource(
43        &self,
44        resource: &str,
45        request: &ResourceRequest,
46    ) -> Result<(), AccessError> {
47        let allowed_actions =
48            self.statements
49                .get(resource)
50                .ok_or_else(|| AccessError::ResourceDenied {
51                    resource: resource.to_string(),
52                })?;
53
54        match request.connector() {
55            Connector::And if request.actions().is_subset(allowed_actions) => Ok(()),
56            Connector::Or
57                if request
58                    .actions()
59                    .iter()
60                    .any(|action| allowed_actions.contains(action)) =>
61            {
62                Ok(())
63            }
64            _ => Err(AccessError::UnauthorizedResource {
65                resource: resource.to_string(),
66            }),
67        }
68    }
69}