From 4924e0d6bcd784fd3011ede2c83e3eb7370379be Mon Sep 17 00:00:00 2001 From: Jose Gonzalez Date: Tue, 14 Dec 2021 12:06:20 +0100 Subject: [PATCH] Updated audit logs view and added controller --- .../extras/delete_files/delete_files.txt | 3 +- pandora_console/godmode/admin_access_logs.php | 277 ------------ pandora_console/godmode/audit_log.php | 71 +++ pandora_console/godmode/menu.php | 4 +- .../include/class/AuditLog.class.php | 404 ++++++++++++++++++ 5 files changed, 479 insertions(+), 280 deletions(-) delete mode 100644 pandora_console/godmode/admin_access_logs.php create mode 100644 pandora_console/godmode/audit_log.php create mode 100644 pandora_console/include/class/AuditLog.class.php diff --git a/pandora_console/extras/delete_files/delete_files.txt b/pandora_console/extras/delete_files/delete_files.txt index 50f79eb02f..a809818909 100644 --- a/pandora_console/extras/delete_files/delete_files.txt +++ b/pandora_console/extras/delete_files/delete_files.txt @@ -114,4 +114,5 @@ enterprise/include/javascript/tooltipster.bundle.min.js enterprise/include/styles/tooltipster.bundle.min.css mobile/include/javascript/jquery.mobile-1.3.1.js mobile/include/style/jquery.mobile-1.3.1.css -godmode/alerts/configure_alert_special_days.php \ No newline at end of file +godmode/alerts/configure_alert_special_days.php +godmode/admin_access_logs.php \ No newline at end of file diff --git a/pandora_console/godmode/admin_access_logs.php b/pandora_console/godmode/admin_access_logs.php deleted file mode 100644 index f635e945c3..0000000000 --- a/pandora_console/godmode/admin_access_logs.php +++ /dev/null @@ -1,277 +0,0 @@ - __( - 'Export to CSV' - ),'class' => 'invert_filter', - ] -); -$header_buttons = [ - 'csv' => [ - 'active' => false, - 'text' => ''.$csv_img.'', - ], -]; - -ui_print_page_header(__('%s audit', get_product_name()).' » '.__('Review Logs'), 'images/gm_log.png', false, '', true, $header_buttons); - -$table = new stdClass(); -$table->class = 'databox filters'; -$table->cellstyle = []; -$table->cellstyle[0] = []; -$table->cellstyle[1] = []; -$table->cellstyle[0][0] = 'text-align: right;'; -$table->cellstyle[0][1] = 'text-align: left;'; -$table->cellstyle[0][2] = 'text-align: right;'; -$table->cellstyle[0][3] = 'text-align: left;'; -$table->cellstyle[0][4] = 'text-align: right;'; -$table->cellstyle[0][5] = 'text-align: left;'; -$table->cellstyle[1][0] = 'text-align: right;'; -$table->cellstyle[1][1] = 'text-align: left;'; -$table->cellstyle[1][2] = 'text-align: right;'; -$table->cellstyle[1][3] = 'text-align: left;'; -$table->cellstyle[1][5] = 'text-align: right;'; -$table->data = []; - -$data = []; - -$data[0] = ''.__('Search').''; -$data[1] = html_print_input_text('filter_text', $filter_text, __('Free text for search (*)'), 20, 40, true); - -$data[2] = ''.__('Max. hours old').''; -$data[3] = html_print_input_text('filter_period', $filter_period, __('Max. hours old'), 3, 6, true); - -$data[4] = ''.__('IP').''; -$data[5] = html_print_input_text('filter_ip', $filter_ip, __('IP'), 15, 15, true); - -$table->data[0] = $data; -$data = []; - -$actions_sql = 'SELECT DISTINCT(accion), accion AS text FROM tsesion'; -$data[0] = ''.__('Action').''; -$data[1] = html_print_select_from_sql($actions_sql, 'filter_type', $filter_type, '', __('All'), '', true); - -$users_sql = 'SELECT id_user, id_user AS text FROM tusuario'; -$data[2] = ''.__('User').''; -$data[3] = html_print_select_from_sql($users_sql, 'filter_user', $filter_user, '', __('All'), '', true); - -$data[4] = ''; -$data[5] = html_print_submit_button(__('Filter'), 'filter', false, 'class="sub search"', true); - -$table->data[1] = $data; - -$form = '
'; -$form .= html_print_table($table, true); -$form .= '
'; -ui_toggle($form, __('Filter'), '', '', false); - -$filter = '1=1'; - -if (!empty($filter_type)) { - $filter .= sprintf(" AND accion = '%s'", $filter_type); -} - -if (!empty($filter_user)) { - $filter .= sprintf(" AND id_usuario = '%s'", $filter_user); -} - -if (!empty($filter_text)) { - $filter .= sprintf(" AND (accion LIKE '%%%s%%' OR descripcion LIKE '%%%s%%')", $filter_text, $filter_text); -} - -if (!empty($filter_ip)) { - $filter .= sprintf(" AND ip_origen LIKE '%%%s%%'", $filter_ip); -} - -if (!empty($filter_period)) { - switch ($config['dbtype']) { - case 'mysql': - $filter .= ' AND fecha >= DATE_ADD(NOW(), INTERVAL -'.$filter_period.' HOUR)'; - break; - - case 'postgresql': - $filter .= ' AND fecha >= NOW() - INTERVAL \''.$filter_period.' HOUR \''; - break; - - case 'oracle': - $filter .= ' AND fecha >= (SYSTIMESTAMP - INTERVAL \''.$filter_period.'\' HOUR)'; - break; - } -} - -$count_sql = sprintf('SELECT COUNT(*) FROM tsesion WHERE %s', $filter); -$count = (int) db_get_value_sql($count_sql); -$url = 'index.php?sec=godmode&sec2=godmode/admin_access_logs'.$filter_query; -ui_pagination($count, $url); - -switch ($config['dbtype']) { - case 'mysql': - $sql = sprintf( - 'SELECT * - FROM tsesion - WHERE %s - ORDER BY fecha DESC - LIMIT %d, %d', - $filter, - $offset, - $config['block_size'] - ); - break; - - case 'postgresql': - $sql = sprintf( - 'SELECT * - FROM tsesion - WHERE %s - ORDER BY fecha DESC - LIMIT %d OFFSET %d', - $filter, - $config['block_size'], - $offset - ); - break; - - case 'oracle': - $set = []; - $set['limit'] = $config['block_size']; - $set['offset'] = $offset; - $sql = sprintf( - 'SELECT * - FROM tsesion - WHERE %s - ORDER BY fecha DESC', - $filter - ); - $result = oracle_recode_query($sql, $set); - break; -} - -$result = db_get_all_rows_sql($sql); -if (empty($result)) { - $result = []; -} - -$table = new stdClass(); -$table->cellpadding = 0; -$table->cellspacing = 0; -$table->width = '100%'; -$table->class = 'info_table'; -$table->size = []; -$table->data = []; -$table->head = []; -$table->align = []; -$table->rowclass = []; - -$table->head[0] = __('User'); -$table->head[1] = __('Action'); -$table->head[2] = __('Date'); -$table->head[3] = __('Source IP'); -$table->head[4] = __('Comments'); -if ($enterprise_include !== ENTERPRISE_NOT_HOOK) { - $table->head[5] = enterprise_hook('tableHeadEnterpriseAudit', ['title1']); - $table->head[6] = enterprise_hook('tableHeadEnterpriseAudit', ['title2']); -} - -$table->size[0] = 80; -$table->size[2] = 130; -$table->size[3] = 100; -$table->size[4] = 200; -if ($enterprise_include !== ENTERPRISE_NOT_HOOK) { - $table->size[5] = enterprise_hook('tableHeadEnterpriseAudit', ['size1']); - $table->size[6] = enterprise_hook('tableHeadEnterpriseAudit', ['size2']); - $table->align[5] = enterprise_hook('tableHeadEnterpriseAudit', ['align']); - $table->align[6] = enterprise_hook('tableHeadEnterpriseAudit', ['align2']); -} - -$table->colspan = []; -$table->rowstyle = []; - -$rowPair = true; -$iterator = 0; - -// Get data -foreach ($result as $row) { - $iterator++; - - $table->rowclass[] = $rowPair ? 'rowPair' : 'rowOdd'; - $rowPair = !$rowPair; - - $data = []; - $data[0] = io_safe_output($row['id_usuario']); - $data[1] = ui_print_session_action_icon($row['accion'], true).$row['accion']; - $data[2] = ui_print_help_tip(date($config['date_format'], $row['utimestamp']), true).ui_print_timestamp($row['utimestamp'], true); - $data[3] = io_safe_output($row['ip_origen']); - $data[4] = io_safe_output($row['descripcion']); - - if ($enterprise_include !== ENTERPRISE_NOT_HOOK) { - $data[5] = enterprise_hook('cell1EntepriseAudit', [$row['id_sesion']]); - $data[6] = enterprise_hook('cell2EntepriseAudit', [$row['id_sesion']]); - } - - $table->data[] = $data; - - if ($enterprise_include !== ENTERPRISE_NOT_HOOK) { - rowEnterpriseAudit($table, $iterator, $row['id_sesion']); - } -} - -foreach ($table->rowclass as $key => $value) { - if (strpos($value, 'limit_scroll') !== false) { - $table->colspan[$key] = [7]; - } else { - if ($enterprise_include !== ENTERPRISE_NOT_HOOK) { - $table->cellclass[$key][6] = 'action_buttons'; - } - } -} - -html_print_table($table); -ui_pagination($count, $url, 0, 0, false, 'offset', true, 'pagination-bottom'); - -if ($enterprise_include !== ENTERPRISE_NOT_HOOK) { - enterprise_hook('enterpriseAuditFooter'); -} diff --git a/pandora_console/godmode/audit_log.php b/pandora_console/godmode/audit_log.php new file mode 100644 index 0000000000..fbded7819e --- /dev/null +++ b/pandora_console/godmode/audit_log.php @@ -0,0 +1,71 @@ + '[AuditLog]'.$e->getMessage() ]); + exit; + } else { + echo '[AuditLog]'.$e->getMessage(); + } + + // Stop this execution, but continue 'globally'. + return; +} + +// AJAX controller. +if ((bool) is_ajax() === true) { + $method = get_parameter('method'); + + if (method_exists($controller, $method) === true) { + if ($controller->ajaxMethod($method) === true) { + $controller->{$method}(); + } else { + $controller->error('Unavailable method.'); + } + } else { + $controller->error('Method not found. ['.$method.']'); + } + + // Stop any execution. + exit; +} else { + // Run. + $controller->run(); +} diff --git a/pandora_console/godmode/menu.php b/pandora_console/godmode/menu.php index 18237feb17..16bf0f256e 100644 --- a/pandora_console/godmode/menu.php +++ b/pandora_console/godmode/menu.php @@ -385,8 +385,8 @@ if (check_acl($config['id_user'], 0, 'PM') || check_acl($config['id_user'], 0, ' if (check_acl($config['id_user'], 0, 'PM')) { // Audit //meter en extensiones. - $sub['godmode/admin_access_logs']['text'] = __('System audit log'); - $sub['godmode/admin_access_logs']['id'] = 'System audit log'; + $sub['godmode/audit_log']['text'] = __('System audit log'); + $sub['godmode/audit_log']['id'] = 'System audit log'; $sub['godmode/setup/links']['text'] = __('Links'); $sub['godmode/setup/links']['id'] = 'Links'; $sub['tools/diagnostics']['text'] = __('Diagnostic info'); diff --git a/pandora_console/include/class/AuditLog.class.php b/pandora_console/include/class/AuditLog.class.php new file mode 100644 index 0000000000..253d44ad59 --- /dev/null +++ b/pandora_console/include/class/AuditLog.class.php @@ -0,0 +1,404 @@ +ajaxController = $ajaxController; + + } + + + /** + * Run view + * + * @return void + */ + public function run() + { + // Javascript. + ui_require_jquery_file('pandora'); + // CSS. + ui_require_css_file('wizard'); + ui_require_css_file('discovery'); + // Datatables list. + try { + $columns = [ + 'id_usuario', + 'accion', + 'fecha', + 'ip_origen', + 'descripcion', + ]; + + $column_names = [ + __('User'), + __('Action'), + __('Date'), + __('Source IP'), + __('Comments'), + ]; + + if (enterprise_installed() === true) { + array_push( + $columns, + [ + 'text' => 'security', + 'class' => 'w80px action_buttons show_security_info', + ], + [ + 'text' => 'action', + 'class' => 'w80px action_buttons show_extended_info', + ] + ); + + array_push($column_names, __('S.'), __('A.')); + } + + $this->tableId = 'audit_logs'; + + // Header (only in Node). + if (is_metaconsole() === false) { + ui_print_standard_header( + __('%s audit', get_product_name()).' » '.__('Review Logs'), + 'images/gm_log.png', + false, + '', + false, + [], + [ + [ + 'link' => '', + 'label' => __('Admin Tools'), + ], + [ + 'link' => '', + 'label' => __('System Audit log'), + ], + ] + ); + } + + // Only in case of Metaconsole, format the frame. + open_meta_frame(); + // Load datatables user interface. + ui_print_datatable( + [ + 'id' => $this->tableId, + 'class' => 'info_table', + 'style' => 'width: 100%', + 'columns' => $columns, + 'column_names' => $column_names, + 'ajax_url' => $this->ajaxController, + 'ajax_data' => ['method' => 'draw'], + 'ajax_postprocces' => 'process_datatables_item(item)', + 'no_sortable_columns' => [-1], + 'order' => [ + 'field' => 'date', + 'direction' => 'asc', + ], + 'search_button_class' => 'sub filter float-right', + 'form' => [ + 'inputs' => [ + [ + 'label' => __('Search'), + 'type' => 'text', + 'class' => 'w200px', + 'id' => 'filter_text', + 'name' => 'filter_text', + ], + [ + 'label' => __('Max. hours old'), + 'type' => 'text', + 'class' => 'w100px', + 'id' => 'filter_period', + 'name' => 'filter_period', + ], + [ + 'label' => __('IP'), + 'type' => 'text', + 'class' => 'w100px', + 'id' => 'filter_ip', + 'name' => 'filter_ip', + ], + [ + 'label' => __('Action'), + 'type' => 'select_from_sql', + 'nothing' => __('All'), + 'nothing_value' => '-1', + 'sql' => 'SELECT DISTINCT(accion), accion AS text FROM tsesion', + 'class' => 'mw250px', + 'id' => 'filter_type', + 'name' => 'filter_type', + ], + [ + 'label' => __('User'), + 'type' => 'select_from_sql', + 'nothing' => __('All'), + 'nothing_value' => '-1', + 'sql' => 'SELECT id_user, id_user AS text FROM tusuario', + 'class' => 'mw250px', + 'id' => 'filter_user', + 'name' => 'filter_user', + ], + ], + ], + ] + ); + } catch (Exception $e) { + echo $e->getMessage(); + } + + // Close the frame. + close_meta_frame(); + // Load own javascript file. + echo $this->loadJS(); + + } + + + /** + * Get the data for draw the table. + * + * @return void. + */ + public function draw() + { + global $config; + // Initialice filter. + $filter = '1=1'; + // Init data. + $data = []; + // Count of total records. + $count = 0; + // Catch post parameters. + $start = get_parameter('start', 0); + $length = get_parameter('length', $config['block_size']); + $order = get_datatable_order(); + $filters = get_parameter('filter', []); + $this->filterType = $filters['filter_type']; + $this->filterUser = $filters['filter_user']; + $this->filterText = $filters['filter_text']; + $this->filterPeriod = (empty($filters['filter_period']) === false) ? $filters['filter_period'] : 24; + $this->filterIp = $filters['filter_ip']; + + if (empty($this->filterType) === false && $this->filterType !== '-1') { + $filter .= sprintf(" AND accion = '%s'", $this->filterType); + } + + if (empty($this->filterUser) === false && $this->filterUser !== '-1') { + $filter .= sprintf(" AND id_usuario = '%s'", $this->filterUser); + } + + if (empty($this->filterText) === false) { + $filter .= sprintf( + " AND (accion LIKE '%%%s%%' OR descripcion LIKE '%%%s%%')", + $this->filterText, + $this->filterText + ); + } + + if (empty($this->filterIp) === false) { + $filter .= sprintf(" AND ip_origen LIKE '%%%s%%'", $this->filterIp); + } + + if (empty($this->filterPeriod) === false) { + $filter .= sprintf(' AND fecha >= DATE_ADD(NOW(), INTERVAL -%d HOUR)', $this->filterPeriod); + } + + $count = (int) db_get_value_sql(sprintf('SELECT COUNT(*) as "total" FROM tsesion WHERE %s', $filter)); + + $sql = sprintf( + 'SELECT * + FROM tsesion + WHERE %s + ORDER BY %s + LIMIT %d, %d', + $filter, + $order, + $start, + $length + ); + $data = db_get_all_rows_sql($sql); + + if (empty($data) === false) { + $data = array_reduce( + $data, + function ($carry, $item) { + global $config; + // Transforms array of arrays $data into an array + // of objects, making a post-process of certain fields. + $tmp = (object) $item; + + $tmp->id_usuario = io_safe_output($tmp->id_usuario); + $tmp->ip_origen = io_safe_output($tmp->ip_origen); + $tmp->descripcion = io_safe_output($tmp->descripcion); + $tmp->accion = ui_print_session_action_icon($tmp->accion, true).$tmp->accion; + $tmp->utimestamp = ui_print_help_tip( + date( + $config['date_format'], + $tmp->utimestamp + ), + true + ).ui_print_timestamp($tmp->utimestamp, true); + + if (enterprise_installed() === true) { + $tmp->security = enterprise_hook('cell1EntepriseAudit', [$tmp->id_sesion]); + $tmp->action = enterprise_hook('cell2EntepriseAudit', []); + $tmp->extendedInfo = enterprise_hook('rowEnterpriseAudit', [$tmp->id_sesion]); + } + + $carry[] = $tmp; + return $carry; + } + ); + } + + echo json_encode( + [ + 'data' => $data, + 'recordsTotal' => $count, + 'recordsFiltered' => $count, + ] + ); + } + + + /** + * Checks if target method is available to be called using AJAX. + * + * @param string $method Target method. + * + * @return boolean True allowed, false not. + */ + public function ajaxMethod(string $method) + { + return in_array($method, $this->AJAXMethods); + } + + + /** + * Load Javascript code. + * + * @return string. + */ + public function loadJS() + { + // Nothing for this moment. + ob_start(); + + // Javascript content. + ?> + +