//! # Admin keys controller //! //! @author Pierre Hubert use bcrypt::verify; use webauthn_rs::prelude::Uuid; use crate::api_data::admin::admin_auth_success::AdminAuthSuccess; use crate::api_data::admin::admin_keys_api::AdminKeyAPI; use crate::constants::admin::AdminRole; use crate::data::admin::AdminKey; use crate::data::admin_action_log::AdminAction; 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_log_helper::log_admin_action; 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; 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().find(|k| k.id == key_id); match key { Some(key) => Ok(key), None => Err(self .bad_request("The key is not associated with this account!".to_string()) .unwrap_err()), } } } /// Get an admin keys pub async fn get_keys_list(r: &mut HttpRequestHandler) -> RequestResult { let admin_id = r.post_admin_id("id")?; if admin_id != r.admin_id()? { r.check_admin_has_role(AdminRole::MANAGE_ADMINS)?; } let keys = admin_account_key_helper::get_admin_keys(admin_id)?; r.set_response( keys.iter() .map(AdminKeyAPI::new) .collect::>(), ) } /// Generate a challenge to register a new key pub async fn challenge_register_key(r: &mut HttpRequestHandler) -> RequestResult { let wan = get_wan(); let user_info = admin_account_helper::find_admin_by_id(r.admin_id()?)?; let (res, state) = wan.start_passkey_registration(Uuid::new_v4(), &user_info.name, &user_info.name, None)?; admin_key_registration_challenges_helper::set(r.admin_id()?, state)?; r.set_response(res) } /// Register key pub async fn register_key(r: &mut HttpRequestHandler) -> RequestResult { let key_name = r.post_string("name")?; let key_password = r.post_string("password")?; let creds = r.post_register_public_key_credential("key")?; let state = r.some_or_internal_error( admin_key_registration_challenges_helper::get(r.admin_id()?)?, "No challenge found!", )?; let wan = get_wan(); let key = wan.finish_passkey_registration(&creds, &state)?; let key_id = admin_account_key_helper::add_key(r.admin_id()?, &key_name, key, key_password)?; log_admin_action( r.admin_id()?, &r.remote_ip(), AdminAction::RegisteredAdminKey { key_id, key_name, target: r.admin_id()?, }, )?; r.ok() } /// Delete an admin auth key pub async fn delete_auth_key(r: &mut HttpRequestHandler) -> RequestResult { let admin_id = r.post_admin_id("adminID")?; let key_id = r.post_u64("keyID")?; if admin_id != r.admin_id()? { r.check_admin_has_role(AdminRole::MANAGE_ADMINS)?; } for key in admin_account_key_helper::get_admin_keys(admin_id)? { if key.id == key_id { log_admin_action( r.admin_id()?, &r.remote_ip(), AdminAction::DeletedAdminKey { key_id, key_name: key.name.to_string(), target: admin_id, }, )?; admin_account_key_helper::delete_key(key)?; return r.ok(); } } r.not_found("Requested key was not found!".to_string()) } /// Generate a challenge to authenticate with a security key pub async 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().start_passkey_authentication(&[key.key])?; admin_key_authentication_challenges_helper::set(key.id, auth_state)?; r.set_response(challenge_response) } /// Authenticate a user with a security key pub async fn auth_with_key(r: &mut HttpRequestHandler) -> RequestResult { let key = r.post_admin_auth_key("mail", "key_id")?; let credentials = r.post_auth_public_key_credential("credential")?; let state = r.some_or_internal_error( admin_key_authentication_challenges_helper::get(key.id)?, "Associated authentication state not found!", )?; // Perform authentication get_wan().finish_passkey_authentication(&credentials, &state)?; // Check key password (if any) if let Some(pass_hash) = key.password { let password = r.post_string("password")?; if !verify(password, &pass_hash)? { r.forbidden("Bad key password!".to_string())?; } } // Generate access token let token = admin_access_token_helper::create(key.admin_id)?; log_admin_action( key.admin_id, &r.remote_ip(), AdminAction::AuthWithAccessKey { key: key.name, key_id: key.id, }, )?; r.set_response(AdminAuthSuccess::new(token)) }