use super::{AttributeSet, BindRule, DnScope, Scope, TargetAttrFilter, TargetFilter};
use crate::entry::LdapEntry;
use crate::operation::{LdapOperation, LdapPermission, OperationType};
use acls_rs::prelude::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[non_exhaustive]
pub struct Aci {
pub(crate) name: String,
pub(crate) target_dn: Option<String>,
pub(crate) scope: Scope,
pub(crate) target_filter: TargetFilter,
pub(crate) target_attributes: Vec<String>,
pub(crate) target_attributes_excluded: bool,
pub(crate) target_attr_filters: Vec<TargetAttrFilter>,
pub(crate) target_from: Option<String>,
pub(crate) target_to: Option<String>,
pub(crate) permissions: Vec<OperationType>,
pub(crate) bind_rule: BindRule,
pub(crate) grant: bool,
}
impl Aci {
pub fn name(&self) -> &str {
&self.name
}
pub fn target_dn(&self) -> Option<&str> {
self.target_dn.as_deref()
}
pub fn scope(&self) -> Scope {
self.scope
}
pub fn target_filter(&self) -> &TargetFilter {
&self.target_filter
}
pub fn target_attributes(&self) -> &[String] {
&self.target_attributes
}
pub fn target_attributes_excluded(&self) -> bool {
self.target_attributes_excluded
}
pub fn target_attr_filters(&self) -> &[TargetAttrFilter] {
&self.target_attr_filters
}
pub fn target_from(&self) -> Option<&str> {
self.target_from.as_deref()
}
pub fn target_to(&self) -> Option<&str> {
self.target_to.as_deref()
}
pub fn permissions(&self) -> &[OperationType] {
&self.permissions
}
pub fn bind_rule(&self) -> &BindRule {
&self.bind_rule
}
pub fn grant(&self) -> bool {
self.grant
}
pub fn attribute_set(&self) -> AttributeSet {
AttributeSet::from_vec(&self.target_attributes, self.target_attributes_excluded)
}
pub fn dn_scope(&self) -> DnScope {
DnScope::new(self.target_dn.clone(), self.scope)
}
pub fn operation_set(&self) -> crate::operation::OperationSet {
crate::operation::OperationSet::from(self.permissions.as_slice())
}
pub fn applies_to_target(&self, operation: &LdapOperation, target_entry: &LdapEntry) -> bool {
if !self.operation_set().contains(operation.operation_type) {
return false;
}
if !self.target_filter.matches(target_entry) {
return false;
}
if !self.dn_scope().contains_dn(&target_entry.dn) {
return false;
}
if !self.target_attributes.is_empty() {
let attr_set = self.attribute_set();
if operation.attributes.is_empty() {
if attr_set.is_excluded() {
return false;
}
} else if attr_set.is_excluded() {
if !operation
.attributes
.iter()
.any(|a| attr_set.contains_attr(a))
{
return false;
}
} else if !operation
.attributes
.iter()
.all(|a| attr_set.contains_attr(a))
{
return false;
}
}
true
}
pub fn applies_to(
&self,
operation: &LdapOperation,
target_entry: &LdapEntry,
user_dn: Option<&str>,
user_entry: Option<&LdapEntry>,
) -> bool {
if !self.applies_to_target(operation, target_entry) {
return false;
}
self.bind_rule
.matches(user_dn, user_entry, &target_entry.dn)
}
pub fn to_permission(&self, operation: &LdapOperation) -> Option<AtomicPermission> {
if self.grant {
Some(LdapPermission::new(operation.operation_type, &operation.target_dn).to_atomic())
} else {
None
}
}
}