diff --git a/pandora_console/api/v1/config/middleware.php b/pandora_console/api/v1/config/middleware.php index d9c6f78278..a0a1128f6e 100644 --- a/pandora_console/api/v1/config/middleware.php +++ b/pandora_console/api/v1/config/middleware.php @@ -1,6 +1,8 @@ getHeader('Authorization'); - $user = false; - if (empty($authorization) === false && empty($authorization[0]) === false) { - $bearer = explode('Bearer ', $authorization[0]); - if (empty($bearer) === false && isset($bearer[1]) === true) { - $user = \db_get_value( - 'id_user', - 'tusuario', - 'api_token', - $bearer[1] - ); - - if ($user !== false) { - if (session_status() === PHP_SESSION_NONE) { - session_start(); - } - - $_SESSION['id_usuario'] = $user; - $config['id_user'] = $user; - - if (session_status() === PHP_SESSION_ACTIVE) { - session_write_close(); - } - } - } - } - - if (empty($user) === true) { + $ipOrigin = $_SERVER['REMOTE_ADDR']; + $aclListMiddleware = $container->get(AclListMiddleware::class); + if ($aclListMiddleware->check($ipOrigin) === false) { $response = $app->getResponseFactory()->createResponse(); $response->getBody()->write( - json_encode(['error' => 'You need to be authenticated to perform this action']) + json_encode(['error' => __('IP %s is not in ACL list', $ipOrigin)]) + ); + + $errorCode = HttpCodesEnum::UNAUTHORIZED; + $newResponse = $response->withStatus($errorCode); + return $newResponse; + } + + $userTokenMiddleware = $container->get(UserTokenMiddleware::class); + if ($userTokenMiddleware->check($request) === false) { + $response = $app->getResponseFactory()->createResponse(); + $response->getBody()->write( + json_encode(['error' => __('You need to be authenticated to perform this action')]) ); $errorCode = HttpCodesEnum::UNAUTHORIZED; @@ -66,7 +54,7 @@ return function (App $app, ContainerInterface $container) { } catch (\Throwable $th) { $response = $app->getResponseFactory()->createResponse(); $response->getBody()->write( - json_encode(['error' => 'Invalid License']) + json_encode(['error' => __('Invalid License')]) ); $errorCode = HttpCodesEnum::UNAUTHORIZED; diff --git a/pandora_console/api/v1/public/swagger.json b/pandora_console/api/v1/public/swagger.json index 94679c3584..c16a2cd147 100644 --- a/pandora_console/api/v1/public/swagger.json +++ b/pandora_console/api/v1/public/swagger.json @@ -1985,15 +1985,18 @@ "nullable": true }, "validity": { - "description": "validity of the token", + "description": "Date until which tocken is valid, if it is void it will never expire", "type": "string", "default": null, + "example": "2023-02-21 08:34:16", "nullable": true }, "lastUsage": { "description": "last_usage of the token", "type": "string", "default": null, + "readOnly": true, + "example": "2023-02-21 08:34:16", "nullable": true } }, diff --git a/pandora_console/godmode/menu.php b/pandora_console/godmode/menu.php index 3505e7cf2c..3bb3da124b 100644 --- a/pandora_console/godmode/menu.php +++ b/pandora_console/godmode/menu.php @@ -250,6 +250,11 @@ if ($access_console_node === true) { $sub['godmode/users/profile_list']['id'] = 'Profile_management'; } + if ((bool) check_acl($config['id_user'], 0, 'PM') === true) { + $sub['godmode/users/token_list']['text'] = __('Token management'); + $sub['godmode/users/token_list']['id'] = 'token_management'; + } + if (empty($sub) === false) { $menu_godmode['gusuarios']['sub'] = $sub; $menu_godmode['gusuarios']['text'] = __('Profiles'); diff --git a/pandora_console/godmode/users/configure_profile.php b/pandora_console/godmode/users/configure_profile.php index a8ff9cd1e5..532b5f1668 100644 --- a/pandora_console/godmode/users/configure_profile.php +++ b/pandora_console/godmode/users/configure_profile.php @@ -44,57 +44,9 @@ $new_profile = (bool) get_parameter('new_profile'); $id_profile = (int) get_parameter('id'); // Header. if (is_metaconsole() === false) { - $buttons = [ - 'user' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/user.svg', - true, - [ - 'title' => __('User management'), - 'class' => 'invert_filter main_menu_icon', - ] - ).'', - ], - 'profile' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/suitcase@svg.svg', - true, - [ - 'title' => __('Profile management'), - 'class' => 'invert_filter main_menu_icon', - ] - ).'', - ], - ]; - - $buttons[$tab]['active'] = true; - $profile = db_get_row('tperfil', 'id_perfil', $id_profile); - - ui_print_standard_header( - __('Edit profile %s', $profile['name']), - 'images/user.svg', - false, - 'configure_profiles_tab', - true, - $buttons, - [ - [ - 'link' => '', - 'label' => __('Profiles'), - ], - [ - 'link' => '', - 'label' => __('Manage users'), - ], - [ - 'link' => ui_get_full_url('index.php?sec=gusuarios&sec2=godmode/users/profile_list&tab=profile'), - 'label' => __('User Profile management'), - ], - ] - ); + $title = __('Edit profile %s', $profile['name']); + user_print_header($pure, $tab, $title); $sec2 = 'gusuarios'; } else { user_meta_print_header(); diff --git a/pandora_console/godmode/users/configure_token.php b/pandora_console/godmode/users/configure_token.php new file mode 100644 index 0000000000..4972b93660 --- /dev/null +++ b/pandora_console/godmode/users/configure_token.php @@ -0,0 +1,202 @@ +getMessage()) + ); + } +} + +$table = new StdClass(); +$table->width = '100%'; +$table->class = 'databox filters'; +$table->data = []; +$table->rowspan = []; +$table->colspan = []; + +if (is_metaconsole() === true) { + $table->class = 'databox data'; + if (empty($id_token) === true) { + $table->head[0] = __('Update Profile'); + } else { + $table->head[0] = __('Create Profile'); + } + + $table->head_colspan[0] = 4; + $table->headstyle[0] = 'text-align: center'; +} + +$table->data[0][0] = __('Token label'); +$table->data[0][1] = html_print_input_text( + 'label', + $token['label'], + '', + 50, + 255, + true +); + +if ((bool) users_is_admin() === true) { + $table->data[0][2] = __('User'); + $table->data[0][3] = 'aaaa'; +} + +$expiration_date = null; +$expiration_time = null; +if (empty($token['validity']) === false) { + $array_date = explode(' ', io_safe_output($token['validity'])); + if (is_array($array_date) === true) { + $expiration_date = $array_date[0]; + if (isset($array_date[1]) === true + && empty($array_date[1]) === false + ) { + $expiration_time = $array_date[1]; + } + } +} + +$table->data[1][0] = __('Expiration'); +$table->data[1][1] = html_print_input_text( + 'date-expiration', + $expiration_date, + '', + 50, + 255, + true +); + +$table->data[1][2] = __('Expiration Time'); +$table->data[1][3] = html_print_input_text( + 'time-expiration', + $expiration_time, + '', + 50, + 255, + true +); + +echo '
'; + +html_print_table($table); + +$actionButtons = []; + +if (empty($id_token) === true) { + $actionButtons[] = html_print_submit_button( + __('Create'), + 'crt', + false, + ['icon' => 'wand'], + true + ); + html_print_input_hidden('create_token', 1); +} else { + $actionButtons[] = html_print_submit_button( + __('Update'), + 'upd', + false, + ['icon' => 'update'], + true + ); + + html_print_input_hidden('id_token', $id_token); + html_print_input_hidden('update_token', 1); +} + +$actionButtons[] = html_print_go_back_button( + ui_get_full_url($url_list), + ['button_class' => ''], + true +); + +html_print_action_buttons( + implode('', $actionButtons), + ['type' => 'form_action'] +); + +echo '
'; + +ui_include_time_picker(); +ui_require_jquery_file('ui.datepicker-'.get_user_language(), 'include/javascript/i18n/'); + +?> + + diff --git a/pandora_console/godmode/users/configure_user.php b/pandora_console/godmode/users/configure_user.php index 668216d330..6b03d75737 100644 --- a/pandora_console/godmode/users/configure_user.php +++ b/pandora_console/godmode/users/configure_user.php @@ -246,60 +246,9 @@ if (is_metaconsole() === true) { user_meta_print_header(); $sec = 'advanced'; } else { - if ((bool) check_acl($config['id_user'], 0, 'UM') === false) { - $buttons = []; - } else { - $buttons = [ - 'user' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/user.svg', - true, - [ - 'title' => __('User management'), - 'class' => 'invert_filter main_menu_icon', - ] - ).'', - ], - 'profile' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/suitcase@svg.svg', - true, - [ - 'title' => __('Profile management'), - 'class' => 'invert_filter main_menu_icon', - ] - ).'', - ], - ]; - $buttons[$tab]['active'] = true; - } - $edit_user = get_parameter('edit_user'); - - ui_print_standard_header( - ($edit_user) ? sprintf('%s [ %s ]', __('Update User'), $id) : __('Create User'), - 'images/gm_users.png', - false, - '', - true, - $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'), - ], - ] - ); + $title = ($edit_user) ? sprintf('%s [ %s ]', __('Update User'), $id) : __('Create User'); + user_print_header($pure, $tab, $title); $sec = 'gusuarios'; } diff --git a/pandora_console/godmode/users/profile_list.php b/pandora_console/godmode/users/profile_list.php index 65a3e43796..cc059780d8 100644 --- a/pandora_console/godmode/users/profile_list.php +++ b/pandora_console/godmode/users/profile_list.php @@ -51,52 +51,7 @@ $pure = get_parameter('pure', 0); // Header. if (is_metaconsole() === false) { - $buttons = [ - 'user' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/user.svg', - true, - [ - 'title' => __('User management'), - 'class' => 'invert_filter main_menu_user', - ] - ).'', - ], - 'profile' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/suitcase@svg.svg', - true, - [ - 'title' => __('Profile management'), - 'class' => 'invert_filter main_menu_user', - ] - ).'', - ], - ]; - - $buttons[$tab]['active'] = true; - - // Header. - ui_print_standard_header( - __('User Profile management'), - 'images/user.svg', - false, - 'profile_tab', - false, - $buttons, - [ - [ - 'link' => '', - 'label' => __('Profiles'), - ], - [ - 'link' => '', - 'label' => __('Manage users'), - ], - ] - ); + user_print_header($pure, $tab); $sec = 'gusuarios'; } else { user_meta_print_header(); diff --git a/pandora_console/godmode/users/token_list.php b/pandora_console/godmode/users/token_list.php new file mode 100644 index 0000000000..5a4a116a55 --- /dev/null +++ b/pandora_console/godmode/users/token_list.php @@ -0,0 +1,193 @@ +getMessage()) + ); + } +} + +$tokenMsg = ''; +if ($create_token === true || $update_token === true) { + $label = get_parameter('label', null); + + $expirationDate = get_parameter('date-expiration', null); + $expirationTime = get_parameter('time-expiration', null); + $validity = null; + if (empty($expirationDate) === false) { + $validity = $expirationDate; + if (empty($expirationTime) === false) { + $validity .= ' '.$expirationTime; + } + } + + $values = [ + 'label' => $label, + 'validity' => $validity, + ]; + + // Create token. + if ($create_token === true) { + try { + $token = create_user_token($values); + $smgInfo = __('This code will appear only once, please keep it in a safe place'); + $smgInfo .= '.
'; + $smgInfo .= __('If you lose the code, you will only able to delete it and create a new one'); + $smgInfo .= '.

'; + $smgInfo .= ''; + $smgInfo .= $token['token']; + $smgInfo .= ''; + $tokenMsg = ui_print_info_message($smgInfo, '', true); + ui_print_success_message(__('Successfully created')); + } catch (\Exception $e) { + ui_print_error_message( + __('There was a problem creating this token, %s', $e->getMessage()) + ); + } + } + + // Update token. + if ($update_token === true) { + try { + $token = update_user_token($id_token, $values); + ui_print_success_message(__('Successfully updated')); + } catch (\Exception $e) { + ui_print_error_message( + __('There was a problem updating this token, %s', $e->getMessage()) + ); + } + } +} + +try { + $columns = [ + 'label', + 'validity', + 'lastUsage', + 'options', + ]; + + $column_names = [ + __('Label'), + __('Expiration'), + __('Last usage'), + [ + 'text' => __('Options'), + 'class' => 'w20px table_action_buttons', + ], + ]; + + $tableId = 'token_table'; + // Load datatables user interface. + ui_print_datatable( + [ + 'id' => $tableId, + 'class' => 'info_table', + 'style' => 'width: 100%', + 'columns' => $columns, + 'column_names' => $column_names, + 'ajax_url' => 'include/ajax/token', + 'ajax_data' => ['list_user_tokens' => 1], + 'extra_html' => $tokenMsg, + 'no_sortable_columns' => [ -1 ], + 'order' => [ + 'field' => 'label', + 'direction' => 'asc', + ], + 'search_button_class' => 'sub filter float-right', + 'form' => [ + 'inputs' => [ + [ + 'label' => __('Free search'), + 'type' => 'text', + 'class' => 'w25p', + 'id' => 'freeSearch', + 'name' => 'freeSearch', + ], + ], + ], + 'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar', + 'dom_elements' => 'lftpB', + ] + ); +} catch (Exception $e) { + echo $e->getMessage(); +} + +echo '
'; +html_print_action_buttons( + html_print_submit_button( + __('Create Token'), + 'crt', + false, + ['icon' => 'next'], + true + ), + [ + 'type' => 'data_table', + 'class' => 'fixed_action_buttons', + ] +); +echo '
'; diff --git a/pandora_console/godmode/users/user_list.php b/pandora_console/godmode/users/user_list.php index 017de9869b..e4c1617755 100644 --- a/pandora_console/godmode/users/user_list.php +++ b/pandora_console/godmode/users/user_list.php @@ -240,73 +240,10 @@ if (is_metaconsole() === true) { user_meta_print_header(); $sec = 'advanced'; } else { - if (check_acl($config['id_user'], 0, 'PM')) { - $buttons = [ - 'user' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/user.svg', - true, - [ - 'title' => __('User management'), - 'class' => 'invert_filter main_menu_icon', - ] - ).'', - ], - 'profile' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/suitcase@svg.svg', - true, - [ - 'title' => __('Profile management'), - 'class' => 'invert_filter main_menu_icon', - ] - ).'', - ], - ]; - } else { - $buttons = [ - 'user' => [ - 'active' => false, - 'text' => ''.html_print_image( - 'images/user.svg', - true, - [ - 'title' => __('User management'), - 'class' => 'invert_filter main_menu_icon', - ] - ).'', - ], - ]; - } - - $buttons[$tab]['active'] = true; - - // Header. - ui_print_standard_header( - __('Users management'), - 'images/user.svg', - false, - '', - false, - $buttons, - [ - [ - 'link' => '', - 'label' => __('Profiles'), - ], - [ - 'link' => '', - 'label' => __('Manage users'), - ], - ] - ); - + user_print_header($pure, $tab); $sec = 'gusuarios'; } - $disable_user = get_parameter('disable_user', false); $delete_user = (bool) get_parameter('user_del', false); diff --git a/pandora_console/include/ajax/token.php b/pandora_console/include/ajax/token.php new file mode 100644 index 0000000000..37914cb417 --- /dev/null +++ b/pandora_console/include/ajax/token.php @@ -0,0 +1,164 @@ +toArray(); + + $sec = 'gusuarios'; + if (is_metaconsole() === true) { + $sec = 'advanced'; + } + + $edit_url = 'index.php?sec='.$sec; + $edit_url .= '&sec2=godmode/users/configure_token&pure=0'; + $edit_url .= '&id_token='.$itemArray['idToken']; + + $delete_url = 'index.php?sec='.$sec; + $delete_url .= '&sec2=godmode/users/token_list'; + $delete_url .= '&pure=0&delete_token=1'; + $delete_url .= '&id_token='.$itemArray['idToken']; + + $itemArray['label'] = html_print_anchor( + [ + 'href' => $edit_url, + 'content' => $itemArray['label'], + ], + true + ); + + if (empty($itemArray['validity']) === true) { + $itemArray['validity'] = __('Never'); + } else { + $itemArray['validity'] = date($config['date_format'], strtotime($itemArray['validity'])); + } + + if (empty($itemArray['lastUsage']) === true) { + $itemArray['lastUsage'] = __('Never'); + } else { + $itemArray['lastUsage'] = human_time_comparation($itemArray['lastUsage']); + } + + $itemArray['options'] = '
'; + $itemArray['options'] .= html_print_anchor( + [ + 'href' => $edit_url, + 'content' => html_print_image( + 'images/edit.svg', + true, + [ + 'title' => __('Show'), + 'class' => 'main_menu_icon invert_filter', + ] + ), + ], + true + ); + $itemArray['options'] .= html_print_anchor( + [ + 'href' => $delete_url, + 'onClick' => 'if (!confirm(\' '.__('Are you sure?').'\')) return false;', + 'content' => html_print_image( + 'images/delete.svg', + true, + [ + 'title' => __('Delete'), + 'class' => 'invert_filter main_menu_icon', + ] + ), + ], + true + ); + $itemArray['options'] .= '
'; + + return $itemArray; + }, + $return['data'] + ); + } + + // Datatables format: RecordsTotal && recordsfiltered. + echo json_encode( + [ + 'data' => $return['data'], + 'recordsTotal' => $return['paginationData']['totalRegisters'], + 'recordsFiltered' => $return['paginationData']['totalRegisters'], + ] + ); + // Capture output. + $response = ob_get_clean(); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + return; + } + + // If not valid, show error with issue. + json_decode($response); + if (json_last_error() == JSON_ERROR_NONE) { + // If valid dump. + echo $response; + } else { + echo json_encode( + ['error' => $response] + ); + } + + return; +} diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index a721e82c12..e50eb96106 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -17,7 +17,9 @@ * @subpackage Config */ -/** +use DI\ContainerBuilder; + +/* * Pandora build version and version */ $build_version = 'PC240126'; @@ -336,3 +338,15 @@ if (isset($config['console_log_enabled']) === true ini_set('log_errors', false); ini_set('error_log', ''); } + +global $container; +if (empty($container) === true) { + include_once $config['homedir'].'/vendor/autoload.php'; + + // Solution to load the ContainerBuilder class. + $containerBuilder = new ContainerBuilder(); + $containerBuilder->addDefinitions(__DIR__.'/../api/v1/config/container.php'); + + // Create DI container instance. + $container = $containerBuilder->build(); +} diff --git a/pandora_console/include/functions_token.php b/pandora_console/include/functions_token.php new file mode 100644 index 0000000000..aabdd925bc --- /dev/null +++ b/pandora_console/include/functions_token.php @@ -0,0 +1,161 @@ +get(GetTokenAction::class)->__invoke($idToken)->toArray(); + + return $token; +} + + +/** + * Get info tokens for user. + * + * @param integer $page Page. + * @param integer $pageSize Size page. + * @param string|null $sortField Sort field. + * @param string|null $sortDirection Sort direction. + * @param array $filters Filters. + * + * @return array + */ +function list_user_tokens( + int $page=0, + int $pageSize=0, + ?string $sortField=null, + ?string $sortDirection=null, + array $filters=[] +): array { + global $config; + global $container; + + $tokenFilter = new TokenFilter; + $tokenFilter->setPage($page); + $tokenFilter->setSizePage($pageSize); + $tokenFilter->setSortField($sortField); + $tokenFilter->setSortDirection($sortDirection); + + if (empty($filters['freeSearch']) === false) { + $tokenFilter->setFreeSearch($filters['freeSearch']); + } + + // phpcs:ignore + /** @var Token $entityFilter */ + $entityFilter = $tokenFilter->getEntityFilter(); + + if (empty($filters['idUser']) === true) { + $entityFilter->setIdUser($config['id_user']); + } else { + $entityFilter->setIdUser($filters['idUser']); + } + + $result = $container->get(ListTokenAction::class)->__invoke($tokenFilter); + + return $result; +} + + +/** + * Create token. + * + * @param array $params Params. + * + * @return array + */ +function create_user_token(array $params): array +{ + global $config; + global $container; + + $token = new Token; + $token->setIdUser($config['id_user']); + $token->setLabel(io_safe_output($params['label'])); + $token->setValidity((empty($params['validity']) === false) ? io_safe_output($params['validity']) : null); + $result = $container->get(CreateTokenAction::class)->__invoke($token)->toArray(); + + return $result; +} + + +/** + * Update token. + * + * @param integer $idToken Token ID. + * @param array $params Params. + * + * @return array + */ +function update_user_token(int $idToken, array $params): array +{ + global $config; + global $container; + + $token = $container->get(GetTokenAction::class)->__invoke($idToken); + $oldToken = clone $token; + + $token->setIdUser($config['id_user']); + $token->setLabel(io_safe_output($params['label'])); + $token->setValidity((empty($params['validity']) === false) ? io_safe_output($params['validity']) : null); + + $result = $container->get(UpdateTokenAction::class)->__invoke($token, $oldToken)->toArray(); + + return $result; +} + + +/** + * Delete token. + * + * @param integer $idToken Token ID. + * + * @return boolean + */ +function delete_user_token(int $idToken): bool +{ + global $container; + + $token = $container->get(GetTokenAction::class)->__invoke($idToken); + $container->get(DeleteTokenAction::class)->__invoke($token); + $result = true; + + return $result; +} diff --git a/pandora_console/include/functions_users.php b/pandora_console/include/functions_users.php index 00dfddef26..afaddbd638 100755 --- a/pandora_console/include/functions_users.php +++ b/pandora_console/include/functions_users.php @@ -1016,3 +1016,111 @@ function checkIPInRange( return $output; } + + +/** + * Build header user options to manage. + * + * @param integer $pure Pure. + * @param string $tab Tab. + * @param string $title Title. + * + * @return void + */ +function user_print_header(int $pure=0, string $tab='user', ?string $title=null): void +{ + global $config; + + $url_list_user = 'index.php?sec=gusuarios&sec2=godmode/users/user_list'; + $url_list_user .= '&tab=user&pure='.$pure; + + $url_list_profile = 'index.php?sec=gusuarios&sec2=godmode/users/profile_list'; + $url_list_profile .= '&tab=profile&pure='.$pure; + + $url_list_token = 'index.php?sec=gusuarios&sec2=godmode/users/token_list'; + $url_list_token .= '&tab=token&pure='.$pure; + + $buttons['user'] = [ + 'active' => false, + 'text' => ''.html_print_image( + 'images/user.svg', + true, + [ + 'title' => __('User management'), + 'class' => 'invert_filter main_menu_icon', + ] + ).'', + ]; + + if ((bool) check_acl($config['id_user'], 0, 'PM') === true) { + $buttons['profile'] = [ + 'active' => false, + 'text' => ''.html_print_image( + 'images/suitcase@svg.svg', + true, + [ + 'title' => __('Profile management'), + 'class' => 'invert_filter main_menu_user', + ] + ).'', + ]; + } + + $buttons['token'] = [ + 'active' => false, + 'text' => ''.html_print_image( + 'images/incremental-data@svg.svg', + true, + [ + 'title' => __('Token management'), + 'class' => 'invert_filter main_menu_user', + ] + ).'', + ]; + + $buttons[$tab]['active'] = true; + + switch ($tab) { + case 'token': + $title = (empty($title) === false) ? $title : __('Token management'); + $img = 'images/incremental-data@svg.svg'; + $tab_name = 'token_tab'; + $short_title = __('Token'); + break; + + case 'profile': + $title = (empty($title) === false) ? $title : __('Profile management'); + $img = 'images/suitcase@svg.svg'; + $tab_name = 'profile_tab'; + $short_title = __('Profile'); + break; + + case 'user': + default: + $title = (empty($title) === false) ? $title : __('User management'); + $img = 'images/user.svg'; + $tab_name = 'user_tab'; + $short_title = __('User'); + break; + } + + // Header. + ui_print_standard_header( + $title, + $img, + false, + $tab_name, + false, + $buttons, + [ + [ + 'link' => '', + 'label' => $short_title, + ], + [ + 'link' => $url_list_user, + 'label' => __('Manage users'), + ], + ] + ); +} diff --git a/pandora_console/include/lib/Modules/Authentication/Entities/Token.php b/pandora_console/include/lib/Modules/Authentication/Entities/Token.php index 30b3940c40..7cfca39697 100644 --- a/pandora_console/include/lib/Modules/Authentication/Entities/Token.php +++ b/pandora_console/include/lib/Modules/Authentication/Entities/Token.php @@ -44,14 +44,17 @@ use PandoraFMS\Modules\Shared\Validators\Validator; * type="string", * nullable=true, * default=null, - * description="validity of the token" + * description="Date until which tocken is valid, if it is void it will never expire", + * example="2023-02-21 08:34:16", * ), * @OA\Property( * property="lastUsage", * type="string", * nullable=true, * default=null, - * description="last_usage of the token" + * description="last_usage of the token", + * example="2023-02-21 08:34:16", + * readOnly=true * ) * ) * @@ -101,7 +104,7 @@ final class Token extends Entity private ?string $validity = null; private ?string $lastUsage = null; - private ?string $token =null; + private ?string $token = null; public function __construct() { @@ -115,6 +118,7 @@ final class Token extends Entity 'challenge' => 1, 'idUser' => 1, 'token' => 1, + 'lastUsage' => 1, ]; } @@ -127,7 +131,7 @@ final class Token extends Entity 'idUser' => $this->getIdUser(), 'validity' => $this->getValidity(), 'lastUsage' => $this->getLastUsage(), - 'token' => $this->getToken() + 'token' => $this->getToken(), ]; } @@ -142,7 +146,7 @@ final class Token extends Entity 'uuid' => Validator::STRING, 'challenge' => Validator::STRING, 'idUser' => Validator::STRING, - 'validity' => Validator::STRING, + 'validity' => Validator::DATETIME, 'lastUsage' => Validator::DATETIME, ]; } @@ -315,7 +319,7 @@ final class Token extends Entity } /** - * Get the value of token + * Get the value of token. * * @return ?string */ @@ -325,11 +329,10 @@ final class Token extends Entity } /** - * Set the value of token + * Set the value of token. * * @param ?string $token * - * @return self */ public function setToken(?string $token): self { diff --git a/pandora_console/include/lib/Modules/Authentication/Entities/TokenFilter.php b/pandora_console/include/lib/Modules/Authentication/Entities/TokenFilter.php index 1674a0958d..42191cc140 100644 --- a/pandora_console/include/lib/Modules/Authentication/Entities/TokenFilter.php +++ b/pandora_console/include/lib/Modules/Authentication/Entities/TokenFilter.php @@ -16,6 +16,13 @@ use PandoraFMS\Modules\Shared\Validators\Validator; * property="idToken", * default=null, * readOnly=false + * ), + * @OA\Property( + * property="freeSearch", + * type="string", + * nullable=true, + * default=null, + * description="Find word in name field." * ) * ) * } @@ -32,6 +39,8 @@ use PandoraFMS\Modules\Shared\Validators\Validator; */ final class TokenFilter extends FilterAbstract { + private ?string $freeSearch = null; + public function __construct() { $this->setDefaultFieldOrder(TokenDataMapper::LABEL); @@ -39,28 +48,28 @@ final class TokenFilter extends FilterAbstract $this->setEntityFilter(new Token()); } - public function fieldsTranslate(): array { return [ - 'idToken' => TokenDataMapper::ID_TOKEN, - 'label' => TokenDataMapper::LABEL, + 'idToken' => TokenDataMapper::ID_TOKEN, + 'label' => TokenDataMapper::LABEL, + 'validity' => TokenDataMapper::VALIDITY, + 'lastUsage' => TokenDataMapper::LAST_USAGE, ]; } - public function fieldsReadOnly(): array { return []; } - public function jsonSerialize(): mixed { - return []; + return [ + 'freeSearch' => $this->getFreeSearch(), + ]; } - public function getValidations(): array { $validations = []; @@ -71,11 +80,24 @@ final class TokenFilter extends FilterAbstract return $validations; } - public function validateFields(array $filters): array { return (new Validator())->validate($filters); } + public function getFreeSearch(): ?string + { + return $this->freeSearch; + } + public function setFreeSearch(?string $freeSearch): self + { + $this->freeSearch = $freeSearch; + return $this; + } + + public function getFieldsFreeSearch(): ?array + { + return [TokenDataMapper::TABLE_NAME.'.'.TokenDataMapper::LABEL]; + } } diff --git a/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepository.php b/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepository.php index fdcc53d6b7..dfdd7c621a 100644 --- a/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepository.php +++ b/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepository.php @@ -61,5 +61,4 @@ class TokenRepository { $this->repository->__delete($id, $this->tokenDataMapper); } - } diff --git a/pandora_console/include/lib/Modules/Authentication/Services/CreateTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/CreateTokenService.php index aa06a5306c..f97aa2496f 100644 --- a/pandora_console/include/lib/Modules/Authentication/Services/CreateTokenService.php +++ b/pandora_console/include/lib/Modules/Authentication/Services/CreateTokenService.php @@ -33,8 +33,9 @@ final class CreateTokenService $token = $this->tokenRepository->create($token); $this->audit->write( - 'Token Management', - ' Create token #'.$token->getIdToken() + AUDIT_LOG_USER_MANAGEMENT, + 'Create token '.$token->getLabel(), + json_encode($token->toArray()) ); return $token; diff --git a/pandora_console/include/lib/Modules/Authentication/Services/DeleteTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/DeleteTokenService.php index 80b6cb1200..78b6263527 100644 --- a/pandora_console/include/lib/Modules/Authentication/Services/DeleteTokenService.php +++ b/pandora_console/include/lib/Modules/Authentication/Services/DeleteTokenService.php @@ -22,8 +22,9 @@ final class DeleteTokenService $this->tokenRepository->delete($idToken); $this->audit->write( - 'Token Management', - ' Deleted token #'.$idToken + AUDIT_LOG_USER_MANAGEMENT, + 'Delete token '.$token->getLabel(), + json_encode($token->toArray()) ); } } diff --git a/pandora_console/include/lib/Modules/Authentication/Services/GetUserTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/GetUserTokenService.php index 57b08c531a..1169f99dff 100644 --- a/pandora_console/include/lib/Modules/Authentication/Services/GetUserTokenService.php +++ b/pandora_console/include/lib/Modules/Authentication/Services/GetUserTokenService.php @@ -20,8 +20,6 @@ final class GetUserTokenService $entityFilter = $tokenFilter->getEntityFilter(); $entityFilter->setUuid($uuid); - // TODO: Validity. - return $this->tokenRepository->getOne($tokenFilter); } } diff --git a/pandora_console/include/lib/Modules/Authentication/Services/UpdateTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/UpdateTokenService.php index b954075ef1..0ea456b5f9 100644 --- a/pandora_console/include/lib/Modules/Authentication/Services/UpdateTokenService.php +++ b/pandora_console/include/lib/Modules/Authentication/Services/UpdateTokenService.php @@ -23,8 +23,9 @@ final class UpdateTokenService $token = $this->tokenRepository->update($token); $this->audit->write( - 'Token Management', - ' Update token #'.$token->getIdToken() + AUDIT_LOG_USER_MANAGEMENT, + 'Update token '.$token->getLabel(), + json_encode($token->toArray()) ); return $token; diff --git a/pandora_console/include/lib/Modules/Authentication/Services/ValidateServerIdentifierTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/ValidateServerIdentifierTokenService.php new file mode 100644 index 0000000000..f7e827bfbd --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/ValidateServerIdentifierTokenService.php @@ -0,0 +1,21 @@ +config->get('server_unique_identifier'); + $apiPassword = $this->config->get('api_password'); + + $tokenUniqueServerIdentifier = md5($serverUniqueIdentifier).md5($apiPassword); + return ($tokenUniqueServerIdentifier === $token); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/ValidateUserTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/ValidateUserTokenService.php index ee66c56954..992079b52b 100644 --- a/pandora_console/include/lib/Modules/Authentication/Services/ValidateUserTokenService.php +++ b/pandora_console/include/lib/Modules/Authentication/Services/ValidateUserTokenService.php @@ -11,12 +11,20 @@ final class ValidateUserTokenService public function __invoke( string $uuid, - string $token, + string $strToken, ): bool { + $token = $this->getUserTokenService->__invoke($uuid); + $validity = $token?->getValidity(); + $challenge = $token?->getChallenge(); + + if (empty($validity) === false) { + if (strtotime($validity) < time()) { + return false; + } + } - $challenge = $this->getUserTokenService->__invoke($uuid)?->getChallenge(); return password_verify( - $token, + $strToken, $challenge ); } diff --git a/pandora_console/include/lib/Modules/Shared/Core/FilterAbstract.php b/pandora_console/include/lib/Modules/Shared/Core/FilterAbstract.php index de8170e835..3f593bcd9d 100644 --- a/pandora_console/include/lib/Modules/Shared/Core/FilterAbstract.php +++ b/pandora_console/include/lib/Modules/Shared/Core/FilterAbstract.php @@ -15,8 +15,8 @@ abstract class FilterAbstract extends SerializableAbstract use OrderFilterTrait; use GroupByFilterTrait; - public const ASC = 'ascending'; - public const DESC = 'descending'; + public const ASC = 'ASC'; + public const DESC = 'DESC'; private ?int $limit = null; private ?int $offset = null; diff --git a/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php b/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php index 47ef62594a..98b63e8803 100644 --- a/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php +++ b/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php @@ -105,8 +105,8 @@ use OpenApi\Annotations as OA; * @OA\Schema( * type="string", * enum={ - * "ascending", - * "descending" + * "ASC", + * "DESC" * }, * default="" * ), diff --git a/pandora_console/include/lib/Modules/Shared/Middlewares/AclListMiddleware.php b/pandora_console/include/lib/Modules/Shared/Middlewares/AclListMiddleware.php new file mode 100644 index 0000000000..3e110ae89f --- /dev/null +++ b/pandora_console/include/lib/Modules/Shared/Middlewares/AclListMiddleware.php @@ -0,0 +1,29 @@ +config->get('homedir').'/include/functions_api.php'; + if ((bool) \isInACL($ipOrigin) === false) { + $result = false; + } + } catch (NotFoundException) { + $result = false; + } + + return $result; + } +} diff --git a/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php b/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php index db8fcbd096..383bfdcbdb 100644 --- a/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php +++ b/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php @@ -2,31 +2,41 @@ namespace PandoraFMS\Modules\Shared\Middlewares; +use PandoraFMS\Core\Config; use PandoraFMS\Modules\Authentication\Services\GetUserTokenService; use PandoraFMS\Modules\Authentication\Services\UpdateTokenService; +use PandoraFMS\Modules\Authentication\Services\ValidateServerIdentifierTokenService; use PandoraFMS\Modules\Authentication\Services\ValidateUserTokenService; use PandoraFMS\Modules\Shared\Exceptions\NotFoundException; use PandoraFMS\Modules\Shared\Services\Timestamp; use Psr\Http\Message\ServerRequestInterface as Request; -class UserTokenMiddleware +final class UserTokenMiddleware { public function __construct( + private readonly ValidateServerIdentifierTokenService $validateServerIdentifierTokenService, private readonly ValidateUserTokenService $validateUserTokenService, private readonly GetUserTokenService $getUserTokenService, private readonly UpdateTokenService $updateTokenService, - private readonly Timestamp $timestamp + private readonly Timestamp $timestamp, + private readonly Config $config ) { } public function check(Request $request): bool { - global $config; - $authorization = ($request->getHeader('Authorization')[0] ?? ''); + hd('El server UUID:', true); + hd($this->config->get('server_unique_identifier'), true); - /* - @var ?Token $token - */ + hd('El api pass es:', true); + hd($this->config->get('api_password'), true); + + hd('El token de md5 con el que se puede loguear: ', true); + hd(md5($this->config->get('server_unique_identifier')).'-'.md5($this->config->get('api_password')), true); + + $authorization = ($request->getHeader('Authorization')[0] ?? ''); + + $token = null; try { $authorization = str_replace('Bearer ', '', $authorization); preg_match( @@ -36,13 +46,19 @@ class UserTokenMiddleware ); $uuid = ($matches[0] ?? ''); - $token = str_replace($uuid.'-', '', $authorization); - $validToken = $this->validateUserTokenService->__invoke($uuid, $token); - $token = $this->getUserTokenService->__invoke($uuid); - if ($token !== null && $validToken) { - $oldToken = clone $token; - $token->setLastUsage($this->timestamp->getMysqlCurrentTimestamp(0)); - $this->updateTokenService->__invoke($token, $oldToken); + $strToken = str_replace($uuid.'-', '', $authorization); + $validTokenUiniqueServerIdentifier = $this->validateServerIdentifierTokenService->__invoke($strToken); + if ($validTokenUiniqueServerIdentifier === false) { + $validToken = $this->validateUserTokenService->__invoke($uuid, $strToken); + $token = $this->getUserTokenService->__invoke($uuid); + if ($token !== null && $validToken) { + $oldToken = clone $token; + $token->setLastUsage($this->timestamp->getMysqlCurrentTimestamp(0)); + $this->updateTokenService->__invoke($token, $oldToken); + } + } else { + $validToken = true; + $token = false; } } catch (NotFoundException) { $token = null; @@ -53,8 +69,13 @@ class UserTokenMiddleware session_start(); } - $_SESSION['id_usuario'] = $token->getIdUser(); - $config['id_user'] = $token->getIdUser(); + if ($validTokenUiniqueServerIdentifier === true) { + $_SESSION['id_usuario'] = 'admin'; + $this->config->set('id_user', 'admin'); + } else { + $_SESSION['id_usuario'] = $token->getIdUser(); + $this->config->set('id_user', $token->getIdUser()); + } if (session_status() === PHP_SESSION_ACTIVE) { session_write_close(); diff --git a/pandora_console/include/lib/Modules/Shared/Repositories/RepositoryMySQL.php b/pandora_console/include/lib/Modules/Shared/Repositories/RepositoryMySQL.php index ba691d19b7..7b6be03a25 100644 --- a/pandora_console/include/lib/Modules/Shared/Repositories/RepositoryMySQL.php +++ b/pandora_console/include/lib/Modules/Shared/Repositories/RepositoryMySQL.php @@ -316,8 +316,8 @@ class RepositoryMySQL extends Repository private function checkDirectionOrderByMsql(?string $direction): string { $directionArray = [ - 'descending' => 'DESC', - 'ascending' => 'ASC', + 'DESC' => 'DESC', + 'ASC' => 'ASC', ]; return (isset($directionArray[$direction]) === true) ? $directionArray[$direction] : 'ASC'; diff --git a/pandora_console/operation/search_results.php b/pandora_console/operation/search_results.php index 3903ddca19..d2f6f751b7 100644 --- a/pandora_console/operation/search_results.php +++ b/pandora_console/operation/search_results.php @@ -206,7 +206,7 @@ ui_print_standard_header( ); $only_count = false; -hd(io_safe_input($_SESSION['stringSearchSQL']), true); + switch ($searchTab) { case 'main': $only_count = true;