Merge branch 'ent-7386-Ocultar-credenciales-de-acceso-a-la-API' into 'develop'

Ent 7386 ocultar credenciales de acceso a la api

See merge request artica/pandorafms!4991
This commit is contained in:
Diego Muñoz-Reja 2023-01-13 12:44:32 +00:00
commit 0435dc09bb
22 changed files with 572 additions and 146 deletions

View File

@ -1 +0,0 @@

View File

@ -1,67 +1,144 @@
<?php
/**
* Pandora FMS API Checker Extension.
*
* @category API
* @package Pandora FMS
* @subpackage Extensions
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2022 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
// Pandora FMS - http://pandorafms.com
// ==================================================
// Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
function api_execute($url, $ip, $pandora_url, $apipass, $user, $password, $op, $op2, $id, $id2, $return_type, $other, $other_mode)
{
if (empty($url)) {
$url = 'http://'.$ip.$pandora_url.'/include/api.php';
// Begin.
$url .= '?';
$url .= 'apipass='.$apipass;
$url .= '&user='.$user;
$url .= '&pass='.$password;
$url .= '&op='.$op;
$url .= '&op2='.$op2;
if ($id !== '') {
$url .= '&id='.$id;
/**
* Api Execution.
*
* @param string $url Url.
* @param string $ip Ip.
* @param string $pandora_url Pandora_url.
* @param string $apipass Apipass.
* @param string $user User.
* @param string $password Password.
* @param string $op Op.
* @param string $op2 Op2.
* @param string $id Id.
* @param string $id2 Id2.
* @param string $return_type Return_type.
* @param string $other Other.
* @param string $other_mode Other_mode.
* @param string $token Token.
*
* @return array.
*/
function api_execute(
string $url,
string $ip,
string $pandora_url,
string $apipass,
string $user,
string $password,
string $op,
string $op2,
string $id='',
string $id2='',
string $return_type='',
string $other='',
string $other_mode='',
string $token=''
) {
$data = [];
if (empty($url) === true) {
$url = 'http://'.$ip.$pandora_url.'/include/api.php?';
if (empty($op) === false) {
$data['op'] = $op;
}
if ($id2 !== '') {
$url .= '&id2='.$id2;
if (empty($op2) === false) {
$data['op2'] = $op2;
}
if ($return_type !== '') {
$url .= '&return_type='.$return_type;
if (empty($id) === false) {
$data['id'] = $id;
}
if ($other !== '') {
$url .= '&other_mode='.$other_mode;
$url .= '&other='.$other;
if (empty($id2) === false) {
$data['id2'] = $id2;
}
if (empty($return_type) === false) {
$data['return_type'] = $return_type;
}
if (empty($other) === false) {
$data['other_mode'] = $other_mode;
$data['other'] = $other;
}
// If token is not reported,use old method.
if (empty($token) === true) {
$data['apipass'] = $apipass;
$data['user'] = $user;
$data['password'] = $password;
}
}
$curlObj = curl_init();
$curlObj = curl_init($url);
if (empty($data) === false) {
$url .= http_build_query($data);
}
// set the content type json
$headers = [
'Content-Type: application/json',
'Authorization: Bearer '.$token,
];
curl_setopt($curlObj, CURLOPT_URL, $url);
curl_setopt($curlObj, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlObj, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curlObj, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($curlObj);
curl_close($curlObj);
$return = [
return [
'url' => $url,
'result' => $result,
];
return $return;
}
/**
* Perform API Checker
*
* @return void.
*/
function extension_api_checker()
{
global $config;
check_login();
if (! check_acl($config['id_user'], 0, 'PM')) {
if ((bool) check_acl($config['id_user'], 0, 'PM') === false) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to access Profile Management'
@ -85,11 +162,12 @@ function extension_api_checker()
$return_type = io_safe_output(get_parameter('return_type', ''));
$other = io_safe_output(get_parameter('other', ''));
$other_mode = io_safe_output(get_parameter('other_mode', 'url_encode_separator_|'));
$token = get_parameter('token');
$api_execute = get_parameter('api_execute', 0);
$api_execute = (bool) get_parameter('api_execute', false);
$return_call_api = '';
if ($api_execute) {
if ($api_execute === true) {
$return_call_api = api_execute(
$url,
$ip,
@ -103,7 +181,8 @@ function extension_api_checker()
urlencode($id2),
$return_type,
urlencode($other),
$other_mode
$other_mode,
$token
);
}
@ -129,6 +208,11 @@ function extension_api_checker()
$row[] = html_print_input_text('pandora_url', $pandora_url, '', 50, 255, true);
$table->data[] = $row;
$row = [];
$row[] = __('API Token').ui_print_help_tip(__('Use API Token instead API Pass, User and Password.'), true);
$row[] = html_print_input_text('token', $token, '', 50, 255, true);
$table->data[] = $row;
$row = [];
$row[] = __('API Pass');
$row[] = html_print_input_password('apipass', $apipass, '', 50, 255, true);
@ -214,7 +298,7 @@ function extension_api_checker()
echo '</div>';
echo '</form>';
if ($api_execute) {
if ($api_execute === true) {
echo '<fieldset>';
echo '<legend>'.__('Result').'</legend>';
echo __('URL').'<br />';

File diff suppressed because one or more lines are too long

View File

@ -1314,7 +1314,7 @@ $row++;
$decimal_separators = [
',' => ',',
'.' => '.'
'.' => '.',
];
$table_other->data[$row][0] = __('Decimal separator');

View File

@ -42,10 +42,7 @@ require_once $config['homedir'].'/include/functions_visual_map.php';
require_once $config['homedir'].'/include/functions_custom_fields.php';
enterprise_include_once('include/functions_profile.php');
$meta = false;
if (enterprise_installed() && defined('METACONSOLE')) {
$meta = true;
}
$meta = is_metaconsole();
$isFunctionSkins = enterprise_include_once('include/functions_skins.php');
@ -55,12 +52,11 @@ if (ENTERPRISE_NOT_HOOK !== enterprise_include('include/functions_policies.php')
$enterprise_include = true;
}
if ($enterprise_include) {
if ($enterprise_include === true) {
enterprise_include_once('meta/include/functions_users_meta.php');
}
if (!is_metaconsole()) {
if (is_metaconsole() === false) {
date_default_timezone_set('UTC');
include 'include/javascript/timezonepicker/includes/parser.inc';
@ -110,13 +106,13 @@ if (!is_metaconsole()) {
// This defines the working user. Beware with this, old code get confusses
// and operates with current logged user (dangerous).
$id = get_parameter('id', get_parameter('id_user', ''));
// ID given as parameter
// ID given as parameter.
$pure = get_parameter('pure', 0);
$user_info = get_user_info($id);
$is_err = false;
if (! check_acl($config['id_user'], 0, 'UM')) {
if ((bool) check_acl($config['id_user'], 0, 'UM') === false) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to access User Management'
@ -126,11 +122,11 @@ if (! check_acl($config['id_user'], 0, 'UM')) {
return;
}
if (is_ajax()) {
if (is_ajax() === true) {
$delete_profile = (bool) get_parameter('delete_profile');
$get_user_profile = (bool) get_parameter('get_user_profile');
if ($delete_profile) {
if ($delete_profile === true) {
$id2 = (string) get_parameter('id_user');
$id_up = (int) get_parameter('id_user_profile');
@ -160,7 +156,7 @@ if (is_ajax()) {
if ($has_profile === false && $user_is_global_admin === false) {
$result = delete_user($id2);
if ($result) {
if ($result === true) {
db_pandora_audit(
AUDIT_LOG_USER_MANAGEMENT,
__('Deleted user %s', io_safe_output($id_user))
@ -173,30 +169,34 @@ if (is_ajax()) {
__('There was a problem deleting the user')
);
// Delete the user in all the consoles
if (defined('METACONSOLE')) {
// Delete the user in all the consoles.
if (is_metaconsole() === true) {
$servers = metaconsole_get_servers();
foreach ($servers as $server) {
// Connect to the remote console
// Connect to the remote console.
metaconsole_connect($server);
// Delete the user
// Delete the user.
$result = delete_user($id_user);
if ($result) {
if ($result === true) {
db_pandora_audit(
AUDIT_LOG_USER_MANAGEMENT,
__('Deleted user %s from metaconsole', io_safe_output($id_user))
);
}
// Restore the db connection
// Restore the db connection.
metaconsole_restore_db();
// Log to the metaconsole too
if ($result) {
// Log to the metaconsole too.
if ($result === true) {
db_pandora_audit(
AUDIT_LOG_USER_MANAGEMENT,
__('Deleted user %s from %s', io_safe_input($id_user), io_safe_input($server['server_name']))
__(
'Deleted user %s from %s',
io_safe_input($id_user),
io_safe_input($server['server_name'])
)
);
}
@ -272,14 +272,8 @@ enterprise_hook('open_meta_frame');
$tab = get_parameter('tab', 'user');
if ($id) {
$header_title = ' &raquo; '.__('Update user');
} else {
$header_title = ' &raquo; '.__('Create user');
}
// Header
if ($meta) {
// Header.
if (is_metaconsole() === true) {
user_meta_print_header();
$sec = 'advanced';
} else {
@ -310,19 +304,34 @@ if ($meta) {
$buttons[$tab]['active'] = true;
ui_print_page_header(
__('User detail editor').$header_title,
ui_print_standard_header(
(empty($id) === false) ? __('Update user') : __('Create user'),
'images/gm_users.png',
false,
'',
true,
$buttons
$buttons,
[
[
'link' => '',
'label' => __('Profiles'),
],
[
'link' => ui_get_full_url('index.php?sec=gusuarios&sec2=godmode/users/user_list'),
'label' => __('Manage users'),
],
[
'link' => '',
'label' => __('User Detail Editor'),
],
]
);
$sec = 'gusuarios';
}
if ($config['user_can_update_info']) {
if ((bool) $config['user_can_update_info'] === true) {
$view_mode = false;
} else {
$view_mode = true;
@ -332,17 +341,18 @@ $new_user = (bool) get_parameter('new_user');
$create_user = (bool) get_parameter('create_user');
$add_profile = (bool) get_parameter('add_profile');
$update_user = (bool) get_parameter('update_user');
$renewAPIToken = (bool) get_parameter('renewAPIToken');
$status = get_parameter('status', -1);
$json_profile = get_parameter('json_profile', '');
// Reset status var if current action is not update_user
if ($new_user || $create_user || $add_profile
|| $delete_profile || $update_user
// Reset status var if current action is not update_user.
if ($new_user === true || $create_user === true || $add_profile === true
|| $delete_profile === true || $update_user === true
) {
$status = -1;
}
if ($new_user && $config['admin_can_add_user']) {
if ($new_user === true && (bool) $config['admin_can_add_user'] === true) {
$user_info = [];
$id = '';
$user_info['fullname'] = '';
@ -366,28 +376,30 @@ if ($new_user && $config['admin_can_add_user']) {
$user_info['section'] = '';
$user_info['data_section'] = '';
// This attributes are inherited from global configuration
// This attributes are inherited from global configuration.
$user_info['block_size'] = $config['block_size'];
if (enterprise_installed() && is_metaconsole() === true) {
if (enterprise_installed() === true && is_metaconsole() === true) {
$user_info['metaconsole_agents_manager'] = 0;
$user_info['metaconsole_access_node'] = 0;
}
if ($config['ehorus_user_level_conf']) {
if ((bool) $config['ehorus_user_level_conf'] === true) {
$user_info['ehorus_user_level_user'] = '';
$user_info['ehorus_user_level_pass'] = '';
$user_info['ehorus_user_level_enabled'] = true;
}
}
if ($create_user) {
if (! $config['admin_can_add_user']) {
ui_print_error_message(__('The current authentication scheme doesn\'t support creating users on %s', get_product_name()));
if ($create_user === true) {
if ((bool) $config['admin_can_add_user'] === false) {
ui_print_error_message(
__('The current authentication scheme doesn\'t support creating users on %s', get_product_name())
);
return;
}
if (html_print_csrf_error()) {
if (html_print_csrf_error() === true) {
return;
}
@ -468,6 +480,8 @@ if ($create_user) {
}
}
// Generate new API token.
$values['api_token'] = api_token_generate();
if (empty($id) === true) {
ui_print_error_message(__('User ID cannot be empty'));
@ -659,7 +673,7 @@ if ($create_user) {
}
if ($update_user) {
if (html_print_csrf_error()) {
if (html_print_csrf_error() === true) {
return;
}
@ -678,6 +692,9 @@ if ($update_user) {
$values['timezone'] = (string) get_parameter('timezone');
$values['default_event_filter'] = (int) get_parameter('default_event_filter');
$values['default_custom_view'] = (int) get_parameter('default_custom_view');
// API Token information.
$apiTokenRenewed = (bool) get_parameter('renewAPIToken');
$values['api_token'] = ($apiTokenRenewed === true) ? api_token_generate() : users_get_API_token($values['id_user']);
if (users_is_admin() === false && (bool) $values['is_admin'] !== false) {
db_pandora_audit(
@ -689,7 +706,7 @@ if ($update_user) {
exit;
}
// eHorus user level conf.
// Ehorus user level conf.
$values['ehorus_user_level_enabled'] = (bool) get_parameter('ehorus_user_level_enabled', false);
$values['ehorus_user_level_user'] = (string) get_parameter('ehorus_user_level_user');
$values['ehorus_user_level_pass'] = (string) get_parameter('ehorus_user_level_pass');
@ -868,7 +885,7 @@ if ($update_user) {
ui_print_result_message(
$res1,
__('User info successfully updated'),
($apiTokenRenewed === true) ? __('You have generated a new API Token.') : __('User info successfully updated'),
__('Error updating user info (no change?)')
);
}
@ -904,7 +921,7 @@ if ($update_user) {
$user_info = $values;
}
if ($status != -1) {
if ((int) $status !== -1) {
ui_print_result_message(
$status,
__('User info successfully updated'),
@ -1029,6 +1046,48 @@ if (!$new_user) {
$user_id .= '<span>'.$id.'</span>';
$user_id .= html_print_input_hidden('id_user', $id, true);
$user_id .= '</div>';
$user_id .= '<div class="label_select_simple"><p class="edit_user_labels">'.__('API Token').'</p>';
$user_id .= html_print_anchor(
[
'onClick' => sprintf(
'javascript:renewAPIToken(\'%s\', \'%s\', \'%s\')',
__('Warning'),
__('The API token will be renewed. After this action, the last token you were using will not work. Are you sure?'),
'user_profile_form',
),
'content' => html_print_image(
'images/icono-refrescar.png',
true,
[
'class' => 'renew_api_token_image clickable',
'title' => __('Renew API Token'),
]
),
'class' => 'renew_api_token_link',
],
true
);
$user_id .= html_print_anchor(
[
'onClick' => sprintf(
'javascript:showAPIToken(\'%s\', \'%s\')',
__('API Token'),
base64_encode(__('Your API Token is:').'&nbsp;<br><span class="font_12pt bolder">'.users_get_API_token($id).'</span><br>&nbsp;'.__('Please, avoid share this string with others.')),
),
'content' => html_print_image(
'images/eye_show.png',
true,
[
'class' => 'renew_api_token_image clickable',
'title' => __('Show API Token'),
]
),
'class' => 'renew_api_token_link',
],
true
);
$user_id .= '</div>';
} else {
$user_id = '<div class="label_select_simple">'.html_print_input_text_extended(
'id_user',
@ -1047,7 +1106,7 @@ if (!$new_user) {
).'</div>';
}
if (is_user_admin($id)) {
if (is_user_admin($id) === true) {
$avatar = html_print_image(
'images/people_1.png',
true,
@ -1444,7 +1503,6 @@ $session_time .= html_print_input_text(
'class="input_line_small"'
).'</div>';
$user_groups = implode(',', array_keys((users_get_groups($id, 'AR', $display_all_group))));
if (empty($user_groups) === false) {
@ -1573,7 +1631,7 @@ if (!$id) {
$user_id_create = $user_id;
}
if (is_metaconsole()) {
if (is_metaconsole() === true) {
$access_or_pagination = $meta_access;
} else {
$access_or_pagination = $size_pagination;
@ -1589,14 +1647,14 @@ if ($id != '' && !$is_err) {
echo '<div id="user_form">
<div class="user_edit_first_row">
<div class="edit_user_info white_box">'.$div_user_info.'</div>
<div class="edit_user_info white_box">'.$div_user_info.'</div>
<div class="edit_user_autorefresh white_box"><p class="bolder">Extra info</p>'.$email.$phone.$not_login.$local_user.$session_time.'</div>
</div>
</div>
<div class="user_edit_second_row white_box">
<div class="edit_user_options">'.$language.$access_or_pagination.$skin.$home_screen.$default_event_filter.$double_authentication.'</div>
<div class="edit_user_timezone">'.$timezone;
if (!is_metaconsole()) {
if (is_metaconsole() === false) {
echo '<div id="timezone-picker">
<img id="timezone-image" src="'.$local_file.'" width="'.$map_width.'" height="'.$map_height.'" usemap="#timezone-map" />
<img class="timezone-pin" src="include/javascript/timezonepicker/images/pin.png" class="pdd_t_4px" />

View File

@ -14,7 +14,7 @@
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
* Copyright (c) 2005-2022 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -69,9 +69,6 @@ $id2 = get_parameter('id2');
$otherSerialize = get_parameter('other');
$otherMode = get_parameter('other_mode', 'url_encode');
$returnType = get_parameter('return_type', 'string');
$api_password = get_parameter('apipass', '');
$password = get_parameter('pass', '');
$user = get_parameter('user', '');
$info = get_parameter('info', '');
$raw_decode = (bool) get_parameter('raw_decode', false);
@ -84,6 +81,21 @@ $apiPassword = io_output_password(
)
);
$apiTokenValid = false;
// Try getting bearer token from header.
// TODO. Getting token from url will be removed.
$apiToken = (string) getBearerToken();
if (empty($apiToken) === true) {
// Legacy user/pass token.
// TODO. Revome in future.
$api_password = get_parameter('apipass', '');
$user = get_parameter('user', '');
$password = get_parameter('pass', '');
} else {
$apiTokenValid = (bool) api_token_check($apiToken);
}
$correctLogin = false;
$no_login_msg = '';
@ -94,8 +106,8 @@ ob_clean();
// Special call without checks to retrieve version and build of the Pandora FMS
// This info is avalable from the web console without login
// Don't change the format, it is parsed by applications.
if ($info == 'version') {
if (!$config['MR']) {
if ($info === 'version') {
if ((bool) $config['MR'] === false) {
$config['MR'] = 0;
}
@ -105,6 +117,7 @@ if ($info == 'version') {
if (empty($apiPassword) === true
|| (empty($apiPassword) === false && $api_password === $apiPassword)
|| $apiTokenValid === true
) {
if (enterprise_hook('metaconsole_validate_origin', [get_parameter('server_auth')]) === true
|| enterprise_hook('console_validate_origin', [get_parameter('server_auth')]) === true
@ -118,7 +131,14 @@ if (empty($apiPassword) === true
$correctLogin = true;
} else if ((bool) isInACL($ipOrigin) === true) {
// External access.
$user_in_db = process_user_login($user, $password, true);
// Token is valid. Bypass the credentials.
if ($apiTokenValid === true) {
$credentials = db_get_row('tusuario', 'api_token', $apiToken);
$user = $credentials['id_user'];
$password = $credentials['password'];
}
$user_in_db = process_user_login($user, $password, true, $apiTokenValid);
if ($user_in_db !== false) {
$config['id_usuario'] = $user_in_db;
// Compat.
@ -144,19 +164,19 @@ if (empty($apiPassword) === true
$no_login_msg = 'Incorrect given API password';
}
if ($correctLogin) {
if ($correctLogin === true) {
if (($op !== 'get') && ($op !== 'set') && ($op !== 'help')) {
returnError('no_set_no_get_no_help', $returnType);
} else {
$function_name = '';
// Check if is an extension function and get the function name.
if ($op2 == 'extension') {
if ($op2 === 'extension') {
$extension_api_url = $config['homedir'].'/'.EXTENSIONS_DIR.'/'.$ext_name.'/'.$ext_name.'.api.php';
// The extension API file must exist and the extension must be
// enabled.
if (file_exists($extension_api_url)
&& !in_array($ext_name, extensions_get_disabled_extensions())
if (file_exists($extension_api_url) === true
&& in_array($ext_name, extensions_get_disabled_extensions()) === false
) {
include_once $extension_api_url;
$function_name = 'apiextension_'.$op.'_'.$ext_function;
@ -164,7 +184,7 @@ if ($correctLogin) {
} else {
$function_name = 'api_'.$op.'_'.$op2;
if ($op == 'set' && $id) {
if ($op === 'set' && $id) {
switch ($op2) {
case 'update_agent':
case 'add_module_in_conf':
@ -173,7 +193,7 @@ if ($correctLogin) {
$agent = agents_locate_agent($id);
if ($agent !== false) {
$id_os = $agent['id_os'];
if ($id_os == 100) {
if ((int) $id_os === 100) {
returnError(
'not_allowed_operation_cluster',
$returnType

View File

@ -94,7 +94,7 @@ $config['admin_can_make_admin'] = true;
* @return mixed False in case of error or invalid credentials, the username in
* case it's correct.
*/
function process_user_login($login, $pass, $api=false)
function process_user_login($login, $pass, $api=false, $passAlreadyEncrypted=false)
{
global $config;
@ -130,10 +130,10 @@ function process_user_login($login, $pass, $api=false)
if ($config['fallback_local_auth']
|| is_user_admin($login)
|| $local_user === true
|| strtolower($config['auth']) == 'mysql'
|| strtolower($config['auth']) === 'mysql'
|| (bool) $user_not_login === true
) {
return process_user_login_local($login, $pass, $api);
return process_user_login_local($login, $pass, $api, $passAlreadyEncrypted);
} else {
return false;
}
@ -144,12 +144,11 @@ function process_user_login($login, $pass, $api=false)
}
function process_user_login_local($login, $pass, $api=false)
function process_user_login_local($login, $pass, $api=false, $passAlreadyEncrypted=false)
{
global $config, $mysql_cache;
// Connect to Database.
if (!$api) {
if ((bool) $api === false) {
$sql = sprintf(
"SELECT `id_user`, `password`
FROM `tusuario`
@ -169,13 +168,17 @@ function process_user_login_local($login, $pass, $api=false)
$row = db_get_row_sql($sql);
// Perform password check whether it is MD5-hashed (old hashing) or Bcrypt-hashed.
if (strlen($row['password']) === 32) {
// MD5.
$credentials_check = $row !== false && $row['password'] !== md5('') && $row['password'] == md5($pass);
if ($passAlreadyEncrypted) {
$credentials_check = $pass === $row['password'];
} else {
// Bcrypt.
$credentials_check = password_verify($pass, $row['password']);
// Perform password check whether it is MD5-hashed (old hashing) or Bcrypt-hashed.
if (strlen($row['password']) === 32) {
// MD5.
$credentials_check = $row !== false && $row['password'] !== md5('') && $row['password'] == md5($pass);
} else {
// Bcrypt.
$credentials_check = password_verify($pass, $row['password']);
}
}
if ($credentials_check === true) {
@ -184,10 +187,10 @@ function process_user_login_local($login, $pass, $api=false)
// is not case sensitive)
// We get DB nick to put in PHP Session variable,
// to avoid problems with case-sensitive usernames.
// Thanks to David Muñiz for Bug discovery :)
// Thanks to David Muñiz for Bug discovery :).
$filter = ['id_usuario' => $login];
$user_profile = db_get_row_filter('tusuario_perfil', $filter);
if (!users_is_admin($login) && !$user_profile) {
if ((bool) users_is_admin($login) === false && (bool) $user_profile === false) {
$mysql_cache['auth_error'] = 'User does not have any profile';
$config['auth_error'] = 'User does not have any profile';
return false;
@ -200,7 +203,7 @@ function process_user_login_local($login, $pass, $api=false)
return $row['id_user'];
} else {
if (!user_can_login($login)) {
if (user_can_login($login) === false) {
$mysql_cache['auth_error'] = 'User only can use the API.';
$config['auth_error'] = 'User only can use the API.';
} else {

View File

@ -6326,7 +6326,7 @@ function arrayOutputSorting($sort, $sortField)
/**
* Get dowload started cookie from js and set ready cokkie for download ready comntrol.
*
* @return
* @return void
*/
function setDownloadCookieToken()
{
@ -6342,3 +6342,48 @@ function setDownloadCookieToken()
);
}
}
/**
* Get header Authorization
* */
function getAuthorizationHeader()
{
$headers = null;
if (isset($_SERVER['Authorization'])) {
$headers = trim($_SERVER['Authorization']);
} else if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
// Nginx or fast CGI
$headers = trim($_SERVER['HTTP_AUTHORIZATION']);
} else if (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
// Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
// print_r($requestHeaders);
if (isset($requestHeaders['Authorization'])) {
$headers = trim($requestHeaders['Authorization']);
}
}
return $headers;
}
/**
* Get access token from header
*
* @return array/false Token received, false in case thre is no token.
* */
function getBearerToken()
{
$headers = getAuthorizationHeader();
// HEADER: Get the access token from the header
if (!empty($headers)) {
if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
return $matches[1];
}
}
return false;
}

View File

@ -17648,3 +17648,20 @@ function api_set_send_report($thrash1, $thrash2, $other, $returnType)
returnData($returnType, $data, ';');
}
}
/**
* Check if token is correct.
*
* @param string $token Token for check.
*
* @return mixed Id of user. If returns 0 there is not valid token.
*/
function api_token_check(string $token)
{
if (empty($token) === true) {
return 0;
} else {
return db_get_value('id_user', 'tusuario', 'api_token', $token);
}
}

View File

@ -2370,13 +2370,17 @@ function ui_print_help_tip(
$return=false,
$img='images/tip_help.png',
$is_relative=false,
$style=''
$style='',
$blink=false
) {
$output = '<a href="javascript:" class="tip" style="'.$style.'" >';
$output .= html_print_image(
$img,
true,
['title' => $text],
[
'title' => $text,
'class' => $blink === true ? 'blink' : '',
],
false,
$is_relative && is_metaconsole()
).'</a>';

View File

@ -884,6 +884,69 @@ function users_get_users_group_by_group($id_group)
}
/**
* Generates a cryptographically secure chain for use with API.
*
* @return string
*/
function api_token_generate()
{
include_once 'functions_api.php';
// Generate a cryptographically secure chain.
$generateToken = bin2hex(openssl_random_pseudo_bytes(16));
// Check if token exists in DB.
$tokenExists = (bool) api_token_check($generateToken);
// If not exists, can be assigned. In other case, try again.
return ($tokenExists === false) ? $generateToken : api_token_generate();
}
/**
* Returns User API Token
*
* @param string $idUser Id of the user.
*
* @return string
*/
function users_get_API_token(string $idUser)
{
$output = db_get_value('api_token', 'tusuario', 'id_user', $idUser);
if (empty($output) === true) {
$output = '<< '.__('NONE').' >>';
}
return $output;
}
/**
* Renews the API Token.
*
* @param integer $idUser Id of the user.
*
* @return boolean Return true if the token was renewed.
*/
function users_renew_API_token(int $idUser)
{
$apiToken = api_token_generate();
if (empty($apiToken) === false) {
$result = db_process_sql_update(
'tusuario',
['api_token' => $apiToken],
['id_user' => $idUser]
);
if ($result !== false) {
return true;
}
}
return false;
}
/**
* Check if IP is in range. Check wildcard `*`, single IP and IP ranges.
*

View File

@ -2185,6 +2185,38 @@ $.fn.filterByText = function(textbox) {
});
};
/**
* Confirm Dialog for API token renewal request.
*
* @param {string} title Title for show.
* @param {string} message Message for show.
* @param {string} form Form to attach renewAPIToken element.
*/
function renewAPIToken(title, message, form) {
confirmDialog({
title: title,
message: message,
onAccept: function() {
$("#" + form)
.append("<input type='hidden' name='renewAPIToken' value='1'>")
.submit();
}
});
}
/**
* Show Dialog for view the API token.
*
* @param {string} title Title for show.
* @param {string} message Base64 encoded message for show.
*/
function showAPIToken(title, message) {
confirmDialog({
title: title,
message: atob(message),
hideCancelButton: true
});
}
function loadPasswordConfig(id, value) {
$.ajax({
url: "ajax.php",

View File

@ -105,7 +105,6 @@ class ClusterManager
*/
public function run()
{
$operation = get_parameter('op', '');
switch ($operation) {
@ -329,10 +328,8 @@ class ClusterManager
*/
public function showClusterEditor(string $operation)
{
global $config;
if (!check_acl($config['id_user'], 0, 'AW')) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to create clusters'

View File

@ -818,9 +818,9 @@ class Manager implements PublicLogin
$string_groups = io_safe_output($string_groups);
$sql_dashboard = sprintf(
"SELECT COUNT(*)
'SELECT COUNT(*)
FROM tdashboard
WHERE (id_group IN (%s))",
WHERE (id_group IN (%s))',
$string_groups
);
} else {

View File

@ -553,4 +553,6 @@ final class Container extends Model
return $item;
}
}

View File

@ -2724,4 +2724,6 @@ class Item extends CachedModel
return false;
}
}

View File

@ -4678,6 +4678,21 @@ input:checked + .p-slider:before {
animation: fadein 0.5s, fadeout 0.5s 7.5s;
}
.blink {
animation: blink-animation 1s steps(5, start) infinite;
-webkit-animation: blink-animation 1s steps(5, start) infinite;
}
@keyframes blink-animation {
to {
visibility: hidden;
}
}
@-webkit-keyframes blink-animation {
to {
visibility: hidden;
}
}
.snackbar p,
.snackbar h3 {
text-align: left;
@ -9065,6 +9080,14 @@ div#err_msg_centralised {
width: 75%;
}
.renew_api_token_link {
margin: 3px 0.5em 0 0;
float: right;
}
.renew_api_token_image {
width: 16px;
}
@media screen and (max-width: 1369px) {
.div-col {
width: 50%;

View File

@ -37,7 +37,6 @@ $ajaxPage = 'operation/cluster/cluster';
// Control call flow.
try {
// User access and validation is being processed on class constructor.
$obj = new ClusterManager($ajaxPage);
} catch (Exception $e) {

View File

@ -83,9 +83,12 @@ if (isset($_GET['modified']) && !$view_mode) {
$upd_info['id_skin'] = get_parameter('skin', $user_info['id_skin']);
$upd_info['default_event_filter'] = get_parameter('event_filter', null);
$upd_info['block_size'] = get_parameter('block_size', $config['block_size']);
// API Token information.
$apiTokenRenewed = (bool) get_parameter('renewAPIToken');
$upd_info['api_token'] = ($apiTokenRenewed === true) ? api_token_generate() : users_get_API_token($config['id_user']);
$default_block_size = get_parameter('default_block_size', 0);
if ($default_block_size) {
if ($default_block_size > 0) {
$upd_info['block_size'] = 0;
}
@ -161,16 +164,16 @@ if (isset($_GET['modified']) && !$view_mode) {
} else if ($password_new !== 'NON-INIT') {
$error_msg = __('Passwords didn\'t match or other problem encountered while updating passwords');
}
} else if (empty($password_new) && empty($password_confirm)) {
} else if (empty($password_new) === true && empty($password_confirm) === true) {
$return = true;
} else if (empty($password_new) || empty($password_confirm)) {
} else if (empty($password_new) === true || empty($password_confirm) === true) {
$return = false;
}
// No need to display "error" here, because when no update is needed
// (no changes in data) SQL function returns 0 (FALSE), but is not an error,
// just no change. Previous error message could be confussing to the user.
if ($return) {
if ($return !== false) {
if (empty($password_new) === false && empty($password_confirm) === false) {
$success_msg = __('Password successfully updated');
}
@ -184,7 +187,11 @@ if (isset($_GET['modified']) && !$view_mode) {
if ($return_update_user === false) {
$error_msg = __('Error updating user info');
} else if ($return_update_user == true) {
$success_msg = __('User info successfully updated');
if ($apiTokenRenewed === true) {
$success_msg = __('You have generated a new API Token.');
} else {
$success_msg = __('User info successfully updated');
}
} else {
if (empty($password_new) === false && empty($password_confirm) === false) {
$success_msg = __('Password successfully updated');
@ -226,7 +233,7 @@ if (isset($_GET['modified']) && !$view_mode) {
}
// Prints action status for current message.
if ($status != -1) {
if ((int) $status !== -1) {
ui_print_result_message(
$status,
__('User info successfully updated'),
@ -261,6 +268,73 @@ if (is_metaconsole() === false && is_management_allowed() === false) {
$user_id = '<div class="label_select_simple"><p class="edit_user_labels">'.__('User ID').': </p>';
$user_id .= '<span>'.$id.'</span></div>';
$user_id .= '<div class="label_select_simple"><p class="edit_user_labels">'.__('API Token').'</p>';
if (is_management_allowed()) {
$user_id .= html_print_anchor(
[
'onClick' => sprintf(
'javascript:renewAPIToken(\'%s\', \'%s\', \'%s\')',
__('Warning'),
__('The API token will be renewed. After this action, the last token you were using will not work. Are you sure?'),
'user_profile_form',
),
'content' => html_print_image(
'images/icono-refrescar.png',
true,
[
'class' => 'renew_api_token_image clickable',
'title' => __('Renew API Token'),
]
),
'class' => 'renew_api_token_link',
],
true
);
}
// Check php conf for header auth.
$lines = file('/etc/httpd/conf.d/php.conf');
$http_authorization = false;
foreach ($lines as $l) {
if (preg_match('/SetEnvIfNoCase \^Authorization\$ \"\(\.\+\)\" HTTP_AUTHORIZATION=\$1/', $l)) {
$http_authorization = true;
}
}
$user_id .= html_print_anchor(
[
'onClick' => sprintf(
'javascript:showAPIToken(\'%s\', \'%s\')',
__('API Token'),
base64_encode(__('Your API Token is:').'<br><span class="font_12pt bolder">'.users_get_API_token($config['id_user']).'</span><br>'.__('Please, avoid share this string with others.')),
),
'content' => html_print_image(
'images/eye_show.png',
true,
[
'class' => 'renew_api_token_image clickable',
'title' => __('Show API Token'),
]
),
'class' => 'renew_api_token_link',
],
true
);
if ($http_authorization === false) {
$user_id .= ui_print_help_tip(
__('Directive HTTP_AUTHORIZATION=$1 is not set. Please, add it to /etc/httpd/conf.d/php.conf'),
true,
'images/warn.png',
false,
'',
true
);
}
$user_id .= '</div>';
$full_name = ' <div class="label_select_simple">'.html_print_input_text_extended(
'fullname',
$user_info['fullname'],
@ -278,7 +352,7 @@ $full_name = ' <div class="label_select_simple">'.html_print_input_text_extended
).'</div>';
// Show "Picture" (in future versions, why not, allow users to upload it's own avatar here.
if (is_user_admin($id)) {
if (is_user_admin($id) === true) {
$avatar = html_print_image('images/people_1.png', true, ['class' => 'user_avatar']);
} else {
$avatar = html_print_image('images/people_2.png', true, ['class' => 'user_avatar']);
@ -654,10 +728,10 @@ foreach ($timezones as $timezone_name => $tz) {
}
}
if (is_metaconsole()) {
echo '<form name="user_mod" method="post" action="'.ui_get_full_url('index.php?sec=advanced&sec2=advanced/users_setup').'&amp;tab=user_edit&amp;modified=1&amp;pure='.$config['pure'].'">';
if (is_metaconsole() === true) {
echo '<form id="user_profile_form" name="user_mod" method="post" action="'.ui_get_full_url('index.php?sec=advanced&sec2=advanced/users_setup').'&amp;tab=user_edit&amp;modified=1&amp;pure='.$config['pure'].'">';
} else {
echo '<form name="user_mod" method="post" action="'.ui_get_full_url('index.php?sec=workspace&sec2=operation/users/user_edit').'&amp;modified=1&amp;pure='.$config['pure'].'">';
echo '<form id="user_profile_form" name="user_mod" method="post" action="'.ui_get_full_url('index.php?sec=workspace&sec2=operation/users/user_edit').'&amp;modified=1&amp;pure='.$config['pure'].'">';
}
html_print_input_hidden('id', $id, false, false, false, 'id');

View File

@ -1313,6 +1313,7 @@ CREATE TABLE IF NOT EXISTS `tusuario` (
`ehorus_user_level_enabled` TINYINT,
`integria_user_level_user` VARCHAR(60),
`integria_user_level_pass` VARCHAR(45),
`api_token` VARCHAR(255) NOT NULL DEFAULT '',
`allowed_ip_active` TINYINT UNSIGNED DEFAULT 0,
`allowed_ip_list` TEXT,
`auth_token_secret` VARCHAR(45) DEFAULT NULL,

View File

@ -344,8 +344,8 @@ INSERT INTO `tmodule_inventory` (`id_module_inventory`, `id_os`, `name`, `descri
--
-- Dumping data for table `tusuario`
--
INSERT INTO `tusuario` (`id_user`, `fullname`, `firstname`, `lastname`, `middlename`, `password`, `comments`, `last_connect`, `registered`, `email`, `phone`, `is_admin`, `language`, `block_size`, `section`, `data_section`, `metaconsole_access`, `local_user`) VALUES
('admin', 'Pandora', 'Pandora', 'Admin', '', '$2y$10$Wv/xoxjI2VAkthJhk/PzeeGIhBKYU/K.TMgUdmW7fEP2NQkdWlB9K', 'Admin Pandora', 1232642121, 0, 'admin@example.com', '555-555-5555', 1, 'default', 0, 'Default', '', 'advanced', 1);
INSERT INTO `tusuario` (`id_user`, `fullname`, `firstname`, `lastname`, `middlename`, `password`, `comments`, `last_connect`, `registered`, `email`, `phone`, `is_admin`, `language`, `block_size`, `section`, `data_section`, `metaconsole_access`, `local_user`, `api_token`) VALUES
('admin', 'Pandora', 'Pandora', 'Admin', '', '$2y$10$Wv/xoxjI2VAkthJhk/PzeeGIhBKYU/K.TMgUdmW7fEP2NQkdWlB9K', 'Admin Pandora', 1232642121, 0, 'admin@example.com', '555-555-5555', 1, 'default', 0, 'Default', '', 'advanced', 1, 'pandora1234');
--
-- Dumping data for table `tusuario_perfil`

View File

@ -87,7 +87,8 @@ ui_print_page_header(
[
'active' => false,
'text' => $main_page,
],[
],
[
'active' => false,
'text' => $edit,
],