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#[must_use]
42#[derive(Debug, Clone, Copy, Default)]
43pub struct Any;
44
45impl Authorizer for Any {
46 fn authorize(&self, _peer: &SpiffeId) -> bool {
47 true
48 }
49}
50
51#[must_use]
53#[derive(Debug, Clone)]
54pub struct Exact {
55 allowed: BTreeSet<SpiffeId>,
56}
57
58impl Exact {
59 pub fn new<I>(ids: I) -> Result<Self>
67 where
68 I: IntoIterator,
69 I::Item: TryInto<SpiffeId>,
70 <I::Item as TryInto<SpiffeId>>::Error: std::fmt::Display,
71 {
72 let mut allowed = BTreeSet::new();
73
74 for id in ids {
75 let spiffe_id = id
76 .try_into()
77 .map_err(|e| AuthorizerConfigError::InvalidSpiffeId(e.to_string()))?;
78 allowed.insert(spiffe_id);
79 }
80
81 Ok(Self { allowed })
82 }
83}
84
85impl Authorizer for Exact {
86 fn authorize(&self, peer: &SpiffeId) -> bool {
87 self.allowed.contains(peer)
88 }
89}
90
91#[must_use]
93#[derive(Debug, Clone)]
94pub struct TrustDomainAllowList {
95 allowed: BTreeSet<TrustDomain>,
96}
97
98#[deprecated(
103 since = "0.4.1",
104 note = "Renamed to TrustDomainAllowList; TrustDomains remains as a compatibility alias."
105)]
106pub type TrustDomains = TrustDomainAllowList;
107
108impl TrustDomainAllowList {
109 pub fn new<I>(domains: I) -> Result<Self>
117 where
118 I: IntoIterator,
119 I::Item: TryInto<TrustDomain>,
120 <I::Item as TryInto<TrustDomain>>::Error: std::fmt::Display,
121 {
122 let mut allowed = BTreeSet::new();
123
124 for domain in domains {
125 let td = domain
126 .try_into()
127 .map_err(|e| AuthorizerConfigError::InvalidTrustDomain(e.to_string()))?;
128 allowed.insert(td);
129 }
130
131 Ok(Self { allowed })
132 }
133}
134
135impl Authorizer for TrustDomainAllowList {
136 fn authorize(&self, peer: &SpiffeId) -> bool {
137 self.allowed.contains(peer.trust_domain())
138 }
139}
140
141pub fn any() -> Any {
157 Any
158}
159
160pub fn exact<I>(ids: I) -> Result<Exact>
186where
187 I: IntoIterator,
188 I::Item: TryInto<SpiffeId>,
189 <I::Item as TryInto<SpiffeId>>::Error: std::fmt::Display,
190{
191 Exact::new(ids)
192}
193
194pub fn trust_domains<I>(domains: I) -> Result<TrustDomainAllowList>
220where
221 I: IntoIterator,
222 I::Item: TryInto<TrustDomain>,
223 <I::Item as TryInto<TrustDomain>>::Error: std::fmt::Display,
224{
225 TrustDomainAllowList::new(domains)
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn test_exact_authorizer() {
234 let id1 = SpiffeId::new("spiffe://example.org/service1").unwrap();
235 let id2 = SpiffeId::new("spiffe://example.org/service2").unwrap();
236 let id3 = SpiffeId::new("spiffe://other.org/service1").unwrap();
237
238 let auth = Exact::new([id1.clone(), id2.clone()]).unwrap();
239 assert!(auth.authorize(&id1));
240 assert!(auth.authorize(&id2));
241 assert!(!auth.authorize(&id3));
242 }
243
244 #[test]
245 fn test_exact_authorizer_rejects_invalid() {
246 let result = Exact::new(["invalid-spiffe-id", "also-invalid"]);
247 assert!(result.is_err());
248 }
249
250 #[test]
251 fn test_trust_domains_authorizer() {
252 let td1 = TrustDomain::new("example.org").unwrap();
253 let td2 = TrustDomain::new("other.org").unwrap();
254
255 let id1 = SpiffeId::new("spiffe://example.org/service1").unwrap();
256 let id2 = SpiffeId::new("spiffe://example.org/service2").unwrap();
257 let id3 = SpiffeId::new("spiffe://other.org/service1").unwrap();
258 let id4 = SpiffeId::new("spiffe://third.org/service1").unwrap();
259
260 let auth = TrustDomainAllowList::new([td1, td2]).unwrap();
261 assert!(auth.authorize(&id1));
262 assert!(auth.authorize(&id2));
263 assert!(auth.authorize(&id3));
264 assert!(!auth.authorize(&id4));
265 }
266
267 #[test]
268 fn test_trust_domains_authorizer_rejects_invalid() {
269 let result = TrustDomainAllowList::new(["Invalid@Trust#Domain"]);
272 assert!(result.is_err());
273
274 let valid = TrustDomainAllowList::new(["example.org", "other.org"]).unwrap();
276 let id1 = SpiffeId::new("spiffe://example.org/service").unwrap();
277 let id2 = SpiffeId::new("spiffe://other.org/service").unwrap();
278 let id3 = SpiffeId::new("spiffe://rejected.org/service").unwrap();
279 assert!(valid.authorize(&id1));
280 assert!(valid.authorize(&id2));
281 assert!(!valid.authorize(&id3));
282 }
283
284 #[test]
285 fn test_any_authorizer_always_authorizes() {
286 let auth = any();
288 let id1 = SpiffeId::new("spiffe://example.org/service").unwrap();
289 let id2 = SpiffeId::new("spiffe://other.org/another").unwrap();
290 let id3 = SpiffeId::new("spiffe://test.domain/path/to/resource").unwrap();
291
292 assert!(auth.authorize(&id1));
294 assert!(auth.authorize(&id2));
295 assert!(auth.authorize(&id3));
296 }
297}