From d898412f31f2ae2d9e0d68435c81c43eedb76bff Mon Sep 17 00:00:00 2001 From: David Huss <dh@atoav.com> Date: Fri, 25 Nov 2022 14:04:45 +0100 Subject: [PATCH] Add basic http authentification --- Cargo.lock | 87 +++++++++++++++++++++--------------- Cargo.toml | 4 +- README.md | 4 +- examples/default-config.toml | 3 ++ src/bin/sms-gateway.rs | 33 ++++++++++++-- src/config.rs | 19 +++++++- src/errors.rs | 4 ++ 7 files changed, 111 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba2ffa8..80d4a2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,6 +182,21 @@ dependencies = [ "syn", ] +[[package]] +name = "actix-web-httpauth" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dda62cf04bc3a9ad2ea8f314f721951cfdb4cdacec4e984d20e77c7bb170991" +dependencies = [ + "actix-utils", + "actix-web", + "base64", + "futures-core", + "futures-util", + "log", + "pin-project-lite", +] + [[package]] name = "adler" version = "1.0.2" @@ -201,9 +216,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -312,9 +327,9 @@ checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "bytes" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "bytestring" @@ -327,9 +342,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.76" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" dependencies = [ "jobserver", ] @@ -428,9 +443,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888" +checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" dependencies = [ "cc", "cxxbridge-flags", @@ -440,9 +455,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3" +checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" dependencies = [ "cc", "codespan-reporting", @@ -455,15 +470,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f" +checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" [[package]] name = "cxxbridge-macro" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704" +checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" dependencies = [ "proc-macro2", "quote", @@ -485,9 +500,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", @@ -526,9 +541,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", "miniz_oxide", @@ -780,9 +795,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", @@ -905,9 +920,9 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "miniz_oxide" -version = "0.5.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] @@ -979,9 +994,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "openssl" -version = "0.10.42" +version = "0.10.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" +checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376" dependencies = [ "bitflags", "cfg-if", @@ -1020,9 +1035,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.77" +version = "0.9.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" +checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132" dependencies = [ "autocfg", "cc", @@ -1176,9 +1191,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.12" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" +checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" dependencies = [ "base64", "bytes", @@ -1299,9 +1314,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.87" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ "itoa", "ryu", @@ -1367,10 +1382,11 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "sms-gateway" -version = "0.4.4" +version = "0.5.0" dependencies = [ "actix-rt", "actix-web", + "actix-web-httpauth", "build-time", "chrono", "derive_more", @@ -1379,6 +1395,7 @@ dependencies = [ "log", "once_cell", "openssl", + "rand", "regex", "reqwest", "serde", @@ -1517,9 +1534,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.21.2" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" dependencies = [ "autocfg", "bytes", @@ -1915,9 +1932,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.1+zstd.1.5.2" +version = "2.0.3+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +checksum = "44ccf97612ac95f3ccb89b2d7346b345e52f1c3019be4984f0455fb4ba991f8a" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index adc8dd0..0f61038 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "sms-gateway" description = "A http frontend for SMS Server Tools 3" authors = ["David Huss <david.huss@hfbk-hamburg.de>"] -version = "0.4.4" +version = "0.5.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -27,3 +27,5 @@ reqwest = { version = "0.11", features = ["json", "blocking"] } # Needed for cross compilation openssl = { version = "0.10.29", features = ["vendored"] } serde_regex = "1.1.0" +actix-web-httpauth = "0.8.0" +rand = "0.8.5" diff --git a/README.md b/README.md index 20da9d4..7d580e8 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,10 @@ A http frontend for smstools ## Usage -Send a message via post request (IP and Port need to match your configuration): +Send a message via post request (IP, Port, username and password need to match your configuration): ```bash -curl -i -d '{"number": "+4915785315089", "text": "Hello from an SMS"}' -H 'Content-Type: application/json' -X POST http://127.0.0.1:4242 +curl -i --user "admin:<PASSWORD>" -d '{"number": "+4915785315089", "text": "Hello from an SMS"}' -H 'Content-Type: application/json' -X POST http://127.0.0.1:4242 ``` ## Building diff --git a/examples/default-config.toml b/examples/default-config.toml index f915874..8f0574c 100644 --- a/examples/default-config.toml +++ b/examples/default-config.toml @@ -6,6 +6,9 @@ level = "info" [server] host = "127.0.0.1" port = 4242 +# Use this user and password in your requests (basic http-authentification) +user = "admin" +password = "9a3a2f736affdc7a9ec2c3c7c34aa2f9b9e433d506136bb8401e33a3169a5caa" [sms] config_path = "/etc/smsd.conf" diff --git a/src/bin/sms-gateway.rs b/src/bin/sms-gateway.rs index de19096..c87733f 100644 --- a/src/bin/sms-gateway.rs +++ b/src/bin/sms-gateway.rs @@ -11,11 +11,18 @@ use actix_web::{ web, post, App, - HttpResponse, - HttpServer, + HttpResponse, + HttpServer, Responder, + Error, middleware::Logger, - web::{Json, Data} + web::{Json, Data}, + dev::ServiceRequest, +}; + +use actix_web_httpauth::{ + extractors::basic::BasicAuth, + middleware::HttpAuthentication }; use actix_rt::{ @@ -55,7 +62,25 @@ async fn home() -> impl Responder { } +/// Validates http=requests +async fn validator( + req: ServiceRequest, + credentials: BasicAuth, +) -> Result<ServiceRequest, (Error, ServiceRequest)> { + info!("Authoriziation via {:?}", &CONFIG.server.password); + match credentials.password() == Some(&CONFIG.server.password) && credentials.user_id() == &CONFIG.server.user { + true => Ok(req), + false => { + match credentials.password() { + Some(pw) => error!("Authentification failed with credentials: \"{}:{}\", check the configuration file for working credentials", credentials.user_id(), pw), + None => error!("Authentification failed for user without credentials: \"{}:\", check the configuration file for working credentials", credentials.user_id()), + } + + return Err((Error::from(SmsError::AuthError), req)); + } + } +} @@ -164,11 +189,13 @@ async fn main() -> std::io::Result<()> { let history_data = Data::new(Mutex::new(History::new())); HttpServer::new(move || { + let auth = HttpAuthentication::basic(validator); App::new() .app_data( Data::clone(&history_data) ) .wrap(Logger::default()) + .wrap(auth) .service(home) .service(sms_send) .service(eventhandler) diff --git a/src/config.rs b/src/config.rs index 558abe4..a6fc2f8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,6 +9,11 @@ use toml; use chrono::Duration; use regex::Regex; use serde_regex; +use rand::{ + thread_rng, + Rng, + distributions::Alphanumeric +}; pub use log::{info, warn, debug, error}; @@ -23,7 +28,9 @@ pub struct Log { #[allow(unused)] pub struct Server { pub host: String, - pub port: u16 + pub port: u16, + pub user: String, + pub password: String } #[derive(Debug, Deserialize, Serialize)] @@ -194,7 +201,7 @@ fn check_paths(config: &Config) { impl Config { pub fn new(name: &str) -> Self { - let default_config: Config = match toml::from_str(include_str!("../examples/default-config.toml")) { + let mut default_config: Config = match toml::from_str(include_str!("../examples/default-config.toml")) { Ok(c) => c, Err(e) => { eprintln!("Error: Could not deserialize default configuration from \"config/default.toml\": {}", e); @@ -202,6 +209,14 @@ impl Config { } }; + // Generate a fresh new secret for each new config + let rand_string: String = thread_rng() + .sample_iter(&Alphanumeric) + .take(32) + .map(char::from) + .collect(); + default_config.server.password = rand_string; + // Read an existing config (or create the folder and a default config) let mut config = ensure_config(name, default_config); env_logger::init_from_env(env_logger::Env::default().default_filter_or(&config.log.level)); diff --git a/src/errors.rs b/src/errors.rs index 9523fdd..f3d1450 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -29,6 +29,8 @@ pub enum SmsError { SendFailed, #[error("Sending SMS failed, because there was no sent SMS within the given timeout")] SendTimeOut, + #[error("Failed to authenticate user")] + AuthError, } impl SmsError { @@ -46,6 +48,7 @@ impl SmsError { SmsError::InBlackList(_) => "Forbidden".to_string(), SmsError::SendFailed => "Service Unavailable".to_string(), SmsError::SendTimeOut => "Gateway Timeout".to_string(), + SmsError::AuthError=> "Forbidden".to_string(), } } } @@ -76,6 +79,7 @@ impl ResponseError for SmsError { SmsError::InBlackList(_) => StatusCode::FORBIDDEN, SmsError::SendFailed => StatusCode::SERVICE_UNAVAILABLE, SmsError::SendTimeOut => StatusCode::GATEWAY_TIMEOUT, + SmsError::AuthError => StatusCode::FORBIDDEN, } } } -- GitLab