webrtc_turn/auth/
mod.rs

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
21// generate_long_term_credentials can be used to create credentials valid for [duration] time
22pub 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
41// generate_auth_key is a convince function to easily generate keys in the format used by AuthHandler
42pub 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    // https://tools.ietf.org/search/rfc5389#section-10.2
83    pub fn new(shared_secret: String) -> Self {
84        LongTermAuthHandler { shared_secret }
85    }
86}