Skip to content

turn: add feature async-auth #671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions turn/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ criterion = "0.5"

[features]
metrics = []
async-auth = []

[[bench]]
name = "bench"
Expand Down
20 changes: 20 additions & 0 deletions turn/examples/turn_server_udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::sync::Arc;

#[cfg(feature = "async-auth")]
use async_trait::async_trait;
use clap::{App, AppSettings, Arg};
use tokio::net::UdpSocket;
use tokio::signal;
Expand All @@ -24,6 +26,7 @@ impl MyAuthHandler {
}
}

#[cfg(not(feature = "async-auth"))]
impl AuthHandler for MyAuthHandler {
fn auth_handle(
&self,
Expand All @@ -39,6 +42,23 @@ impl AuthHandler for MyAuthHandler {
}
}
}
#[cfg(feature = "async-auth")]
#[async_trait]
impl AuthHandler for MyAuthHandler {
async fn auth_handle(
&self,
username: &str,
_realm: &str,
_src_addr: SocketAddr,
) -> Result<Vec<u8>, Error> {
if let Some(pw) = self.cred_map.get(username) {
//log::debug!("username={}, password={:?}", username, pw);
Ok(pw.to_vec())
} else {
Err(Error::ErrFakeErr)
}
}
}

// RUST_LOG=trace cargo run --color=always --package turn --example turn_server_udp -- --public-ip 0.0.0.0 --users user=pass

Expand Down
15 changes: 15 additions & 0 deletions turn/src/allocation/allocation_manager/allocation_manager_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::net::{IpAddr, Ipv4Addr};
use std::str::FromStr;

#[cfg(feature = "async-auth")]
use async_trait::async_trait;
use stun::attributes::ATTR_USERNAME;
use stun::textattrs::TextAttribute;
use tokio::net::UdpSocket;
Expand Down Expand Up @@ -397,11 +399,24 @@ async fn test_delete_allocation_by_username() -> Result<()> {
}

struct TestAuthHandler;
#[cfg(not(feature = "async-auth"))]
impl AuthHandler for TestAuthHandler {
fn auth_handle(&self, username: &str, realm: &str, _src_addr: SocketAddr) -> Result<Vec<u8>> {
Ok(generate_auth_key(username, realm, "pass"))
}
}
#[cfg(feature = "async-auth")]
#[async_trait]
impl AuthHandler for TestAuthHandler {
async fn auth_handle(
&self,
username: &str,
realm: &str,
_src_addr: SocketAddr,
) -> Result<Vec<u8>> {
Ok(generate_auth_key(username, realm, "pass"))
}
}

async fn create_server(
alloc_close_notify: Option<Sender<AllocationInfo>>,
Expand Down
42 changes: 42 additions & 0 deletions turn/src/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,31 @@ mod auth_test;
use std::net::SocketAddr;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

#[cfg(feature = "async-auth")]
use async_trait::async_trait;
use base64::prelude::BASE64_STANDARD;
use base64::Engine;
use md5::{Digest, Md5};
use ring::hmac;

use crate::error::*;

#[cfg(not(feature = "async-auth"))]
pub trait AuthHandler {
fn auth_handle(&self, username: &str, realm: &str, src_addr: SocketAddr) -> Result<Vec<u8>>;
}

#[cfg(feature = "async-auth")]
#[async_trait]
pub trait AuthHandler {
async fn auth_handle(
&self,
username: &str,
realm: &str,
src_addr: SocketAddr,
) -> Result<Vec<u8>>;
}

/// `generate_long_term_credentials()` can be used to create credentials valid for `duration` time/
pub fn generate_long_term_credentials(
shared_secret: &str,
Expand Down Expand Up @@ -48,6 +62,7 @@ pub struct LongTermAuthHandler {
shared_secret: String,
}

#[cfg(not(feature = "async-auth"))]
impl AuthHandler for LongTermAuthHandler {
fn auth_handle(&self, username: &str, realm: &str, src_addr: SocketAddr) -> Result<Vec<u8>> {
log::trace!(
Expand All @@ -68,6 +83,33 @@ impl AuthHandler for LongTermAuthHandler {
Ok(generate_auth_key(username, realm, &password))
}
}
#[cfg(feature = "async-auth")]
#[async_trait]
impl AuthHandler for LongTermAuthHandler {
async fn auth_handle(
&self,
username: &str,
realm: &str,
src_addr: SocketAddr,
) -> Result<Vec<u8>> {
log::trace!(
"Authentication username={} realm={} src_addr={}",
username,
realm,
src_addr
);

let t = Duration::from_secs(username.parse::<u64>()?);
if t < SystemTime::now().duration_since(UNIX_EPOCH)? {
return Err(Error::Other(format!(
"Expired time-windowed username {username}"
)));
}

let password = long_term_credentials(username, &self.shared_secret);
Ok(generate_auth_key(username, realm, &password))
}
}

impl LongTermAuthHandler {
/// https://tools.ietf.org/search/rfc5389#section-10.2
Expand Down
15 changes: 15 additions & 0 deletions turn/src/client/client_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::net::IpAddr;

#[cfg(feature = "async-auth")]
use async_trait::async_trait;
use tokio::net::UdpSocket;
use tokio::time::Duration;
use util::vnet::net::*;
Expand Down Expand Up @@ -120,11 +122,24 @@ async fn test_client_with_stun_send_binding_request_to_timeout() -> Result<()> {
}

struct TestAuthHandler;
#[cfg(not(feature = "async-auth"))]
impl AuthHandler for TestAuthHandler {
fn auth_handle(&self, username: &str, realm: &str, _src_addr: SocketAddr) -> Result<Vec<u8>> {
Ok(generate_auth_key(username, realm, "pass"))
}
}
#[cfg(feature = "async-auth")]
#[async_trait]
impl AuthHandler for TestAuthHandler {
async fn auth_handle(
&self,
username: &str,
realm: &str,
_src_addr: SocketAddr,
) -> Result<Vec<u8>> {
Ok(generate_auth_key(username, realm, "pass"))
}
}

// Create an allocation, and then delete all nonces
// The subsequent Write on the allocation will cause a CreatePermission
Expand Down
23 changes: 23 additions & 0 deletions turn/src/server/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ impl Request {
return Ok(None);
}

#[cfg(not(feature = "async-auth"))]
let our_key = match self.auth_handler.auth_handle(
&username_attr.to_string(),
&realm_attr.to_string(),
Expand All @@ -218,6 +219,28 @@ impl Request {
return Ok(None);
}
};
#[cfg(feature = "async-auth")]
let our_key = match self
.auth_handler
.auth_handle(
&username_attr.to_string(),
&realm_attr.to_string(),
self.src_addr,
)
.await
{
Ok(key) => key,
Err(_) => {
build_and_send_err(
&self.conn,
self.src_addr,
bad_request_msg,
Error::ErrNoSuchUser,
)
.await?;
return Ok(None);
}
};

let mi = MessageIntegrity(our_key);
if let Err(err) = mi.check(&mut m.clone()) {
Expand Down
15 changes: 15 additions & 0 deletions turn/src/server/request/request_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::net::IpAddr;
use std::str::FromStr;

#[cfg(feature = "async-auth")]
use async_trait::async_trait;
use tokio::net::UdpSocket;
use tokio::time::{Duration, Instant};
use util::vnet::net::*;
Expand Down Expand Up @@ -50,11 +52,24 @@ async fn test_allocation_lifetime_overflow() -> Result<()> {
}

struct TestAuthHandler;
#[cfg(not(feature = "async-auth"))]
impl AuthHandler for TestAuthHandler {
fn auth_handle(&self, _username: &str, _realm: &str, _src_addr: SocketAddr) -> Result<Vec<u8>> {
Ok(STATIC_KEY.as_bytes().to_vec())
}
}
#[cfg(feature = "async-auth")]
#[async_trait]
impl AuthHandler for TestAuthHandler {
async fn auth_handle(
&self,
_username: &str,
_realm: &str,
_src_addr: SocketAddr,
) -> Result<Vec<u8>> {
Ok(STATIC_KEY.as_bytes().to_vec())
}
}

#[tokio::test]
async fn test_allocation_lifetime_deletion_zero_lifetime() -> Result<()> {
Expand Down
19 changes: 19 additions & 0 deletions turn/src/server/server_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::str::FromStr;

#[cfg(feature = "async-auth")]
use async_trait::async_trait;
use tokio::net::UdpSocket;
use tokio::sync::mpsc;
use util::vnet::router::Nic;
Expand Down Expand Up @@ -30,6 +32,7 @@ impl TestAuthHandler {
}
}

#[cfg(not(feature = "async-auth"))]
impl AuthHandler for TestAuthHandler {
fn auth_handle(&self, username: &str, _realm: &str, _src_addr: SocketAddr) -> Result<Vec<u8>> {
if let Some(pw) = self.cred_map.get(username) {
Expand All @@ -39,6 +42,22 @@ impl AuthHandler for TestAuthHandler {
}
}
}
#[cfg(feature = "async-auth")]
#[async_trait]
impl AuthHandler for TestAuthHandler {
async fn auth_handle(
&self,
username: &str,
_realm: &str,
_src_addr: SocketAddr,
) -> Result<Vec<u8>> {
if let Some(pw) = self.cred_map.get(username) {
Ok(pw.to_vec())
} else {
Err(Error::ErrFakeErr)
}
}
}

#[tokio::test]
async fn test_server_simple() -> Result<()> {
Expand Down
Loading