krishiv_plan/
governance.rs1#![forbid(unsafe_code)]
2pub trait AuthProvider: Send + Sync {
8 fn authenticate(&self, api_key: &str) -> Option<String>;
10}
11
12pub struct StaticApiKeyAuthProvider {
14 keys: std::collections::HashMap<String, String>,
15}
16
17impl StaticApiKeyAuthProvider {
18 pub fn new(keys: std::collections::HashMap<String, String>) -> Self {
20 Self { keys }
21 }
22}
23
24impl AuthProvider for StaticApiKeyAuthProvider {
25 fn authenticate(&self, api_key: &str) -> Option<String> {
26 use constant_time_eq::constant_time_eq;
27 let candidate = api_key.as_bytes();
28 let mut result: Option<String> = None;
31 for (stored, subject) in &self.keys {
32 if constant_time_eq(stored.as_bytes(), candidate) {
33 result = Some(subject.clone());
34 }
35 }
36 result
37 }
38}
39
40pub trait PolicyHook: Send + Sync {
44 fn check_table_access(&self, table_name: &str) -> bool;
46}
47
48pub struct AllowAllPolicyHook;
50
51impl PolicyHook for AllowAllPolicyHook {
52 fn check_table_access(&self, _table_name: &str) -> bool {
53 true
54 }
55}
56
57#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn static_auth_provider_known_key() {
65 let mut keys = std::collections::HashMap::new();
66 keys.insert("key1".to_string(), "alice".to_string());
67 let provider = StaticApiKeyAuthProvider::new(keys);
68 let subject = provider.authenticate("key1");
69 assert_eq!(subject.as_deref(), Some("alice"));
70 }
71
72 #[test]
73 fn static_auth_provider_unknown_key() {
74 let mut keys = std::collections::HashMap::new();
75 keys.insert("key1".to_string(), "alice".to_string());
76 let provider = StaticApiKeyAuthProvider::new(keys);
77 assert!(provider.authenticate("unknown").is_none());
78 }
79
80 #[test]
81 fn static_auth_provider_no_prefix_timing_oracle() {
82 let mut keys = std::collections::HashMap::new();
83 keys.insert("secretXXX".to_string(), "alice".to_string());
84 let provider = StaticApiKeyAuthProvider::new(keys);
85 assert!(provider.authenticate("secret").is_none());
86 assert!(provider.authenticate("secretXXXextra").is_none());
87 assert!(provider.authenticate("secretXXX").is_some());
88 assert!(provider.authenticate("").is_none());
89 }
90
91 #[test]
92 fn allow_all_policy_hook_allows_all() {
93 let hook = AllowAllPolicyHook;
94 assert!(hook.check_table_access("any_table"));
95 assert!(hook.check_table_access("internal_accounts"));
96 }
97}