1use ndn_packet::Name;
8use ndn_security::Certificate;
9
10#[derive(Debug, Clone)]
12pub enum PolicyDecision {
13 Allow,
15 Deny(String),
17}
18
19pub trait NamespacePolicy: Send + Sync {
21 fn evaluate(
24 &self,
25 requested_name: &Name,
26 requester_cert: Option<&Certificate>,
27 ca_prefix: &Name,
28 ) -> PolicyDecision;
29}
30
31pub struct HierarchicalPolicy;
43
44impl NamespacePolicy for HierarchicalPolicy {
45 fn evaluate(
46 &self,
47 requested_name: &Name,
48 requester_cert: Option<&Certificate>,
49 ca_prefix: &Name,
50 ) -> PolicyDecision {
51 let ca_identity = strip_ca_suffix(ca_prefix);
53
54 let requester_prefix = match requester_cert {
56 None => ca_identity.clone(),
57 Some(cert) => {
58 strip_key_suffix(cert.name.as_ref())
60 }
61 };
62
63 if requested_name.has_prefix(&requester_prefix) {
64 PolicyDecision::Allow
65 } else {
66 PolicyDecision::Deny(format!(
67 "{} is not under requester prefix {}",
68 requested_name, requester_prefix
69 ))
70 }
71 }
72}
73
74pub struct DelegationPolicy {
78 pub rules: Vec<(Name, Name)>,
80 pub allow_new_devices: bool,
82}
83
84impl DelegationPolicy {
85 pub fn new() -> Self {
86 Self {
87 rules: Vec::new(),
88 allow_new_devices: true,
89 }
90 }
91
92 pub fn allow(mut self, requester_prefix: Name, allowed_prefix: Name) -> Self {
94 self.rules.push((requester_prefix, allowed_prefix));
95 self
96 }
97}
98
99impl Default for DelegationPolicy {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105impl NamespacePolicy for DelegationPolicy {
106 fn evaluate(
107 &self,
108 requested_name: &Name,
109 requester_cert: Option<&Certificate>,
110 _ca_prefix: &Name,
111 ) -> PolicyDecision {
112 match requester_cert {
113 None => {
114 if self.allow_new_devices {
115 for (_, allowed) in &self.rules {
117 if requested_name.has_prefix(allowed) {
118 return PolicyDecision::Allow;
119 }
120 }
121 PolicyDecision::Deny("no matching rule for new device".to_string())
122 } else {
123 PolicyDecision::Deny("new devices not allowed".to_string())
124 }
125 }
126 Some(cert) => {
127 let requester_identity = strip_key_suffix(cert.name.as_ref());
128 for (req_prefix, allowed_prefix) in &self.rules {
129 if requester_identity.has_prefix(req_prefix)
130 && requested_name.has_prefix(allowed_prefix)
131 {
132 return PolicyDecision::Allow;
133 }
134 }
135 PolicyDecision::Deny("no matching delegation rule".to_string())
136 }
137 }
138 }
139}
140
141fn strip_key_suffix(name: &Name) -> Name {
142 let comps = name.components();
143 let key_pos = comps
145 .iter()
146 .rposition(|c| c.typ == 0x08 && c.value.as_ref() == b"KEY");
147 match key_pos {
148 Some(pos) if pos > 0 => Name::from_components(comps[..pos].iter().cloned()),
149 _ => name.clone(),
150 }
151}
152
153fn strip_ca_suffix(name: &Name) -> Name {
154 let comps = name.components();
155 if let Some(last) = comps.last()
157 && last.typ == 0x08
158 && last.value.as_ref() == b"CA"
159 {
160 return Name::from_components(comps[..comps.len() - 1].iter().cloned());
161 }
162 name.clone()
163}