securitydept_creds/
validator.rs1use std::collections::HashMap;
4
5use crate::{
6 BasicAuthCred, StaticTokenAuthCred, StaticTokenAuthCredsConfig,
7 config::BasicAuthCredsConfig,
8 error::{CredsError, CredsResult},
9};
10
11pub trait BasicAuthCredsValidator<Cred>
13where
14 Cred: BasicAuthCred,
15{
16 fn get_cred(&self, username: &str) -> CredsResult<Option<&Cred>>;
17 fn verify_cred(&self, username: &str, password: &str) -> CredsResult<Option<&Cred>> {
18 let Some(cred) = self.get_cred(username)? else {
19 return Ok(None);
20 };
21 if cred.verify_password(password)? {
22 Ok(Some(cred))
23 } else {
24 Ok(None)
25 }
26 }
27}
28
29pub struct MapBasicAuthCredsValidator<Creds>
30where
31 Creds: BasicAuthCred + Clone,
32{
33 pub creds: HashMap<String, Creds>,
34}
35
36impl<Creds> MapBasicAuthCredsValidator<Creds>
37where
38 Creds: BasicAuthCred + Clone,
39{
40 pub fn from_config(config: &BasicAuthCredsConfig<Creds>) -> CredsResult<Self> {
42 config.validate()?;
43 Ok(Self {
44 creds: config
45 .users
46 .iter()
47 .map(|creds| (creds.username().to_string(), creds.clone()))
48 .collect(),
49 })
50 }
51}
52
53impl<Creds> BasicAuthCredsValidator<Creds> for MapBasicAuthCredsValidator<Creds>
54where
55 Creds: BasicAuthCred + Clone,
56{
57 fn get_cred(&self, username: &str) -> CredsResult<Option<&Creds>> {
58 Ok(self.creds.get(username))
59 }
60}
61
62pub trait StaticTokenAuthCredsValidator<Cred>
63where
64 Cred: StaticTokenAuthCred,
65{
66 fn get_cred(&self, token: &str) -> CredsResult<Option<&Cred>>;
67 fn verify_cred(&self, token: &str) -> CredsResult<Option<&Cred>> {
68 let cred = self
69 .get_cred(token)?
70 .ok_or(CredsError::InvalidStaticTokenCredentials)?;
71 cred.verify_token(token)?;
72 Ok(Some(cred))
73 }
74}
75
76pub struct MapStaticTokenAuthCredsValidator<Creds>
77where
78 Creds: StaticTokenAuthCred + Clone,
79{
80 pub creds: HashMap<String, Creds>,
81}
82
83impl<Creds> MapStaticTokenAuthCredsValidator<Creds>
84where
85 Creds: StaticTokenAuthCred + Clone,
86{
87 pub fn from_config(config: &StaticTokenAuthCredsConfig<Creds>) -> CredsResult<Self> {
89 config.validate()?;
90 Ok(Self {
91 creds: config
92 .tokens
93 .iter()
94 .map(|creds| (creds.token_hash().to_string(), creds.clone()))
95 .collect(),
96 })
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use crate::{Argon2BasicAuthCred, BasicAuthCred};
104
105 fn test_config() -> BasicAuthCredsConfig<Argon2BasicAuthCred> {
106 BasicAuthCredsConfig {
107 users: vec![
108 Argon2BasicAuthCred::new("admin".to_string(), "secret123".to_string()).unwrap(),
109 Argon2BasicAuthCred::new("user".to_string(), "password".to_string()).unwrap(),
110 ],
111 }
112 }
113
114 #[test]
115 fn test_validate_credentials() -> CredsResult<()> {
116 let validator = MapBasicAuthCredsValidator::from_config(&test_config()).unwrap();
117 assert!(validator.verify_cred("admin", "secret123")?.is_some());
118 assert!(validator.verify_cred("user", "password")?.is_some());
119 assert!(validator.verify_cred("admin", "wrong")?.is_none());
120 assert!(validator.verify_cred("unknown", "password")?.is_none());
121 Ok(())
122 }
123
124 #[test]
125 fn test_get_display_name() -> CredsResult<()> {
126 let validator = MapBasicAuthCredsValidator::from_config(&test_config()).unwrap();
127 assert_eq!(
128 validator.get_cred("admin")?.map(|c| c.display_name()),
129 Some("admin")
130 );
131 assert_eq!(
132 validator.get_cred("user")?.map(|c| c.display_name()),
133 Some("user")
134 );
135 assert!(validator.get_cred("unknown")?.is_none());
136 Ok(())
137 }
138}