diff --git a/pandora_console/general/login_page.php b/pandora_console/general/login_page.php index bbc499661f..a5d8d8bb90 100755 --- a/pandora_console/general/login_page.php +++ b/pandora_console/general/login_page.php @@ -712,6 +712,29 @@ if ($login_screen === 'disabled_access_node') { echo ''; } +if (empty($process_error_message) === true + && isset($config['pending_sync_process_message']) === true + && $login_screen === 'login' +) { + echo '
'; + echo '
'; + echo '
'; + echo html_print_image('images/icono_logo_pandora.png', true, ['alt' => __('Pending synchronization process'), 'border' => 0]); + echo '
'; + echo '
'; + echo '
'; + echo '

'.__('Access granted').'

'; + echo '

'.$config['pending_sync_process_message'].'

'; + echo '
'; + echo '
'; + echo '
'; + html_print_submit_button('Ok', 'hide-sync-process', false, ['class' => 'mini float-right']); + echo '
'; + echo '
'; + echo '
'; + echo '
'; +} + switch ($login_screen) { case 'error_dbconfig': case 'error_authconfig': @@ -966,6 +989,24 @@ html_print_div(['id' => 'forced_title_layer', 'class' => 'forced_title_layer', ' $("#login_failed" ).dialog('close'); $("#login_correct_pass").dialog('close'); }); + + if ($('#pending_sync_process').length > 0) { + $('#pending_sync_process').dialog({ + resizable: true, + draggable: true, + modal: true, + height: 230, + width: 530, + overlay: { + opacity: 0.5, + background: "black" + } + }); + } + + $('#button-hide-sync-process').click(function() { + $('#pending_sync_process').dialog('close') + }) }); $('#nick').focus(); break; diff --git a/pandora_console/include/auth/mysql.php b/pandora_console/include/auth/mysql.php index 8068d664cc..37164a111c 100644 --- a/pandora_console/include/auth/mysql.php +++ b/pandora_console/include/auth/mysql.php @@ -72,6 +72,7 @@ if (isset($config) === false) { } require_once $config['homedir'].'/include/functions_profile.php'; +require_once $config['homedir'].'/include/functions_token.php'; enterprise_include('include/auth/mysql.php'); $config['user_can_update_info'] = true; @@ -220,14 +221,31 @@ function process_user_login_remote($login, $pass, $api=false) { global $config, $mysql_cache; + $create_by_remote_api = false; + if (is_metaconsole() === false && is_management_allowed() === false) { + $create_by_remote_api = true; + } + // Remote authentication. switch ($config['auth']) { // LDAP. case 'ldap': - $sr = ldap_process_user_login($login, $pass); - // Try with secondary server if not login. - if ($sr === false && (bool) $config['secondary_ldap_enabled'] === true) { - $sr = ldap_process_user_login($login, $pass, true); + if ($create_by_remote_api === true) { + $sr = ldap_process_user_login_by_api($login, $pass); + if ($sr !== false && isset($sr['uid']) === true && is_array($sr['uid']) === true) { + $already_user = db_get_value('id_user', 'tusuario', 'id_user', $sr['uid'][0]); + // If the node is centralized, LDAP login is delegated to the metaconsole via the API. + // Since the user is not yet on the nodes, they are asked to try again in a few minutes. + if ($already_user === false && is_metaconsole() === false) { + $config['pending_sync_process_message'] = __('Successful login, please wait a few minutes for the metaconsole to synchronize with the nodes and then log in again with the same credentials.'); + } + } + } else { + $sr = ldap_process_user_login($login, $pass); + // Try with secondary server if not login. + if ($sr === false && (bool) $config['secondary_ldap_enabled'] === true) { + $sr = ldap_process_user_login($login, $pass, true); + } } if (!$sr) { @@ -237,10 +255,22 @@ function process_user_login_remote($login, $pass, $api=false) // Active Directory. case 'ad': - $sr = enterprise_hook('ad_process_user_login', [$login, $pass]); - // Try with secondary server. - if ($sr === false && (bool) $config['secondary_active_directory'] === true) { - $sr = enterprise_hook('ad_process_user_login', [$login, $pass, true]); + if ($create_by_remote_api === true) { + $sr = ldap_process_user_login_by_api($login, $pass); + if ($sr !== false && isset($sr['uid']) === true && is_array($sr['uid']) === true) { + $already_user = db_get_value('id_user', 'tusuario', 'id_user', $sr['uid'][0]); + // If the node is centralized, AD login is delegated to the metaconsole via the API. + // Since the user is not yet on the nodes, they are asked to try again in a few minutes. + if ($already_user === false && is_metaconsole() === false) { + $config['pending_sync_process_message'] = __('Successful login, please wait a few minutes for the metaconsole to synchronize with the nodes and then log in again with the same credentials.'); + } + } + } else { + $sr = enterprise_hook('ad_process_user_login', [$login, $pass]); + // Try with secondary server. + if ($sr === false && (bool) $config['secondary_active_directory'] === true) { + $sr = enterprise_hook('ad_process_user_login', [$login, $pass, true]); + } } if ($sr === false) { @@ -278,7 +308,7 @@ function process_user_login_remote($login, $pass, $api=false) if (($config['auth'] === 'ad')) { // Check if autocreate remote users is active. - if ($config['autocreate_remote_users'] == 1) { + if ($create_by_remote_api === false && $config['autocreate_remote_users'] == 1) { if ($config['ad_save_password']) { $update_credentials = change_local_user_pass_ldap($login, $pass); } else { @@ -286,7 +316,7 @@ function process_user_login_remote($login, $pass, $api=false) } } - if (isset($config['ad_advanced_config']) && $config['ad_advanced_config']) { + if ($create_by_remote_api === false && isset($config['ad_advanced_config']) && $config['ad_advanced_config']) { $return = enterprise_hook( 'prepare_permissions_groups_of_user_ad', [ @@ -305,7 +335,7 @@ function process_user_login_remote($login, $pass, $api=false) } } else if ($config['auth'] === 'ldap') { // Check if autocreate remote users is active. - if ($config['autocreate_remote_users'] == 1) { + if ($create_by_remote_api === false && $config['autocreate_remote_users'] == 1) { if ($config['ldap_save_password']) { $update_credentials = change_local_user_pass_ldap($login, $pass); } else { @@ -351,11 +381,6 @@ function process_user_login_remote($login, $pass, $api=false) && (isset($config['ad_advanced_config']) && $config['ad_advanced_config']) ) { - if (is_management_allowed() === false) { - $config['auth_error'] = __('Please, login into metaconsole first'); - return false; - } - $user_info = [ 'fullname' => db_escape_string_sql($login), 'comments' => 'Imported from '.$config['auth'], @@ -365,27 +390,24 @@ function process_user_login_remote($login, $pass, $api=false) $user_info['metaconsole_access_node'] = $config['ad_adv_user_node']; } - // Create the user. - if (enterprise_hook( - 'prepare_permissions_groups_of_user_ad', - [ - $login, - $pass, - $user_info, - false, - defined('METACONSOLE') && is_centralized() === false, - ] - ) === false - ) { - $config['auth_error'] = __('User not found in database or incorrect password'); - return false; + if ($create_by_remote_api === false) { + // Create the user. + if (enterprise_hook( + 'prepare_permissions_groups_of_user_ad', + [ + $login, + $pass, + $user_info, + false, + defined('METACONSOLE') && is_centralized() === false, + ] + ) === false + ) { + $config['auth_error'] = __('User not found in database or incorrect password'); + return false; + } } } else if ($config['auth'] === 'ldap') { - if (is_management_allowed() === false) { - $config['auth_error'] = __('Please, login into metaconsole first'); - return false; - } - if (is_metaconsole() === true) { $user_info['metaconsole_access_node'] = $config['ldap_adv_user_node']; } @@ -401,15 +423,16 @@ function process_user_login_remote($login, $pass, $api=false) } else { $user_info['fullname'] = db_escape_string_sql(io_safe_input($sr['cn'][0])); $user_info['email'] = io_safe_input($sr['mail'][0]); - - // Create the user. - $create_user = create_user_and_permisions_ldap( - $login, - $pass, - $user_info, - $permissions, - is_metaconsole() && is_centralized() === false - ); + if ($create_by_remote_api === false) { + // Create the user. + $create_user = create_user_and_permisions_ldap( + $login, + $pass, + $user_info, + $permissions, + is_metaconsole() && is_centralized() === false + ); + } } } else { $user_info = [ @@ -420,24 +443,26 @@ function process_user_login_remote($login, $pass, $api=false) $user_info['metaconsole_access_node'] = $config['ad_adv_user_node']; } - if (is_management_allowed() === false) { + if ($create_by_remote_api === false && is_management_allowed() === false) { $config['auth_error'] = __('Please, login into metaconsole first'); return false; } // Create the user in the local database. - if (create_user($login, $pass, $user_info) === false) { + if ($create_by_remote_api === false && create_user($login, $pass, $user_info) === false) { $config['auth_error'] = __('User not found in database or incorrect password'); return false; } - profile_create_user_profile( - $login, - $config['default_remote_profile'], - $config['default_remote_group'], - false, - $config['default_assign_tags'] - ); + if ($create_by_remote_api === false) { + profile_create_user_profile( + $login, + $config['default_remote_profile'], + $config['default_remote_group'], + false, + $config['default_assign_tags'] + ); + } } return $login; @@ -988,6 +1013,7 @@ function ldap_process_user_login($login, $password, $secondary_server=false) if ($memberof['count'] == 0 && !isset($memberof[0]['memberof'])) { @ldap_close($ds); + $config['auth_error'] = 'User not found in database or incorrect password'; return false; } else { $memberof = $memberof[0]; @@ -1644,5 +1670,79 @@ function local_ldap_search( } +/** + * Performs the LDAP login process by delegating it to the metaconsole via the API. + * It will return the user's ID and email if successful in LDAP format. USE ONLY ON NODE. + * + * @param string $user User to login. + * @param string $pass Password of user. + * + * @return false|array + */ +function ldap_process_user_login_by_api($user, $pass) +{ + global $config; + if (is_metaconsole() === true) { + return false; + } + + metaconsole_load_external_db( + [ + 'dbhost' => $config['replication_dbhost'], + 'dbuser' => $config['replication_dbuser'], + 'dbpass' => io_output_password($config['replication_dbpass']), + 'dbname' => $config['replication_dbname'], + ] + ); + $serverUniqueIdentifier = db_get_value('value', 'tconfig', 'token', 'server_unique_identifier'); + $apiPassword = db_get_value('value', 'tconfig', 'token', 'api_password'); + $token = generate_token_for_system($serverUniqueIdentifier, $apiPassword); + metaconsole_restore_db(); + + $url = $config['metaconsole_base_url']; + $url .= (substr($config['metaconsole_base_url'], -1) === '/') ? '' : '/'; + $curl = curl_init(); + curl_setopt_array( + $curl, + [ + CURLOPT_URL => $url.'api/v2/user/'.urlencode($user).'/login?password='.urlencode($pass), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => [ + 'Accept: application/json', + 'Authorization: Bearer '.$token, + ], + CURLOPT_RETURNTRANSFER => true, + ] + ); + + $response = json_decode(curl_exec($curl), true); + $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + if ($code === 200) { + if (isset($response['idUser']) === true) { + $ldap_format = [ + 'mail' => [$response['email']], + 'uid' => [$response['idUser']], + ]; + + return $ldap_format; + } else { + return false; + } + } else { + if (isset($response['error']) === true) { + $config['auth_error'] = $response['error']; + } else { + $config['auth_error'] = __('Unexpected error'); + } + + return false; + } +} + + // Reference the global use authorization error to last auth error. $config['auth_error'] = &$mysql_cache['auth_error']; diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php index d4c71597fc..7d6f952bae 100644 --- a/pandora_console/include/functions_config.php +++ b/pandora_console/include/functions_config.php @@ -513,6 +513,10 @@ function config_update_config() if (config_update_value('ipam_ocuppied_warning_treshold', get_parameter('ipam_ocuppied_warning_treshold'), true) === false) { $error_update[] = __('Ipam Ocuppied Manager Warning'); } + + if (config_update_value('metaconsole_base_url', get_parameter('metaconsole_base_url'), true) === false) { + $error_update[] = __('Metaconsole base url'); + } } break; diff --git a/pandora_console/include/functions_token.php b/pandora_console/include/functions_token.php index 41d1107943..0914da5612 100644 --- a/pandora_console/include/functions_token.php +++ b/pandora_console/include/functions_token.php @@ -155,3 +155,23 @@ function delete_user_token(int $idToken): bool return $result; } + + +/** + * Generate token for use ONLY in pandora. + * + * @param string $serverUniqueIdentifier Value server_unique_identifier from tconfig. + * @param string $apiPassword Value api_password from tconfig. + * + * @return string + */ +function generate_token_for_system(string $serverUniqueIdentifier='', string $apiPassword=''):string +{ + if (empty($serverUniqueIdentifier) === true + || empty($apiPassword) === true + ) { + return ''; + } + + return md5($serverUniqueIdentifier).md5($apiPassword); +} diff --git a/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php b/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php index 8c1ecc1ee7..cd10e0d1f0 100644 --- a/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php +++ b/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php @@ -2,7 +2,6 @@ namespace PandoraFMS\Modules\Shared\Middlewares; -use PandoraFMS\Modules\Shared\Services\Config; use PandoraFMS\Modules\Authentication\Services\GetUserTokenService; use PandoraFMS\Modules\Authentication\Services\UpdateTokenService; use PandoraFMS\Modules\Authentication\Services\ValidateServerIdentifierTokenService; @@ -20,14 +19,20 @@ final class UserTokenMiddleware private readonly ValidateUserTokenService $validateUserTokenService, private readonly GetUserTokenService $getUserTokenService, private readonly UpdateTokenService $updateTokenService, - private readonly Timestamp $timestamp, - private readonly Config $config + private readonly Timestamp $timestamp ) { } public function check(Request $request): bool { + global $config; + + // DO NOT REMOVE THIS LINE. + // In case a JSON error occurs outside of the API, it will be reset to handle + // formatting errors in the parameters. + json_encode([]); + $authorization = ($request->getHeader('Authorization')[0] ?? ''); $token = null; @@ -50,7 +55,7 @@ final class UserTokenMiddleware $validToken = $this->validateUserTokenService->__invoke($uuid, $strToken); $token = $this->getUserTokenService->__invoke($uuid); if ($token !== null && $validToken) { - $this->config->set('id_user', $token->getIdUser()); + $config['id_user'] = $token->getIdUser(); $oldToken = clone $token; $token->setLastUsage($this->timestamp->getMysqlCurrentTimestamp(0)); $this->updateTokenService->__invoke($token, $oldToken); @@ -70,10 +75,10 @@ final class UserTokenMiddleware if ($validTokenUiniqueServerIdentifier === true) { $_SESSION['id_usuario'] = 'admin'; - $this->config->set('id_user', 'admin'); + $config['id_user'] = 'admin'; } else { $_SESSION['id_usuario'] = $token->getIdUser(); - $this->config->set('id_user', $token->getIdUser()); + $config['id_user'] = $token->getIdUser(); } if (session_status() === PHP_SESSION_ACTIVE) { diff --git a/pandora_console/index.php b/pandora_console/index.php index cb09883501..addea2babb 100755 --- a/pandora_console/index.php +++ b/pandora_console/index.php @@ -578,6 +578,15 @@ if (isset($config['id_user']) === false) { exit(''); } + if (isset($config['pending_sync_process_message']) === true) { + include_once 'general/login_page.php'; + while (ob_get_length() > 0) { + ob_end_flush(); + } + + exit(''); + } + // Login ok and password has not expired. $process_login = true;