use std::collections::BTreeSet;
use cedar_policy::{Effect, RequestEnv, Schema};
use cedar_policy_core::ast::{Policy, PolicySet};
use crate::symcc::{self, factory, term::Term, SymEnv};
use crate::Result;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CompiledPolicy {
pub(super) term: Term,
pub(super) symenv: symcc::SymEnv,
pub(super) policy: Policy,
pub(super) footprint: BTreeSet<Term>,
pub(super) acyclicity: BTreeSet<Term>,
}
impl CompiledPolicy {
pub fn compile(policy: &Policy, env: &RequestEnv, schema: &Schema) -> Result<Self> {
let policy = symcc::well_typed_policy(policy, env, schema)?;
let env = symcc::SymEnv::new(schema, env)?;
let term = symcc::compiler::compile(&policy.condition(), &env)?;
let footprint: BTreeSet<Term> =
symcc::enforcer::footprint(&policy.condition(), &env).collect();
let acyclicity = footprint
.iter()
.map(|term| symcc::enforcer::acyclicity(term, &env.entities))
.collect();
Ok(Self {
term,
symenv: env,
policy,
footprint,
acyclicity,
})
}
pub fn into_compiled_policies(self) -> CompiledPolicies {
CompiledPolicies {
term: match self.policy.effect() {
Effect::Forbid => {
false.into()
}
Effect::Permit => {
factory::eq(self.term, factory::some_of(true.into()))
}
},
symenv: self.symenv,
#[allow(clippy::expect_used)]
policies: PolicySet::try_from_iter([self.policy])
.expect("constructing a singleton policyset should not fail"),
footprint: self.footprint, acyclicity: self.acyclicity, }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CompiledPolicies {
pub(super) term: Term,
pub(super) symenv: symcc::SymEnv,
pub(super) policies: PolicySet,
pub(super) footprint: BTreeSet<Term>,
pub(super) acyclicity: BTreeSet<Term>,
}
impl CompiledPolicies {
pub fn compile(pset: &PolicySet, env: &RequestEnv, schema: &Schema) -> Result<Self> {
let policies = symcc::well_typed_policies(pset, env, schema)?;
let env = symcc::SymEnv::new(schema, env)?;
let term = symcc::authorizer::is_authorized(&policies, &env)?;
let footprint = {
let conditions: Vec<_> = policies.policies().map(Policy::condition).collect();
symcc::enforcer::footprints(conditions.iter(), &env)
};
let acyclicity = footprint
.iter()
.map(|term| symcc::enforcer::acyclicity(term, &env.entities))
.collect();
Ok(Self {
term,
symenv: env,
policies,
footprint,
acyclicity,
})
}
pub fn allow_all(symenv: SymEnv) -> Self {
let footprint: BTreeSet<Term> =
symcc::enforcer::footprint(&symcc::verifier::allow_all().condition(), &symenv)
.collect();
Self {
term: Term::from(true),
policies: symcc::verifier::allow_all_pset(),
acyclicity: footprint
.iter()
.map(|term| symcc::enforcer::acyclicity(&term, &symenv.entities))
.collect(),
symenv,
footprint,
}
}
pub fn deny_all(symenv: SymEnv) -> Self {
Self {
term: Term::from(false),
symenv,
policies: PolicySet::new(),
footprint: BTreeSet::new(),
acyclicity: BTreeSet::new(),
}
}
}