spiffe_rustls/
authorizer.rs1use crate::error::{AuthorizerConfigError, Result};
4use spiffe::{SpiffeId, TrustDomain};
5use std::collections::BTreeSet;
6use std::sync::Arc;
7
8pub trait Authorizer: Send + Sync + 'static {
13 fn authorize(&self, peer: &SpiffeId) -> bool;
15}
16
17impl<F> Authorizer for F
20where
21 F: Fn(&SpiffeId) -> bool + Send + Sync + 'static,
22{
23 fn authorize(&self, peer: &SpiffeId) -> bool {
24 self(peer)
25 }
26}
27
28impl Authorizer for Arc<dyn Authorizer> {
29 fn authorize(&self, peer: &SpiffeId) -> bool {
30 (**self).authorize(peer)
31 }
32}
33
34impl Authorizer for Box<dyn Authorizer> {
35 fn authorize(&self, peer: &SpiffeId) -> bool {
36 (**self).authorize(peer)
37 }
38}
39
40#[derive(Debug, Clone, Copy, Default)]
42pub struct Any;
43
44impl Authorizer for Any {
45 fn authorize(&self, _peer: &SpiffeId) -> bool {
46 true
47 }
48}
49
50#[derive(Debug, Clone)]
52pub struct Exact {
53 allowed: Arc<BTreeSet<SpiffeId>>,
54}
55
56impl Exact {
57 pub fn new<I>(ids: I) -> Result<Self>
65 where
66 I: IntoIterator,
67 I::Item: TryInto<SpiffeId>,
68 <I::Item as TryInto<SpiffeId>>::Error: std::fmt::Display,
69 {
70 let mut allowed = BTreeSet::new();
71
72 for id in ids {
73 let spiffe_id = id
74 .try_into()
75 .map_err(|e| AuthorizerConfigError::InvalidSpiffeId(e.to_string()))?;
76 allowed.insert(spiffe_id);
77 }
78
79 Ok(Self {
80 allowed: Arc::new(allowed),
81 })
82 }
83}
84
85impl Authorizer for Exact {
86 fn authorize(&self, peer: &SpiffeId) -> bool {
87 self.allowed.contains(peer)
88 }
89}
90
91#[derive(Debug, Clone)]
93pub struct TrustDomains {
94 allowed: Arc<BTreeSet<TrustDomain>>,
95}
96
97impl TrustDomains {
98 pub fn new<I>(domains: I) -> Result<Self>
106 where
107 I: IntoIterator,
108 I::Item: TryInto<TrustDomain>,
109 <I::Item as TryInto<TrustDomain>>::Error: std::fmt::Display,
110 {
111 let mut allowed = BTreeSet::new();
112
113 for domain in domains {
114 let td = domain
115 .try_into()
116 .map_err(|e| AuthorizerConfigError::InvalidTrustDomain(e.to_string()))?;
117 allowed.insert(td);
118 }
119
120 Ok(Self {
121 allowed: Arc::new(allowed),
122 })
123 }
124}
125
126impl Authorizer for TrustDomains {
127 fn authorize(&self, peer: &SpiffeId) -> bool {
128 self.allowed.contains(peer.trust_domain())
129 }
130}
131
132pub fn any() -> Any {
148 Any
149}
150
151pub fn exact<I>(ids: I) -> Result<Exact>
177where
178 I: IntoIterator,
179 I::Item: TryInto<SpiffeId>,
180 <I::Item as TryInto<SpiffeId>>::Error: std::fmt::Display,
181{
182 Exact::new(ids)
183}
184
185pub fn trust_domains<I>(domains: I) -> Result<TrustDomains>
211where
212 I: IntoIterator,
213 I::Item: TryInto<TrustDomain>,
214 <I::Item as TryInto<TrustDomain>>::Error: std::fmt::Display,
215{
216 TrustDomains::new(domains)
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn test_exact_authorizer() {
225 let id1 = SpiffeId::new("spiffe://example.org/service1").unwrap();
226 let id2 = SpiffeId::new("spiffe://example.org/service2").unwrap();
227 let id3 = SpiffeId::new("spiffe://other.org/service1").unwrap();
228
229 let auth = Exact::new([id1.clone(), id2.clone()]).unwrap();
230 assert!(auth.authorize(&id1));
231 assert!(auth.authorize(&id2));
232 assert!(!auth.authorize(&id3));
233 }
234
235 #[test]
236 fn test_exact_authorizer_rejects_invalid() {
237 let result = Exact::new(["invalid-spiffe-id", "also-invalid"]);
238 assert!(result.is_err());
239 }
240
241 #[test]
242 fn test_trust_domains_authorizer() {
243 let td1 = TrustDomain::new("example.org").unwrap();
244 let td2 = TrustDomain::new("other.org").unwrap();
245
246 let id1 = SpiffeId::new("spiffe://example.org/service1").unwrap();
247 let id2 = SpiffeId::new("spiffe://example.org/service2").unwrap();
248 let id3 = SpiffeId::new("spiffe://other.org/service1").unwrap();
249 let id4 = SpiffeId::new("spiffe://third.org/service1").unwrap();
250
251 let auth = TrustDomains::new([td1, td2]).unwrap();
252 assert!(auth.authorize(&id1));
253 assert!(auth.authorize(&id2));
254 assert!(auth.authorize(&id3));
255 assert!(!auth.authorize(&id4));
256 }
257
258 #[test]
259 fn test_trust_domains_authorizer_rejects_invalid() {
260 let result = TrustDomains::new(["Invalid@Trust#Domain"]);
263 assert!(result.is_err());
264
265 let valid = TrustDomains::new(["example.org", "other.org"]).unwrap();
267 let id1 = SpiffeId::new("spiffe://example.org/service").unwrap();
268 let id2 = SpiffeId::new("spiffe://other.org/service").unwrap();
269 let id3 = SpiffeId::new("spiffe://rejected.org/service").unwrap();
270 assert!(valid.authorize(&id1));
271 assert!(valid.authorize(&id2));
272 assert!(!valid.authorize(&id3));
273 }
274
275 #[test]
276 fn test_any_authorizer_always_authorizes() {
277 let auth = any();
279 let id1 = SpiffeId::new("spiffe://example.org/service").unwrap();
280 let id2 = SpiffeId::new("spiffe://other.org/another").unwrap();
281 let id3 = SpiffeId::new("spiffe://test.domain/path/to/resource").unwrap();
282
283 assert!(auth.authorize(&id1));
285 assert!(auth.authorize(&id2));
286 assert!(auth.authorize(&id3));
287 }
288}