1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-12-26 05:28:50 +00:00

Start to log administrator actions

This commit is contained in:
Pierre HUBERT 2021-07-10 19:09:54 +02:00
parent 81d6996f01
commit 5a13d7beb3
12 changed files with 144 additions and 8 deletions

View File

@ -296,3 +296,11 @@ CREATE TABLE `comunic_admin_roles` (
`role_id` VARCHAR(25) NULL,
`time_insert` INT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `comunic_admin_log` (
`id` INT NOT NULL AUTO_INCREMENT,
`admin_id` INT NULL,
`ip` VARCHAR(40) NULL,
`time` INT NULL,
`action` VARCHAR(100) NULL,
PRIMARY KEY (`id`));

View File

@ -22,3 +22,11 @@ CREATE TABLE `comunic_admin_roles` (
`role_id` VARCHAR(25) NULL,
`time_insert` INT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `comunic_admin_log` (
`id` INT NOT NULL AUTO_INCREMENT,
`admin_id` INT NULL,
`ip` VARCHAR(40) NULL,
`time` INT NULL,
`action` VARCHAR(100) NULL,
PRIMARY KEY (`id`));

View File

@ -65,6 +65,7 @@ pub mod database_tables_names {
pub const ADMIN_LIST_TABLE: &str = "comunic_admin";
pub const ADMIN_KEYS_TABLE: &str = "comunic_admin_key";
pub const ADMIN_ROLES_TABLE: &str = "comunic_admin_roles";
pub const ADMIN_LOGS_TABLE: &str = "comunic_admin_log";
}
/// Push Notifications Database prefix

View File

@ -9,20 +9,26 @@ use crate::api_data::admin::admin_id_api::AdminIDAPI;
use crate::api_data::admin::admin_info_api::AdminInfoAPI;
use crate::api_data::admin::admin_res_create_account::AdminResCreateAccount;
use crate::api_data::admin::admin_res_create_reset_token::AdminResCreateResetToken;
use crate::constants::admin::AdminRole;
use crate::data::admin::{NewAdmin, NewAdminGeneralSettings};
use crate::data::admin_action_log::AdminAction;
use crate::data::base_request_handler::BaseRequestHandler;
use crate::data::http_request_handler::HttpRequestHandler;
use crate::helpers::{admin_access_token_helper, admin_account_helper, admin_account_key_helper};
use crate::helpers::admin_log_helper::log_admin_action;
use crate::routes::RequestResult;
use crate::utils::date_utils::time;
use crate::constants::admin::AdminRole;
/// Create a new administrator account
pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
let email = r.post_email("mail")?;
let name = r.post_string_opt("name", 3, true)?;
let admin_id = admin_account_helper::create(&NewAdmin { name, email })?;
let new_admin = NewAdmin { name, email };
let admin_id = admin_account_helper::create(&new_admin)?;
log_admin_action(r.admin_id()?, &r.remote_ip(),
AdminAction::CreatedAdmin { id: admin_id, name: new_admin.name, email: new_admin.email })?;
r.set_response(AdminResCreateAccount::new(admin_id))
}
@ -52,6 +58,9 @@ pub fn auth_with_reset_token(r: &mut HttpRequestHandler) -> RequestResult {
let token = admin_access_token_helper::create(admin.id)?;
log_admin_action(admin.id, &r.remote_ip(),
AdminAction::AuthWithResetToken)?;
r.set_response(AdminAuthSuccess::new(token))
}
@ -102,10 +111,13 @@ pub fn update_general_settings(r: &mut HttpRequestHandler) -> RequestResult {
admin_account_helper::set_general_settings(NewAdminGeneralSettings {
id: admin_id,
name: new_name,
email: new_email,
name: new_name.to_string(),
email: new_email.to_string(),
})?;
log_admin_action(r.admin_id()?, &r.remote_ip(),
AdminAction::UpdatedAdminGeneralSettings { target: admin_id, new_name, new_email })?;
r.ok()
}
@ -119,5 +131,8 @@ pub fn generate_reset_token(r: &mut HttpRequestHandler) -> RequestResult {
let token = admin_account_helper::create_new_reset_token(admin_id)?;
log_admin_action(r.admin_id()?, &r.remote_ip(),
AdminAction::GeneratedAdminResetToken { target: admin_id })?;
r.set_response(AdminResCreateResetToken::new(token))
}

View File

@ -4,15 +4,17 @@
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;
use crate::api_data::admin::admin_keys_api::AdminKeyAPI;
use crate::constants::admin::AdminRole;
impl HttpRequestHandler {
pub fn post_admin_auth_key(&mut self, name_mail: &str, name_key_id: &str) -> Res<AdminKey> {
@ -73,6 +75,9 @@ pub fn register_key(r: &mut HttpRequestHandler) -> RequestResult {
admin_account_key_helper::add_key(r.admin_id()?, &name, key)?;
log_admin_action(r.admin_id()?, &r.remote_ip(),
AdminAction::RegisteredAdminKey { name, target: r.admin_id()? })?;
r.ok()
}
@ -87,6 +92,9 @@ pub fn delete_auth_key(r: &mut HttpRequestHandler) -> RequestResult {
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 { name: key.name.to_string(), target: admin_id })?;
admin_account_key_helper::delete_key(key)?;
return r.ok();
@ -125,5 +133,8 @@ pub fn auth_with_key(r: &mut HttpRequestHandler) -> RequestResult {
// 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))
}

View File

@ -4,8 +4,10 @@
use crate::api_data::admin::admin_role_api::AdminRoleDetailsAPI;
use crate::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
use crate::data::admin_action_log::AdminAction;
use crate::data::base_request_handler::BaseRequestHandler;
use crate::data::http_request_handler::HttpRequestHandler;
use crate::helpers::admin_log_helper::log_admin_action;
use crate::helpers::admin_roles_helper;
use crate::routes::RequestResult;
@ -30,8 +32,13 @@ pub fn toggle(r: &mut HttpRequestHandler) -> RequestResult {
if !enable {
admin_roles_helper::remove_role(admin_id, role)?;
log_admin_action(r.admin_id()?, &r.remote_ip(),
AdminAction::RemoveAdminRole { target: admin_id, role: role_str })?;
} else if !admin_roles_helper::has_role(admin_id, role)? {
admin_roles_helper::add_role(admin_id, role)?;
log_admin_action(r.admin_id()?, &r.remote_ip(),
AdminAction::AddAdminRole { target: admin_id, role: role_str })?;
}
r.ok()

View File

@ -2,9 +2,12 @@
//!
//! @author Pierre Hubert
use mysql::serde::{Deserializer, Serializer};
use serde::{Deserialize, Serialize};
use webauthn_rs::proto::Credential;
use crate::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
use crate::data::u64_visitor::U64Visitor;
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub struct AdminID(u64);
@ -82,4 +85,18 @@ impl AdminRole {
.next()
.expect("Should have found a role!!!")
}
}
impl Serialize for AdminID {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
S: Serializer {
serializer.serialize_u64(self.0)
}
}
impl<'de> Deserialize<'de> for AdminID {
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where
D: Deserializer<'de> {
deserializer.deserialize_u64(U64Visitor {}).map(|id| AdminID::new(id))
}
}

View File

@ -0,0 +1,26 @@
//! # Admin action log
use crate::data::admin::AdminID;
#[derive(serde::Serialize, serde::Deserialize)]
pub enum AdminAction {
AuthWithResetToken,
AuthWithAccessKey { key: String, key_id: u64 },
RegisteredAdminKey { name: String, target: AdminID },
DeletedAdminKey { name: String, target: AdminID },
GeneratedAdminResetToken { target: AdminID },
CreatedAdmin { id: AdminID, name: String, email: String },
UpdatedAdminGeneralSettings { target: AdminID, new_email: String, new_name: String },
AddAdminRole { target: AdminID, role: String },
RemoveAdminRole { target: AdminID, role: String },
UnsupportedAction,
}
pub struct AdminActionLog {
pub id: u64,
pub admin_id: AdminID,
pub ip: String,
pub time: u64,
pub action: AdminAction,
}

View File

@ -42,4 +42,6 @@ pub mod new_notifications_settings;
pub mod push_notification;
pub mod presence;
pub mod admin;
pub mod webauthn_config;
pub mod webauthn_config;
pub mod admin_action_log;
pub mod u64_visitor;

20
src/data/u64_visitor.rs Normal file
View File

@ -0,0 +1,20 @@
use std::fmt;
use std::fmt::Formatter;
use mysql::serde::de::Error;
use serde::de::Visitor;
pub struct U64Visitor;
impl<'de> Visitor<'de> for U64Visitor {
type Value = u64;
fn expecting<'a>(&self, formatter: &mut Formatter<'a>) -> fmt::Result {
formatter.write_str("An unsigned integer value")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> where
E: Error, {
Ok(v)
}
}

View File

@ -0,0 +1,20 @@
//! # Admin logs management
//!
//! @author Pierre Hubert
use crate::constants::database_tables_names::ADMIN_LOGS_TABLE;
use crate::data::admin::AdminID;
use crate::data::admin_action_log::AdminAction;
use crate::data::error::Res;
use crate::helpers::database;
use crate::utils::date_utils::time;
/// Record an administrator action
pub fn log_admin_action(admin: AdminID, ip: &str, action: AdminAction) -> Res {
database::InsertQuery::new(ADMIN_LOGS_TABLE)
.add_admin_id("admin_id", admin)
.add_str("ip", ip)
.add_u64("time", time())
.add_str("action", &serde_json::to_string(&action)?)
.insert_drop_result()
}

View File

@ -27,4 +27,5 @@ pub mod admin_account_key_helper;
pub mod admin_access_token_helper;
pub mod admin_key_registration_challenges_helper;
pub mod admin_key_authentication_challenges_helper;
pub mod admin_roles_helper;
pub mod admin_roles_helper;
pub mod admin_log_helper;