From 70860ab184f628311e6ceda8d56ad1fa3a7167d3 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Fri, 14 May 2021 09:30:59 +0200 Subject: [PATCH] Can generate admin key enrollment challenge --- Cargo.lock | 45 +++++++++++++++++++ Cargo.toml | 3 +- .../admin/admin_account_controller.rs | 16 ++++++- src/data/admin.rs | 8 +++- src/data/mod.rs | 3 +- src/data/webauthn_config.rs | 36 +++++++++++++++ src/helpers/admin_access_token_helper.rs | 2 +- ...dmin_key_registration_challenges_helper.rs | 34 ++++++++++++++ src/helpers/mod.rs | 3 +- src/routes.rs | 1 + src/server.rs | 7 ++- 11 files changed, 147 insertions(+), 11 deletions(-) create mode 100644 src/data/webauthn_config.rs create mode 100644 src/helpers/admin_key_registration_challenges_helper.rs diff --git a/Cargo.lock b/Cargo.lock index 5758693..f2d26f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -816,6 +816,7 @@ dependencies = [ "serde_json", "sha1", "tokio 0.2.25", + "webauthn-rs", "webpage", "webrtc-sdp", "yaml-rust", @@ -1401,6 +1402,12 @@ dependencies = [ "tracing-futures", ] +[[package]] +name = "half" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" + [[package]] name = "hashbrown" version = "0.9.1" @@ -2948,6 +2955,25 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_bytes" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_cbor" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.123" @@ -3798,6 +3824,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webauthn-rs" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca232368e409a186d2cc0a83380398429a5b6c39608143c2a9bcc16e96b08d0" +dependencies = [ + "base64 0.12.3", + "log", + "nom", + "openssl", + "rand 0.7.3", + "serde", + "serde_bytes", + "serde_cbor", + "serde_derive", + "serde_json", + "thiserror", +] + [[package]] name = "webpage" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index 2708e78..5917b57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,4 +40,5 @@ mp4 = "0.8.1" zip = "0.5.10" webpage = "1.2.0" gouth = "0.2.0" -tokio = { version = "0.2" } \ No newline at end of file +tokio = { version = "0.2" } +webauthn-rs = "0.2.5" \ No newline at end of file diff --git a/src/controllers/admin/admin_account_controller.rs b/src/controllers/admin/admin_account_controller.rs index 4ddc678..34541b1 100644 --- a/src/controllers/admin/admin_account_controller.rs +++ b/src/controllers/admin/admin_account_controller.rs @@ -2,6 +2,8 @@ //! //! @author Pierre Hubert + + use crate::api_data::admin::admin_auth_options::AdminAuthOptions; use crate::api_data::admin::admin_auth_success::AdminAuthSuccess; use crate::api_data::admin::admin_id_api::AdminIDAPI; @@ -9,7 +11,8 @@ use crate::api_data::admin::admin_info_api::AdminInfoAPI; use crate::data::admin::NewAdminGeneralSettings; use crate::data::base_request_handler::BaseRequestHandler; use crate::data::http_request_handler::HttpRequestHandler; -use crate::helpers::{admin_access_token_helper, admin_account_helper}; +use crate::data::webauthn_config::get_wan; +use crate::helpers::{admin_access_token_helper, admin_account_helper, admin_key_registration_challenges_helper}; use crate::routes::RequestResult; use crate::utils::date_utils::time; @@ -89,4 +92,15 @@ pub fn update_general_settings(r: &mut HttpRequestHandler) -> RequestResult { })?; r.ok() +} + +/// Generate a challenge to register a new key +pub fn challenge_register_key(r: &mut HttpRequestHandler) -> RequestResult { + let mut wan = get_wan(); + + let (res, state) = wan.generate_challenge_register(&r.admin_id()?.id_str(), None)?; + + admin_key_registration_challenges_helper::set(r.admin_id()?, state)?; + + r.set_response(res) } \ No newline at end of file diff --git a/src/data/admin.rs b/src/data/admin.rs index a3e90da..22f8230 100644 --- a/src/data/admin.rs +++ b/src/data/admin.rs @@ -13,6 +13,10 @@ impl AdminID { pub fn id(&self) -> u64 { self.0 } + + pub fn id_str(&self) -> String { + format!("{}", self.0) + } } pub struct NewAdmin { @@ -47,12 +51,12 @@ pub struct AdminKey { pub struct AdminAccessToken { pub token: String, pub id: AdminID, - pub last_refresh: u64 + pub last_refresh: u64, } /// New admin general settings pub struct NewAdminGeneralSettings { pub id: AdminID, pub name: String, - pub email: String + pub email: String, } \ No newline at end of file diff --git a/src/data/mod.rs b/src/data/mod.rs index 599c6df..71b16e1 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -41,4 +41,5 @@ pub mod call_signal; pub mod new_notifications_settings; pub mod push_notification; pub mod presence; -pub mod admin; \ No newline at end of file +pub mod admin; +pub mod webauthn_config; \ No newline at end of file diff --git a/src/data/webauthn_config.rs b/src/data/webauthn_config.rs new file mode 100644 index 0000000..7f1a7f9 --- /dev/null +++ b/src/data/webauthn_config.rs @@ -0,0 +1,36 @@ +//! # Webauthn config +//! +//! @author Pierre Hubert + +use webauthn_rs::{Webauthn, WebauthnConfig}; + +use crate::data::config::conf; + +pub struct ComunicAdminWebauthnConfig {} + +impl WebauthnConfig for ComunicAdminWebauthnConfig { + fn get_relying_party_name(&self) -> String { + "ComunicAdmin".to_string() + } + + fn get_origin(&self) -> &String { + &conf().admin_url + } + + fn get_relying_party_id(&self) -> String { + self.get_origin() + .replace("https://", "") + .replace("http://", "") + .split(":") + .next() + .unwrap() + .split("/") + .next() + .unwrap() + .to_string() + } +} + +pub fn get_wan() -> Webauthn { + Webauthn::new(ComunicAdminWebauthnConfig {}) +} \ No newline at end of file diff --git a/src/helpers/admin_access_token_helper.rs b/src/helpers/admin_access_token_helper.rs index 7507e1a..ff1b34c 100644 --- a/src/helpers/admin_access_token_helper.rs +++ b/src/helpers/admin_access_token_helper.rs @@ -13,7 +13,7 @@ use crate::utils::date_utils::time; static mut CACHE: Option>>> = None; -/// Initialize this helper +/// Initialize this helper's cache pub fn init() { unsafe { let map = HashMap::new(); diff --git a/src/helpers/admin_key_registration_challenges_helper.rs b/src/helpers/admin_key_registration_challenges_helper.rs new file mode 100644 index 0000000..6e1443a --- /dev/null +++ b/src/helpers/admin_key_registration_challenges_helper.rs @@ -0,0 +1,34 @@ +//! # Administrators key registration challenges helper +//! +//! Allows to temporarily stores keys registration challenges +//! +//! @author Pierre Hubert + +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; + +use webauthn_rs::RegistrationState; + +use crate::data::admin::AdminID; +use crate::data::error::Res; + +static mut CACHE: Option>>> = None; + +/// Initialize this helper's cache +pub fn init() { + unsafe { + let map = HashMap::new(); + CACHE = Some(Arc::new(Mutex::new(map))); + } +} + +/// Store a new entry in the cache +pub fn set(admin: AdminID, key: RegistrationState) -> Res { + let cache = unsafe { + CACHE.as_ref().unwrap().lock() + }; + + cache?.insert(admin, key); + + Ok(()) +} \ No newline at end of file diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index b5a1f2f..6edd76d 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -23,4 +23,5 @@ pub mod independent_push_notifications_service_helper; pub mod firebase_notifications_helper; pub mod forez_presence_helper; pub mod admin_account_helper; -pub mod admin_access_token_helper; \ No newline at end of file +pub mod admin_access_token_helper; +pub mod admin_key_registration_challenges_helper; \ No newline at end of file diff --git a/src/routes.rs b/src/routes.rs index 927b35d..e0c05f2 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -353,5 +353,6 @@ pub fn get_routes() -> Vec { Route::admin_post("/admin/accounts/id", Box::new(admin_account_controller::get_admin_id)), Route::admin_post("/admin/accounts/info", Box::new(admin_account_controller::get_admin_info)), Route::admin_post("/admin/accounts/update_general_settings", Box::new(admin_account_controller::update_general_settings)), + Route::admin_post("/admin/accounts/challenge_register_key", Box::new(admin_account_controller::challenge_register_key)) ] } \ No newline at end of file diff --git a/src/server.rs b/src/server.rs index e3718d3..daab7dc 100644 --- a/src/server.rs +++ b/src/server.rs @@ -17,7 +17,7 @@ use crate::controllers::{rtc_relay_controller, user_ws_controller}; use crate::data::base_request_handler::{BaseRequestHandler, PostFile, RequestValue}; use crate::data::config::Config; use crate::data::http_request_handler::HttpRequestHandler; -use crate::helpers::{api_helper, requests_limit_helper, admin_access_token_helper}; +use crate::helpers::{admin_access_token_helper, admin_key_registration_challenges_helper, api_helper, requests_limit_helper}; use crate::routes::{get_routes, RequestResult, Route, RouteScope}; use crate::routes::Method::{GET, POST}; use crate::utils::user_data_utils::user_data_path; @@ -221,7 +221,7 @@ fn process_simple_route(route: &Route, req: &mut HttpRequestHandler) -> RequestR if route.need_login || req.has_post_parameter("token") { req.check_user_token()?; } - }, + } // "Admin" user scope RouteScope::ADMIN => { @@ -234,7 +234,6 @@ fn process_simple_route(route: &Route, req: &mut HttpRequestHandler) -> RequestR } - let res: RequestResult = (route.func)(req); requests_limit_helper::trigger_after(res.is_ok(), req, route)?; @@ -350,8 +349,8 @@ pub async fn start_server(conf: &Config) -> std::io::Result<()> { // Initialize limit helper requests_limit_helper::init(); - admin_access_token_helper::init(); + admin_key_registration_challenges_helper::init(); let addr = conf.server_listen_address(); println!("Start to listen on http://{}/", addr);