haste_access_control/
lib.rs1use crate::context::PermissionLevel;
2use haste_fhir_client::FHIRClient;
3use haste_fhir_model::r4::generated::{
4 resources::AccessPolicyV2,
5 terminology::{AccessPolicyv2Engine, IssueType},
6};
7use haste_fhir_operation_error::OperationOutcomeError;
8use std::sync::Arc;
9
10pub mod context;
11mod engine;
12mod request_reflection;
13mod utilities;
14
15pub async fn evaluate_policy<
24 CTX: Send + Sync + Clone + 'static,
25 Client: FHIRClient<CTX, OperationOutcomeError> + Send + Sync + 'static,
26>(
27 context: Arc<context::PolicyContext<CTX, Client>>,
28 policy: Arc<AccessPolicyV2>,
29) -> Result<PermissionLevel, OperationOutcomeError> {
30 match &policy.engine {
31 policy_engine if policy_engine == &AccessPolicyv2Engine::full_access() => {
32 Ok(engine::full_access::evaluate(policy.as_ref()))
33 }
34 policy_engine if policy_engine == &AccessPolicyv2Engine::rule_engine() => {
35 Ok(engine::rule_engine::pdp::evaluate(context, policy).await?)
36 }
37 policy_engine if policy_engine == &AccessPolicyv2Engine::null() => {
38 Err(OperationOutcomeError::fatal(
39 haste_fhir_model::r4::generated::terminology::IssueType::forbidden(),
40 "Access policy denies access.".to_string(),
41 ))
42 }
43 _ => Err(OperationOutcomeError::fatal(
44 haste_fhir_model::r4::generated::terminology::IssueType::invalid(),
45 "Unsupported policy engine.".to_string(),
46 )),
47 }
48}
49
50pub async fn evaluate_policies<
63 CTX: Send + Sync + Clone + 'static,
64 Client: FHIRClient<CTX, OperationOutcomeError> + Send + Sync + 'static,
65>(
66 context: context::PolicyContext<CTX, Client>,
67 policies: &Vec<Arc<AccessPolicyV2>>,
68) -> Result<context::PolicyContext<CTX, Client>, OperationOutcomeError> {
69 let mut outcomes = vec![];
70 let context = Arc::new(context);
71
72 for policy in policies {
73 let result = evaluate_policy(context.clone(), policy.clone()).await;
74 if let Ok(permission) = result {
75 if permission == PermissionLevel::Allow {
76 return Arc::into_inner(context).ok_or_else(|| {
77 OperationOutcomeError::error(
78 IssueType::forbidden(),
79 "Failed to retrieve policy context.".to_string(),
80 )
81 });
82 }
83 } else if let Err(e) = result {
84 outcomes.push(e);
85 }
86 }
87
88 Err(OperationOutcomeError::error(
89 IssueType::forbidden(),
90 "No policy has granted access to your request.".to_string(),
91 ))
92}