auth-policy 0.0.2

Rust crate for evaluating authorization decisions against declarative policies
Documentation
use std::collections::HashMap;

/// Authorization request under evaluation.
#[derive(Debug, Default, Clone)]
pub struct Request {
    action: String,
    actor_attrs: HashMap<String, String>,
    resource_attrs: HashMap<String, String>,
    environment_attrs: HashMap<String, String>,
}

impl Request {
    /// Create an empty request.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the action verb for the request.
    pub fn action(mut self, action: impl Into<String>) -> Self {
        self.action = action.into();
        self
    }

    /// Add an attribute that belongs to the actor (subject) performing the request.
    pub fn actor_attr(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.actor_attrs.insert(key.into(), value.into());
        self
    }

    /// Add an attribute belonging to the resource being accessed.
    pub fn resource_attr(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.resource_attrs.insert(key.into(), value.into());
        self
    }

    /// Add an attribute describing the surrounding environment (time, IP, etc.).
    pub fn environment_attr(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.environment_attrs.insert(key.into(), value.into());
        self
    }

    /// Return the configured action, if any.
    pub fn action_name(&self) -> &str {
        &self.action
    }

    pub(crate) fn lookup(&self, namespace: &str, key: Option<&str>) -> Option<&str> {
        match namespace {
            "actor" => key.and_then(|k| self.actor_attrs.get(k)).map(String::as_str),
            "resource" => key
                .and_then(|k| self.resource_attrs.get(k))
                .map(String::as_str),
            "environment" => key
                .and_then(|k| self.environment_attrs.get(k))
                .map(String::as_str),
            "action" => {
                if let Some("name") | Some("id") = key {
                    Some(self.action.as_str())
                } else if key.is_none() {
                    Some(self.action.as_str())
                } else {
                    None
                }
            }
            _ => None,
        }
    }
}