Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Custom Matchers

The default ExactMatcher uses HashSet membership for O(1) exact equality checks. For dimensions that need custom logic – CIDR matching, numeric ranges, time-of-day restrictions – implement the Matcher trait.

The Matcher trait

#![allow(unused)]
fn main() {
use abac_rs::{Matcher, AttributeValue, AttributeType};

pub trait Matcher: Send + Sync {
    fn matches(
        &self,
        rule_value: &AttributeValue,
        request_value: &AttributeType,
        request_groups: &[AttributeType],
    ) -> bool;

    fn supports_bloom_filter(&self) -> bool { true }
}
}

IP CIDR matching

Match IP addresses against CIDR ranges:

#![allow(unused)]
fn main() {
use abac_rs::{Matcher, AttributeValue, AttributeType};

pub struct IpCidrMatcher;

impl Matcher for IpCidrMatcher {
    fn matches(
        &self,
        rule_value: &AttributeValue,
        request_value: &AttributeType,
        _groups: &[AttributeType],
    ) -> bool {
        match (rule_value, request_value) {
            (AttributeValue::All, _) => true,
            (AttributeValue::Specific(cidrs), AttributeType::IpAddr(ip)) => {
                cidrs.iter().any(|cidr| {
                    if let AttributeType::IpCidr(network) = cidr {
                        network.contains(*ip)
                    } else {
                        false
                    }
                })
            }
            _ => false,
        }
    }
}
}

Usage:

#![allow(unused)]
fn main() {
use ipnetwork::IpNetwork;

// Rule: allow from corporate network
let rule = AbacRule::builder("allow_corp_network")
    .dimension_values("source_ip", vec![
        AttributeType::IpCidr("10.0.0.0/8".parse::<IpNetwork>().unwrap()),
    ])
    .enabled(true)
    .build();

// Request with IP address
let mut request = AbacRequest::new();
request.add_attribute(
    "source_ip",
    AttributeType::IpAddr("10.1.2.3".parse().unwrap()),
    vec![]
);
}

Numeric range matching

Match integers within a range:

#![allow(unused)]
fn main() {
pub struct NumericRangeMatcher;

impl Matcher for NumericRangeMatcher {
    fn matches(
        &self,
        rule_value: &AttributeValue,
        request_value: &AttributeType,
        _groups: &[AttributeType],
    ) -> bool {
        match (rule_value, request_value) {
            (AttributeValue::All, _) => true,
            (AttributeValue::Specific(ranges), AttributeType::Integer(value)) => {
                ranges.iter().any(|range| {
                    if let AttributeType::Integer(min) = range {
                        *value >= *min  // Simplified: actual range needs min+max
                    } else {
                        false
                    }
                })
            }
            _ => false,
        }
    }

    fn supports_bloom_filter(&self) -> bool { false }
}
}

Performance considerations

Custom matchers:

  • Bypass Bloom filter optimization (return false from supports_bloom_filter)
  • Still benefit from LRU cache and composite index
  • Evaluated sequentially for candidate rules

For best performance, use ExactMatcher when possible.

See also