From 70d82c3faad9204e47ed514b58c7bd7c5e7cb61a Mon Sep 17 00:00:00 2001 From: khai96_ Date: Sun, 5 May 2019 14:30:13 +0700 Subject: Begin to support multiple auths --- src/args.rs | 30 +++++++++++++++++++++--------- src/auth.rs | 44 ++++++++++++++++++++++---------------------- 2 files changed, 43 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/args.rs b/src/args.rs index 63799a0..3972995 100644 --- a/src/args.rs +++ b/src/args.rs @@ -77,8 +77,20 @@ fn parse_interface(src: &str) -> Result { src.parse::() } -/// Checks wether the auth string is valid, i.e. it follows the syntax username:password +/// Parse a string of multiple authentication requirements fn parse_auth(src: &str) -> Result { + let mut required_auth = auth::RequiredAuth::new(); + + for pair in src.split_whitespace().map(parse_single_auth) { + let (username, password) = pair?; + required_auth.insert(username.to_owned(), password); + } + + Ok(required_auth) +} + +/// Parse a single authentication requirement +fn parse_single_auth(src: &str) -> Result<(String, auth::RequiredAuthPassword), ContextualError> { let mut split = src.splitn(3, ':'); let invalid_auth_format = Err(ContextualError::InvalidAuthFormat); @@ -119,10 +131,7 @@ fn parse_auth(src: &str) -> Result { auth::RequiredAuthPassword::Plain(second_part.to_owned()) }; - Ok(auth::RequiredAuth { - username: username.to_owned(), - password, - }) + Ok((username.to_owned(), password)) } /// Parses the command line arguments @@ -172,16 +181,19 @@ mod tests { fn create_required_auth(username: &str, password: &str, encrypt: &str) -> auth::RequiredAuth { use auth::*; use RequiredAuthPassword::*; + let mut required_auth = RequiredAuth::new(); - RequiredAuth { - username: username.to_owned(), - password: match encrypt { + required_auth.insert( + username.to_owned(), + match encrypt { "plain" => Plain(password.to_owned()), "sha256" => Sha256(hex::decode(password.to_owned()).unwrap()), "sha512" => Sha512(hex::decode(password.to_owned()).unwrap()), _ => panic!("Unknown encryption type"), }, - } + ); + + required_auth } #[rstest_parametrize( diff --git a/src/auth.rs b/src/auth.rs index e526923..735929b 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -2,6 +2,7 @@ use actix_web::http::header; use actix_web::middleware::{Middleware, Response}; use actix_web::{HttpRequest, HttpResponse, Result}; use sha2::{Digest, Sha256, Sha512}; +use std::collections::HashMap; use crate::errors::{ContextualError}; @@ -22,12 +23,8 @@ pub enum RequiredAuthPassword { Sha512(Vec), } -#[derive(Clone, Debug, PartialEq)] /// Authentication structure to match `BasicAuthParams` against -pub struct RequiredAuth { - pub username: String, - pub password: RequiredAuthPassword, -} +pub type RequiredAuth = HashMap; /// Decode a HTTP basic auth string into a tuple of username and password. pub fn parse_basic_auth( @@ -57,20 +54,20 @@ pub fn parse_basic_auth( /// Verify authentication pub fn match_auth(basic_auth: BasicAuthParams, required_auth: &RequiredAuth) -> bool { - if basic_auth.username != required_auth.username { - return false; - } - - match &required_auth.password { - RequiredAuthPassword::Plain(ref required_password) => { - basic_auth.password == *required_password - } - RequiredAuthPassword::Sha256(password_hash) => { - compare_hash::(basic_auth.password, password_hash) - } - RequiredAuthPassword::Sha512(password_hash) => { - compare_hash::(basic_auth.password, password_hash) + if let Some(password) = required_auth.get(&basic_auth.username) { + match &password { + RequiredAuthPassword::Plain(ref required_password) => { + basic_auth.password == *required_password + } + RequiredAuthPassword::Sha256(password_hash) => { + compare_hash::(basic_auth.password, password_hash) + } + RequiredAuthPassword::Sha512(password_hash) => { + compare_hash::(basic_auth.password, password_hash) + } } + } else { + false } } @@ -150,16 +147,19 @@ mod tests { /// Helper function that creates a `RequiredAuth` structure and encrypt `password` if necessary fn create_required_auth(username: &str, password: &str, encrypt: &str) -> RequiredAuth { use RequiredAuthPassword::*; + let mut required_auth = RequiredAuth::new(); - RequiredAuth { - username: username.to_owned(), - password: match encrypt { + required_auth.insert( + username.to_owned(), + match encrypt { "plain" => Plain(password.to_owned()), "sha256" => Sha256(get_hash::(password.to_owned())), "sha512" => Sha512(get_hash::(password.to_owned())), _ => panic!("Unknown encryption type"), }, - } + ); + + required_auth } #[rstest_parametrize( -- cgit v1.2.3