use std::collections::HashMap;
use crate::item::{Node, SequenceTrait};
use crate::transform::Transform;
use crate::transform::callable::ActualParameters;
use crate::transform::context::{Context, StaticContextBuilder};
use crate::xdmerror::{Error, ErrorKind};
use qualname::QName;
#[derive(Clone, Debug, PartialEq)]
pub enum SecurityResult {
Permitted(Option<String>),
NotPermitted,
}
#[derive(Clone, Debug)]
pub struct SecurityPolicies<N: Node> {
policies: HashMap<QName, Policy<N>>,
in_force: Option<QName>,
}
impl<N: Node> SecurityPolicies<N> {
pub fn new() -> Self {
Self {
policies: HashMap::new(),
in_force: None,
}
}
pub fn push(&mut self, policy: Policy<N>) {
self.policies.insert(policy.name.clone(), policy);
}
pub fn find(&self, name: QName) -> Option<&Policy<N>> {
self.policies.get(&name)
}
pub fn activate(&mut self, name: &QName) -> Option<&Policy<N>> {
self.policies.get_key_value(name).map(|(_k, v)| {
self.in_force = Some(name.clone());
v
})
}
pub fn get(&self, f: &QName, a: ActualParameters<N>) -> Result<SecurityResult, Error> {
if self.in_force.is_none() {
return Ok(SecurityResult::NotPermitted);
}
if let Some(p) = self.policies.get(&self.in_force.as_ref().unwrap()) {
p.get(f, a)
} else {
Ok(SecurityResult::NotPermitted)
}
}
}
#[derive(Clone, Debug)]
pub struct Policy<N: Node> {
name: QName,
features: HashMap<QName, Feature<N>>,
}
impl<N: Node> Policy<N> {
pub fn new(name: QName) -> Self {
Self {
name,
features: HashMap::new(),
}
}
pub fn name(&self) -> QName {
self.name.clone()
}
pub fn add(&mut self, name: QName, f: Feature<N>) {
self.features.insert(name, f);
}
pub fn feature(&self, name: &QName) -> Option<&Feature<N>> {
self.features.get(name)
}
pub fn get(&self, name: &QName, a: ActualParameters<N>) -> Result<SecurityResult, Error> {
self.features
.get(name)
.map_or_else(|| Ok(SecurityResult::NotPermitted), |f| f.get(a))
}
}
#[derive(Clone, Debug)]
pub enum Feature<N: Node> {
Permitted(Option<Transform<N>>),
NotPermitted,
}
impl<N: Node> Feature<N> {
pub fn get(&self, a: ActualParameters<N>) -> Result<SecurityResult, Error> {
match self {
Feature::NotPermitted => Ok(SecurityResult::NotPermitted),
Feature::Permitted(o) => Ok(SecurityResult::Permitted(if let Some(t) = o {
let mut stctxt = StaticContextBuilder::new()
.message(|_| Ok(()))
.parser(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented")))
.fetcher(|_: &_| Err(Error::new(ErrorKind::NotImplemented, "not implemented")))
.build();
let mut ctxt = Context::new();
if let ActualParameters::Named(ap) = a {
ap.iter().try_for_each(|(an, av)| {
ctxt.var_push(an.to_string(), ctxt.dispatch(&mut stctxt, av)?);
Ok(())
})?
}
let r = ctxt.dispatch(&mut stctxt, t)?;
Some(r.to_string())
} else {
None
})),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::item::Item;
use crate::trees::nullo::Nullo;
use crate::value::Value;
use std::rc::Rc;
#[test]
fn feature_get_np() {
let f: Feature<Nullo> = Feature::NotPermitted;
assert_eq!(
f.get(ActualParameters::Named(vec![]))
.expect("unable to determine status of security feature"),
SecurityResult::NotPermitted
)
}
#[test]
fn feature_get_unlimited() {
let f: Feature<Nullo> = Feature::Permitted(None);
assert_eq!(
f.get(ActualParameters::Named(vec![]))
.expect("unable to determine status of security feature"),
SecurityResult::Permitted(None)
)
}
#[test]
fn feature_get_limited() {
let f: Feature<Nullo> = Feature::Permitted(Some(Transform::Literal(Item::Value(Rc::new(
Value::from(1234),
)))));
assert_eq!(
f.get(ActualParameters::Named(vec![]))
.expect("unable to determine status of security feature"),
SecurityResult::Permitted(Some(String::from("1234")))
)
}
}