mirror of
https://github.com/itflow-org/itflow
synced 2026-08-24 08:25:14 +00:00
Fix login not passing master key if agent is client and agent and if MFA is enabled
This commit is contained in:
@@ -17,7 +17,7 @@ $client_id = intval($row['client_id']);
|
|||||||
$client_name = nullable_htmlentities($row['client_name']);
|
$client_name = nullable_htmlentities($row['client_name']);
|
||||||
$contact_name = nullable_htmlentities($row['contact_name']);
|
$contact_name = nullable_htmlentities($row['contact_name']);
|
||||||
$contact_title = nullable_htmlentities($row['contact_title']);
|
$contact_title = nullable_htmlentities($row['contact_title']);
|
||||||
$contact_department =nullable_htmlentities($row['contact_department']);
|
$contact_department = nullable_htmlentities($row['contact_department']);
|
||||||
$contact_phone_country_code = nullable_htmlentities($row['contact_phone_country_code']);
|
$contact_phone_country_code = nullable_htmlentities($row['contact_phone_country_code']);
|
||||||
$contact_phone = nullable_htmlentities(formatPhoneNumber($row['contact_phone'], $contact_phone_country_code));
|
$contact_phone = nullable_htmlentities(formatPhoneNumber($row['contact_phone'], $contact_phone_country_code));
|
||||||
$contact_extension = nullable_htmlentities($row['contact_extension']);
|
$contact_extension = nullable_htmlentities($row['contact_extension']);
|
||||||
@@ -196,6 +196,56 @@ ob_start();
|
|||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<ul class="nav nav-pills nav-justified mt-3">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-details"><i class="fas fa-fw fa-user fa-2x"></i><br>Details</a>
|
||||||
|
</li>
|
||||||
|
<?php if ($asset_count) { ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-assets<?= $contact_id ?>"><i class="fas fa-fw fa-desktop fa-2x"></i><br>Assets (<?= $asset_count ?>)</a>
|
||||||
|
</li>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if ($credential_count) { ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-credentials<?= $contact_id ?>"><i class="fas fa-fw fa-key fa-2x"></i><br>Credentials (<?= $credential_count ?>)</a>
|
||||||
|
</li>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if ($software_count) { ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-licenses<?= $contact_id ?>"><i class="fas fa-fw fa-cube fa-2x"></i><br>Licenses (<?= $software_count ?>)</a>
|
||||||
|
</li>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if ($ticket_count) { ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-tickets<?= $contact_id ?>"><i class="fas fa-fw fa-life-ring fa-2x"></i><br>Tickets (<?= $ticket_count ?>)</a>
|
||||||
|
</li>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if ($recurring_ticket_count) { ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-recurring-tickets<?= $contact_id ?>"><i class="fas fa-fw fa-redo-alt fa-2x"></i><br>Rcr Tickets (<?= $recurring_ticket_count ?>)</a>
|
||||||
|
</li>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if ($document_count) { ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-documents<?= $contact_id ?>"><i class="fas fa-fw fa-file-alt fa-2x"></i><br>Documents (<?= $document_count ?>)</a>
|
||||||
|
</li>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if ($file_count) { ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-files<?= $contact_id ?>"><i class="fas fa-fw fa-briefcase fa-2x"></i><br>Files (<?= $file_count ?>)</a>
|
||||||
|
</li>
|
||||||
|
<?php } ?>
|
||||||
|
<?php if ($note_count) { ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="pill" href="#pills-contact-notes<?= $contact_id ?>"><i class="fas fa-fw fa-edit fa-2x"></i><br>Notes (<?= $note_count ?>)</a>
|
||||||
|
</li>
|
||||||
|
<?php } ?>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
|
||||||
|
<div class="tab-pane fade" id="pills-contact-details">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<?php if ($contact_phone || $contact_mobile || $contact_extension || $contact_email) { ?>
|
<?php if ($contact_phone || $contact_mobile || $contact_extension || $contact_email) { ?>
|
||||||
@@ -276,50 +326,7 @@ ob_start();
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="nav nav-pills nav-justified mt-3">
|
</div>
|
||||||
<?php if ($asset_count) { ?>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" data-toggle="pill" href="#pills-contact-assets<?= $contact_id ?>"><i class="fas fa-fw fa-desktop fa-2x"></i><br>Assets (<?= $asset_count ?>)</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
|
||||||
<?php if ($credential_count) { ?>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" data-toggle="pill" href="#pills-contact-credentials<?= $contact_id ?>"><i class="fas fa-fw fa-key fa-2x"></i><br>Credentials (<?= $credential_count ?>)</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
|
||||||
<?php if ($software_count) { ?>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" data-toggle="pill" href="#pills-contact-licenses<?= $contact_id ?>"><i class="fas fa-fw fa-cube fa-2x"></i><br>Licenses (<?= $software_count ?>)</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
|
||||||
<?php if ($ticket_count) { ?>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" data-toggle="pill" href="#pills-contact-tickets<?= $contact_id ?>"><i class="fas fa-fw fa-life-ring fa-2x"></i><br>Tickets (<?= $ticket_count ?>)</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
|
||||||
<?php if ($recurring_ticket_count) { ?>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" data-toggle="pill" href="#pills-contact-recurring-tickets<?= $contact_id ?>"><i class="fas fa-fw fa-redo-alt fa-2x"></i><br>Rcr Tickets (<?= $recurring_ticket_count ?>)</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
|
||||||
<?php if ($document_count) { ?>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" data-toggle="pill" href="#pills-contact-documents<?= $contact_id ?>"><i class="fas fa-fw fa-file-alt fa-2x"></i><br>Documents (<?= $document_count ?>)</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
|
||||||
<?php if ($file_count) { ?>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" data-toggle="pill" href="#pills-contact-files<?= $contact_id ?>"><i class="fas fa-fw fa-briefcase fa-2x"></i><br>Files (<?= $file_count ?>)</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
|
||||||
<?php if ($note_count) { ?>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" data-toggle="pill" href="#pills-contact-notes<?= $contact_id ?>"><i class="fas fa-fw fa-edit fa-2x"></i><br>Notes (<?= $note_count ?>)</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="tab-content">
|
|
||||||
|
|
||||||
<?php if ($asset_count) { ?>
|
<?php if ($asset_count) { ?>
|
||||||
<div class="tab-pane fade" id="pills-contact-assets<?= $contact_id ?>">
|
<div class="tab-pane fade" id="pills-contact-assets<?= $contact_id ?>">
|
||||||
|
|||||||
44
login.php
44
login.php
@@ -305,8 +305,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['login']) || isset($_
|
|||||||
// Proceed if selected
|
// Proceed if selected
|
||||||
if ($selectedRow !== null && $selectedType !== null) {
|
if ($selectedRow !== null && $selectedType !== null) {
|
||||||
|
|
||||||
// Clear dual pending once we actually proceed
|
// Cache pending sessions BEFORE unsetting anything (needed for role->MFA and MFA success)
|
||||||
unset($_SESSION['pending_dual_login']);
|
$pending_dual = $_SESSION['pending_dual_login'] ?? null;
|
||||||
|
$pending_mfa = $_SESSION['pending_mfa_login'] ?? null;
|
||||||
|
|
||||||
|
// NOTE: do NOT unset pending_dual_login here anymore; we may still need agent_master_key for MFA or role-step agent login
|
||||||
|
|
||||||
$user_id = intval($selectedRow['user_id']);
|
$user_id = intval($selectedRow['user_id']);
|
||||||
$user_email = sanitizeInput($selectedRow['user_email']);
|
$user_email = sanitizeInput($selectedRow['user_email']);
|
||||||
@@ -364,9 +367,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['login']) || isset($_
|
|||||||
|
|
||||||
if ($mfa_is_complete) {
|
if ($mfa_is_complete) {
|
||||||
|
|
||||||
// Clear pending MFA if exists
|
|
||||||
unset($_SESSION['pending_mfa_login']);
|
|
||||||
|
|
||||||
// Remember me token creation
|
// Remember me token creation
|
||||||
if (isset($_POST['remember_me'])) {
|
if (isset($_POST['remember_me'])) {
|
||||||
$newRememberToken = bin2hex(random_bytes(64));
|
$newRememberToken = bin2hex(random_bytes(64));
|
||||||
@@ -429,17 +429,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['login']) || isset($_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup encryption session key WITHOUT PASSWORD IN SESSION
|
// Setup encryption session key WITHOUT PASSWORD IN SESSION
|
||||||
// If we are coming from MFA step, master key is in pending_mfa_login.
|
|
||||||
// If we are coming from login step with no MFA, decrypt now.
|
|
||||||
$site_encryption_master_key = null;
|
$site_encryption_master_key = null;
|
||||||
|
|
||||||
if ($is_mfa_step) {
|
if ($is_mfa_step) {
|
||||||
$sess = $_SESSION['pending_mfa_login'] ?? null;
|
// Step 3: MFA submit
|
||||||
if ($sess && isset($sess['agent_master_key'])) {
|
$sess = $pending_mfa ?? ($_SESSION['pending_mfa_login'] ?? null);
|
||||||
|
if ($sess && !empty($sess['agent_master_key'])) {
|
||||||
$site_encryption_master_key = $sess['agent_master_key'];
|
$site_encryption_master_key = $sess['agent_master_key'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} elseif ($is_role_step) {
|
||||||
|
// Step 2: role choice (no password available)
|
||||||
|
$sess = $pending_dual ?? ($_SESSION['pending_dual_login'] ?? null);
|
||||||
|
if ($sess && !empty($sess['agent_master_key'])) {
|
||||||
|
$site_encryption_master_key = $sess['agent_master_key'];
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// No MFA step: password exists in this request (Step 1)
|
// Step 1: initial login (password available in this request)
|
||||||
if (!empty($user_encryption_ciphertext)) {
|
if (!empty($user_encryption_ciphertext)) {
|
||||||
$site_encryption_master_key = decryptUserSpecificKey($user_encryption_ciphertext, $password);
|
$site_encryption_master_key = decryptUserSpecificKey($user_encryption_ciphertext, $password);
|
||||||
}
|
}
|
||||||
@@ -449,6 +456,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['login']) || isset($_
|
|||||||
generateUserSessionKey($site_encryption_master_key);
|
generateUserSessionKey($site_encryption_master_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOW safe to clear pending sessions AFTER we used them
|
||||||
|
unset($_SESSION['pending_mfa_login']);
|
||||||
|
unset($_SESSION['pending_dual_login']);
|
||||||
|
|
||||||
// Redirect
|
// Redirect
|
||||||
if (isset($_GET['last_visited']) && (str_starts_with(base64_decode($_GET['last_visited']), '/agent') || str_starts_with(base64_decode($_GET['last_visited']), '/admin'))) {
|
if (isset($_GET['last_visited']) && (str_starts_with(base64_decode($_GET['last_visited']), '/agent') || str_starts_with(base64_decode($_GET['last_visited']), '/admin'))) {
|
||||||
redirect($_SERVER["REQUEST_SCHEME"] . "://" . $config_base_url . base64_decode($_GET['last_visited']));
|
redirect($_SERVER["REQUEST_SCHEME"] . "://" . $config_base_url . base64_decode($_GET['last_visited']));
|
||||||
@@ -461,13 +472,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['login']) || isset($_
|
|||||||
// MFA required — store *only what we need*, not password
|
// MFA required — store *only what we need*, not password
|
||||||
$pending_mfa_token = bin2hex(random_bytes(32));
|
$pending_mfa_token = bin2hex(random_bytes(32));
|
||||||
|
|
||||||
// If we arrived here from role-choice step, the agent master key may be in pending_dual_login
|
// If we arrived here from role-choice step, the agent master key may be in cached pending_dual
|
||||||
// If we arrived from initial login step, decrypt now (password in memory) and store master key.
|
// If we arrived from initial login step, decrypt now (password in memory) and store master key.
|
||||||
$agent_master_key = null;
|
$agent_master_key = null;
|
||||||
|
|
||||||
if ($is_role_step) {
|
if ($is_role_step) {
|
||||||
$sess = $_SESSION['pending_dual_login'] ?? null;
|
$sess = $pending_dual ?? ($_SESSION['pending_dual_login'] ?? null);
|
||||||
if ($sess && isset($sess['agent_master_key'])) {
|
if ($sess && array_key_exists('agent_master_key', $sess)) {
|
||||||
$agent_master_key = $sess['agent_master_key'];
|
$agent_master_key = $sess['agent_master_key'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -484,6 +495,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['login']) || isset($_
|
|||||||
'created' => time()
|
'created' => time()
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Now that we've transferred what we need, it's safe to clear the dual-role pending session.
|
||||||
|
unset($_SESSION['pending_dual_login']);
|
||||||
|
|
||||||
$token_field = "
|
$token_field = "
|
||||||
<div class='input-group mb-3'>
|
<div class='input-group mb-3'>
|
||||||
<input type='text' inputmode='numeric' pattern='[0-9]*' maxlength='6'
|
<input type='text' inputmode='numeric' pattern='[0-9]*' maxlength='6'
|
||||||
@@ -567,6 +581,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['login']) || isset($_
|
|||||||
$session_user_id = $user_id;
|
$session_user_id = $user_id;
|
||||||
logAction("Client Login", "Success", "Client contact $user_email successfully logged in locally", $client_id, $user_id);
|
logAction("Client Login", "Success", "Client contact $user_email successfully logged in locally", $client_id, $user_id);
|
||||||
|
|
||||||
|
// Clear any pending sessions (avoid stale dual-role/MFA state)
|
||||||
|
unset($_SESSION['pending_dual_login']);
|
||||||
|
unset($_SESSION['pending_mfa_login']);
|
||||||
|
|
||||||
header("Location: client/index.php");
|
header("Location: client/index.php");
|
||||||
exit();
|
exit();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user