//! # Admin keys controller //! //! @author Pierre Hubert use bcrypt::verify; 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_access_token_helper, admin_account_helper, admin_account_key_helper, admin_key_authentication_challenges_helper, admin_key_registration_challenges_helper}; use crate::helpers::admin_log_helper::log_admin_action; use crate::routes::RequestResult; impl HttpRequestHandler { pub fn post_admin_auth_key(&mut self, name_mail: &str, name_key_id: &str) -> Res<AdminKey> { 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 an admin keys pub 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::<Vec<AdminKeyAPI>>()) } /// Generate a challenge to register a new key pub fn challenge_register_key(r: &mut HttpRequestHandler) -> RequestResult { let wan = get_wan(); let (res, state) = wan.generate_challenge_register(&r.admin_id()?.id_str(), false)?; admin_key_registration_challenges_helper::set(r.admin_id()?, state)?; r.set_response(res) } /// Register key pub 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.register_credential(&creds, &state, |_| Ok(false))?; let key_id = admin_account_key_helper::add_key(r.admin_id()?, &key_name, key.0, 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 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()? { unimplemented!(); // TODO } 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 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])?; admin_key_authentication_challenges_helper::set(key.id, auth_state)?; r.set_response(challenge_response) } /// Authenticate a user with a security key pub 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 let state = get_wan().authenticate_credential(&credentials, &state)?; if !state.1.user_present { r.forbidden("Invalid key!".to_string())?; } // 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)) }