1#[cfg(test)]
2mod auth_test;
3
4use std::net::SocketAddr;
5use std::time::{Duration, SystemTime, UNIX_EPOCH};
6
7use util::Error;
8
9use md5::{Digest, Md5};
10use ring::hmac;
11
12pub trait AuthHandler {
13 fn auth_handle(
14 &self,
15 username: &str,
16 realm: &str,
17 src_addr: SocketAddr,
18 ) -> Result<Vec<u8>, Error>;
19}
20
21pub fn generate_long_term_credentials(
23 shared_secret: &str,
24 duration: Duration,
25) -> Result<(String, String), Error> {
26 let t = SystemTime::now().duration_since(UNIX_EPOCH)? + duration;
27 let username = format!("{}", t.as_secs());
28 let password = long_term_credentials(&username, shared_secret);
29 Ok((username, password))
30}
31
32fn long_term_credentials(username: &str, shared_secret: &str) -> String {
33 let mac = hmac::Key::new(
34 hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
35 shared_secret.as_bytes(),
36 );
37 let password = hmac::sign(&mac, username.as_bytes()).as_ref().to_vec();
38 base64::encode(&password)
39}
40
41pub fn generate_auth_key(username: &str, realm: &str, password: &str) -> Vec<u8> {
43 let s = format!("{}:{}:{}", username, realm, password);
44
45 let mut h = Md5::new();
46 h.update(s.as_bytes());
47 h.finalize().as_slice().to_vec()
48}
49
50pub struct LongTermAuthHandler {
51 shared_secret: String,
52}
53
54impl AuthHandler for LongTermAuthHandler {
55 fn auth_handle(
56 &self,
57 username: &str,
58 realm: &str,
59 src_addr: SocketAddr,
60 ) -> Result<Vec<u8>, Error> {
61 log::trace!(
62 "Authentication username={} realm={} src_addr={}",
63 username,
64 realm,
65 src_addr
66 );
67
68 let t = Duration::from_secs(username.parse::<u64>()?);
69 if t < SystemTime::now().duration_since(UNIX_EPOCH)? {
70 return Err(Error::new(format!(
71 "Expired time-windowed username {}",
72 username
73 )));
74 }
75
76 let password = long_term_credentials(username, &self.shared_secret);
77 Ok(generate_auth_key(username, realm, &password))
78 }
79}
80
81impl LongTermAuthHandler {
82 pub fn new(shared_secret: String) -> Self {
84 LongTermAuthHandler { shared_secret }
85 }
86}