#13548 new method login ldap from nodo when metaconsole is centralized

This commit is contained in:
Daniel Cebrian 2024-05-08 12:58:05 +02:00
parent 25d17fb990
commit 38a886f4bf
5 changed files with 187 additions and 25 deletions

View File

@ -712,6 +712,29 @@ if ($login_screen === 'disabled_access_node') {
echo '</div>';
}
if (empty($process_error_message) === true
&& isset($config['pending_sync_process_message']) === true
&& $login_screen === 'login'
) {
echo '<div id="pending_sync_process" title="'.__('Centralized user in metaconsole').'">';
echo '<div class="content_alert">';
echo '<div class="icon_message_alert">';
echo html_print_image('images/icono_logo_pandora.png', true, ['alt' => __('Pending synchronization process'), 'border' => 0]);
echo '</div>';
echo '<div class="content_message_alert">';
echo '<div class="text_message_alert">';
echo '<h1>'.__('Access granted').'</h1>';
echo '<p>'.$config['pending_sync_process_message'].'</p>';
echo '</div>';
echo '<br>';
echo '<div class="button_message_alert">';
html_print_submit_button('Ok', 'hide-sync-process', false, ['class' => 'mini float-right']);
echo '</div>';
echo '</div>';
echo '</div>';
echo '</div>';
}
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;

View File

@ -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) {
@ -305,7 +323,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 {
@ -381,11 +399,6 @@ function process_user_login_remote($login, $pass, $api=false)
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 +414,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 = [
@ -988,6 +1002,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 +1659,77 @@ 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();
$curl = curl_init();
curl_setopt_array(
$curl,
[
CURLOPT_URL => $config['metaconsole_base_url'].'api/v2/user/'.$user.'/login?password='.$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['email']) === true
&& 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'];
}
return false;
}
}
// Reference the global use authorization error to last auth error.
$config['auth_error'] = &$mysql_cache['auth_error'];

View File

@ -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);
}

View File

@ -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) {

View File

@ -578,6 +578,15 @@ if (isset($config['id_user']) === false) {
exit('</html>');
}
if (isset($config['pending_sync_process_message']) === true) {
include_once 'general/login_page.php';
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
}
// Login ok and password has not expired.
$process_login = true;