diff --git a/src/controllers/admin/admin_account_controller.rs b/src/controllers/admin/admin_account_controller.rs index 493b370..364c606 100644 --- a/src/controllers/admin/admin_account_controller.rs +++ b/src/controllers/admin/admin_account_controller.rs @@ -8,14 +8,34 @@ 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; use crate::api_data::admin::admin_info_api::AdminInfoAPI; -use crate::data::admin::NewAdminGeneralSettings; +use crate::data::admin::{AdminKey, NewAdminGeneralSettings}; use crate::data::base_request_handler::BaseRequestHandler; +use crate::data::error::Res; use crate::data::http_request_handler::HttpRequestHandler; use crate::data::webauthn_config::get_wan; -use crate::helpers::{admin_access_token_helper, admin_account_helper, admin_account_key_helper, admin_key_registration_challenges_helper}; +use crate::helpers::{admin_access_token_helper, admin_account_helper, admin_account_key_helper, admin_key_authentication_challenges_helper, admin_key_registration_challenges_helper}; use crate::routes::RequestResult; use crate::utils::date_utils::time; +impl HttpRequestHandler { + pub fn post_admin_auth_key(&mut self, name_mail: &str, name_key_id: &str) -> Res { + let mail = self.post_string(name_mail)?; + let key_id = self.post_u64(name_key_id)?; + + let admin = admin_account_helper::find_admin_by_email(&mail)?; + let keys = admin_account_key_helper::get_admin_keys(admin.id)?; + + let key = keys.into_iter() + .filter(|k| k.id == key_id) + .next(); + + match key { + Some(key) => Ok(key), + None => Err(self.bad_request("The key is not associated with this account!".to_string()).unwrap_err()) + } + } +} + /// Get admin auth options pub fn get_auth_options(r: &mut HttpRequestHandler) -> RequestResult { let mail = r.post_email("mail")?; @@ -122,4 +142,16 @@ pub fn register_key(r: &mut HttpRequestHandler) -> RequestResult { admin_account_key_helper::add_key(r.admin_id()?, &name, key)?; r.ok() +} + +/// Generate a challenge to authenticate with a security key +pub fn challenge_auth_with_key(r: &mut HttpRequestHandler) -> RequestResult { + let key = r.post_admin_auth_key("mail", "key_id")?; + + let (challenge_response, auth_state) = + get_wan().generate_challenge_authenticate(vec![key.key], None)?; + + admin_key_authentication_challenges_helper::set(key.id, auth_state)?; + + r.set_response(challenge_response) } \ No newline at end of file diff --git a/src/helpers/admin_key_authentication_challenges_helper.rs b/src/helpers/admin_key_authentication_challenges_helper.rs new file mode 100644 index 0000000..e4e1310 --- /dev/null +++ b/src/helpers/admin_key_authentication_challenges_helper.rs @@ -0,0 +1,41 @@ +//! # Administrators key authentication challenges helper +//! +//! Allows to temporarily stores keys authentication challenges +//! +//! @author Pierre Hubert + +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; + +use webauthn_rs::AuthenticationState; + +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(key_id: u64, state: AuthenticationState) -> Res { + let cache = unsafe { + CACHE.as_ref().unwrap().lock() + }; + + cache?.insert(key_id, state); + + Ok(()) +} + +pub fn get(key_id: u64) -> Res> { + let cache = unsafe { + CACHE.as_ref().unwrap().lock() + }; + + Ok(cache?.remove(&key_id)) +} \ No newline at end of file diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index bf6402e..319e6a3 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -25,4 +25,5 @@ pub mod forez_presence_helper; pub mod admin_account_helper; pub mod admin_account_key_helper; pub mod admin_access_token_helper; -pub mod admin_key_registration_challenges_helper; \ No newline at end of file +pub mod admin_key_registration_challenges_helper; +pub mod admin_key_authentication_challenges_helper; \ No newline at end of file diff --git a/src/routes.rs b/src/routes.rs index b44bc3e..481992e 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -355,5 +355,6 @@ pub fn get_routes() -> Vec { 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)), Route::admin_post("/admin/accounts/register_key", Box::new(admin_account_controller::register_key)), + Route::limited_admin_post_without_login("/admin/accounts/challenge_auth_with_key", Box::new(admin_account_controller::challenge_auth_with_key), LimitPolicy::ANY(10)), ] } \ No newline at end of file diff --git a/src/server.rs b/src/server.rs index daab7dc..790836c 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::{admin_access_token_helper, admin_key_registration_challenges_helper, api_helper, requests_limit_helper}; +use crate::helpers::{admin_access_token_helper, admin_key_authentication_challenges_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; @@ -351,6 +351,7 @@ pub async fn start_server(conf: &Config) -> std::io::Result<()> { requests_limit_helper::init(); admin_access_token_helper::init(); admin_key_registration_challenges_helper::init(); + admin_key_authentication_challenges_helper::init(); let addr = conf.server_listen_address(); println!("Start to listen on http://{}/", addr);