manas_access_control/model/pdp/
mod.rs

1//! I define interfaces and implementations for access control
2//! policy-decision-points.
3//!
4
5use std::{collections::HashSet, fmt::Debug, ops::Deref, sync::Arc};
6
7use acp::model::{access_mode::HAccessMode, attribute::HAttribute, context::DContext};
8use dyn_problem::{define_anon_problem_types, ProbFuture};
9use http_uri::invariant::NormalAbsoluteHttpUri;
10use itertools::Itertools;
11use manas_space::{resource::slot::SolidResourceSlot, SolidStorageSpace};
12use rdf_utils::model::{
13    graph::{InfallibleGraph, InfallibleMutableGraph},
14    handle::Handle,
15    term::ArcTerm,
16};
17use sophia_api::term::Term;
18
19use super::AccessGrantSet;
20use crate::model::prp::SlotAcrChain;
21
22pub mod impl_;
23
24/// A struct to represent access grant response.
25#[derive(Debug, Clone)]
26pub struct AccessGrantResponse<Space: SolidStorageSpace> {
27    /// Slot of the resource. [`None`] implies resource
28    /// doesn't exist.
29    pub res_slot: Option<SolidResourceSlot<Space>>,
30
31    /// Resolved access grant set on the resource.
32    pub access_grant_set: AccessGrantSet,
33}
34
35/// A trait for access control policy decision points.
36/// A pdp is a centralized point which resolves decisions
37/// regarding access to resources in a storage space.
38///
39pub trait PolicyDecisionPoint: Debug + Send + Sync + 'static {
40    /// Type of solid storage space.
41    type StSpace: SolidStorageSpace;
42
43    /// Type of graphs.
44    type Graph: InfallibleMutableGraph + Default + Send + Sync + 'static;
45
46    /// Get the slice of access modes supported by this pdp.
47    fn supported_access_modes(&self) -> &HashSet<HAccessMode<ArcTerm>>;
48
49    /// Get the slice of attributes supported by this pdp.
50    fn supported_attrs(&self) -> &HashSet<HAttribute<ArcTerm>>;
51
52    /// Resolve the granted access modes for given access context.
53    fn resolve_grants(
54        &self,
55        context: ResourceAccessContext<Self::Graph>,
56        acr_chain: SlotAcrChain<Self::StSpace, Self::Graph, Arc<Self::Graph>>,
57    ) -> ProbFuture<'static, AccessGrantResponse<Self::StSpace>>;
58}
59
60/// A struct to represent resource access context.
61pub struct ResourceAccessContext<G: InfallibleGraph> {
62    target_uri: NormalAbsoluteHttpUri,
63    inner: DContext<G, G>,
64}
65
66impl<G: InfallibleGraph> TryFrom<DContext<G, G>> for ResourceAccessContext<G> {
67    type Error = InvalidTargetAttribute;
68
69    fn try_from(context: DContext<G, G>) -> Result<Self, Self::Error> {
70        // Get handle to the target resource.
71        let h_target = context
72            .h_target::<ArcTerm>()
73            .exactly_one()
74            .map_err(|_| InvalidTargetAttribute::InvalidCardinality)?;
75
76        // Get target resource uri.
77        let target_uri = h_target
78            .as_term()
79            .iri()
80            .and_then(|iri| NormalAbsoluteHttpUri::try_new_from(iri.as_str()).ok())
81            .ok_or(InvalidTargetAttribute::UriIsNotNormalAbsolute)?;
82
83        Ok(Self {
84            target_uri,
85            inner: context,
86        })
87    }
88}
89
90impl<G: InfallibleGraph> Deref for ResourceAccessContext<G> {
91    type Target = DContext<G, G>;
92
93    #[inline]
94    fn deref(&self) -> &Self::Target {
95        &self.inner
96    }
97}
98
99impl<G: InfallibleGraph> ResourceAccessContext<G> {
100    /// Create a new access context with out checks.
101    /// Caller must ensure that inner context has
102    /// matching target uri.
103    #[inline]
104    pub(crate) fn new_unchecked(target_uri: NormalAbsoluteHttpUri, inner: DContext<G, G>) -> Self {
105        Self { target_uri, inner }
106    }
107
108    /// Get access target uri.
109    #[inline]
110    pub fn target_uri(&self) -> &NormalAbsoluteHttpUri {
111        &self.target_uri
112    }
113
114    /// Convert into inner access context.
115    #[inline]
116    pub fn into_inner(self) -> DContext<G, G> {
117        self.inner
118    }
119}
120
121/// Invalid  `acp:target`  attribute in access context graph.
122#[derive(Debug, thiserror::Error)]
123pub enum InvalidTargetAttribute {
124    /// Invalid cardinality of `acp:target` in access context graph.
125    #[error("Invalid cardinality of `acp:target` in access context graph.")]
126    InvalidCardinality,
127
128    /// acp:target attribute value is not a normal absolute http uri.
129    #[error("acp:target attribute value is not a normal absolute http uri.")]
130    UriIsNotNormalAbsolute,
131}
132
133define_anon_problem_types!(
134    /// Unknown target resource.
135    UNKNOWN_TARGET_RESOURCE: (
136        "Unknown target resource."
137    );
138
139    /// Invalid prp response.
140    INVALID_PRP_RESPONSE: (
141        "Invalid prp response."
142    );
143);