use crate::abac::Abac;
use crate::policy::{IncomingPolicyAccessControl, OutgoingPolicyAccessControl};
use crate::{Action, Env, Policies, Resource};
use core::fmt;
use core::fmt::{Debug, Formatter};
use ockam_core::compat::sync::Arc;
use ockam_core::{Address, DenyAll, Result};
use ockam_identity::{Identifier, IdentitiesAttributes};
use ockam_node::Context;
use tracing::debug;
#[derive(Clone)]
pub struct PolicyAccessControl {
pub(super) abac: Abac,
pub(super) policies: Policies,
pub(super) resource: Resource,
pub(super) action: Action,
}
impl Debug for PolicyAccessControl {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("PolicyAccessControl")
.field("resource_name", &self.resource.resource_name)
.field("resource_type", &self.resource.resource_type)
.field("action", &self.action)
.field("abac", &self.abac)
.finish()
}
}
impl PolicyAccessControl {
pub fn new(
policies: Policies,
identities_attributes: Arc<IdentitiesAttributes>,
authority: Option<Identifier>,
env: Env,
resource: Resource,
action: Action,
) -> Self {
let abac = Abac::new(identities_attributes, authority, env);
Self {
abac,
policies,
resource,
action,
}
}
pub fn create_incoming(&self) -> IncomingPolicyAccessControl {
IncomingPolicyAccessControl {
policy_access_control: self.clone(),
}
}
pub fn create_outgoing(&self, ctx: &Context) -> Result<OutgoingPolicyAccessControl> {
let ctx = ctx.new_detached(
Address::random_tagged("OutgoingPolicyAbac"),
DenyAll,
DenyAll,
)?;
Ok(OutgoingPolicyAccessControl {
ctx,
policy_access_control: self.clone(),
})
}
pub async fn is_identity_authorized(&self, identifier: &Identifier) -> Result<bool> {
let expression = if let Some(expr) = self
.policies
.get_expression_for_resource(&self.resource, &self.action)
.await?
{
expr
} else {
debug! {
resource = %self.resource,
action = %self.action,
"no policy found; access denied"
}
return Ok(false);
};
self.abac
.is_identity_authorized(identifier, &expression)
.await
}
}