use broadcast_auth::{AuthResult, Credentials, RequestContext, Verifier, respond};
const REALM: &str = "cameras";
fn main() {
digest();
basic();
bearer();
forwarded();
}
fn digest() {
let verifier = Verifier::new(
Credentials::Digest {
username: "admin".into(),
password: "hunter2".into(),
},
REALM,
);
let challenge = verifier.challenge();
println!("[digest] challenge: {challenge}");
let ctx = RequestContext::new("DESCRIBE", "rtsp://cam/live");
let correct = respond(&challenge, &ctx, Credentials::new("admin", "hunter2"))
.expect("respond computes an Authorization value");
let outcome = verify(&verifier, &correct, &ctx);
println!("[digest] correct password -> {outcome:?}");
assert_eq!(outcome, AuthResult::Ok);
let wrong = respond(&challenge, &ctx, Credentials::new("admin", "WRONG"))
.expect("respond computes an Authorization value even for a wrong password");
let outcome = verify(&verifier, &wrong, &ctx);
println!("[digest] wrong password -> {outcome:?}");
assert_eq!(outcome, AuthResult::Unauthorized);
}
fn basic() {
let verifier = Verifier::new(
Credentials::Basic {
username: "admin".into(),
password: "hunter2".into(),
},
REALM,
);
let challenge = verifier.challenge();
println!("[basic] challenge: {challenge}");
let ctx = RequestContext::new("GET", "/stream/media.m3u8");
let correct =
respond(&challenge, &ctx, Credentials::new("admin", "hunter2")).expect("responds");
assert_eq!(verify(&verifier, &correct, &ctx), AuthResult::Ok);
println!("[basic] correct password -> Ok");
let wrong = respond(&challenge, &ctx, Credentials::new("admin", "WRONG")).expect("responds");
assert_eq!(verify(&verifier, &wrong, &ctx), AuthResult::Unauthorized);
println!("[basic] wrong password -> Unauthorized");
}
fn bearer() {
let verifier = Verifier::new(Credentials::bearer("right-token"), REALM);
let challenge = verifier.challenge();
println!("[bearer] challenge: {challenge}");
let ctx = RequestContext::new("GET", "/stream/media.m3u8");
let correct = respond(&challenge, &ctx, Credentials::bearer("right-token")).expect("responds");
assert_eq!(verify(&verifier, &correct, &ctx), AuthResult::Ok);
println!("[bearer] correct token -> Ok");
let wrong = respond(&challenge, &ctx, Credentials::bearer("wrong-token")).expect("responds");
assert_eq!(verify(&verifier, &wrong, &ctx), AuthResult::Unauthorized);
println!("[bearer] wrong token -> Unauthorized");
}
fn forwarded() {
let verifier = Verifier::forwarded("X-Forwarded-User", Some("X-Forwarded-For".to_string()));
println!("[forwarded] challenge: {}", verifier.challenge());
let headers: &[(&str, &str)] = &[("X-Forwarded-User", "alice")];
let ctx = RequestContext::new("GET", "/stream/media.m3u8").with_headers(headers);
assert_eq!(verifier.verify(&ctx), AuthResult::Ok);
println!("[forwarded] header present -> Ok");
let ctx_no_header = RequestContext::new("GET", "/stream/media.m3u8");
assert_eq!(verifier.verify(&ctx_no_header), AuthResult::Unauthorized);
println!("[forwarded] header absent -> Unauthorized");
}
fn verify(verifier: &Verifier, authorization: &str, ctx: &RequestContext<'_>) -> AuthResult {
let headers: &[(&str, &str)] = &[("authorization", authorization)];
let ctx_with_auth = RequestContext::new(ctx.method, ctx.uri).with_headers(headers);
verifier.verify(&ctx_with_auth)
}