|
|
|
@@ -830,11 +830,15 @@ function check_login($user, $pass, $app_passwd_data = false) {
|
|
|
|
|
$stmt->execute(array(':user' => $user));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
foreach ($rows as $row) {
|
|
|
|
|
// verify password
|
|
|
|
|
if (verify_hash($row['password'], $pass)) {
|
|
|
|
|
if (get_tfa($user)['name'] != "none") {
|
|
|
|
|
// check for tfa authenticators
|
|
|
|
|
$authenticators = get_tfa($user);
|
|
|
|
|
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
|
|
|
|
|
// active tfa authenticators found, set pending user login
|
|
|
|
|
$_SESSION['pending_mailcow_cc_username'] = $user;
|
|
|
|
|
$_SESSION['pending_mailcow_cc_role'] = "admin";
|
|
|
|
|
$_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
|
|
|
|
|
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
|
|
|
|
|
unset($_SESSION['ldelay']);
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
'type' => 'info',
|
|
|
|
@@ -842,8 +846,7 @@ function check_login($user, $pass, $app_passwd_data = false) {
|
|
|
|
|
'msg' => 'awaiting_tfa_confirmation'
|
|
|
|
|
);
|
|
|
|
|
return "pending";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
unset($_SESSION['ldelay']);
|
|
|
|
|
// Reactivate TFA if it was set to "deactivate TFA for next login"
|
|
|
|
|
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
|
|
|
|
@@ -866,11 +869,14 @@ function check_login($user, $pass, $app_passwd_data = false) {
|
|
|
|
|
$stmt->execute(array(':user' => $user));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
foreach ($rows as $row) {
|
|
|
|
|
// verify password
|
|
|
|
|
if (verify_hash($row['password'], $pass) !== false) {
|
|
|
|
|
if (get_tfa($user)['name'] != "none") {
|
|
|
|
|
// check for tfa authenticators
|
|
|
|
|
$authenticators = get_tfa($user);
|
|
|
|
|
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
|
|
|
|
|
$_SESSION['pending_mailcow_cc_username'] = $user;
|
|
|
|
|
$_SESSION['pending_mailcow_cc_role'] = "domainadmin";
|
|
|
|
|
$_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
|
|
|
|
|
$_SESSION['pending_tfa_method'] = $authenticators['additional'];
|
|
|
|
|
unset($_SESSION['ldelay']);
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
'type' => 'info',
|
|
|
|
@@ -1142,47 +1148,46 @@ function set_tfa($_data) {
|
|
|
|
|
global $yubi;
|
|
|
|
|
global $tfa;
|
|
|
|
|
$_data_log = $_data;
|
|
|
|
|
$access_denied = null;
|
|
|
|
|
!isset($_data_log['confirm_password']) ?: $_data_log['confirm_password'] = '*';
|
|
|
|
|
$username = $_SESSION['mailcow_cc_username'];
|
|
|
|
|
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
'type' => 'danger',
|
|
|
|
|
'log' => array(__FUNCTION__, $_data_log),
|
|
|
|
|
'msg' => 'access_denied'
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
|
|
|
|
|
WHERE `username` = :username");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
|
|
|
if (!empty($num_results)) {
|
|
|
|
|
if (!verify_hash($row['password'], $_data["confirm_password"])) {
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
'type' => 'danger',
|
|
|
|
|
'log' => array(__FUNCTION__, $_data_log),
|
|
|
|
|
'msg' => 'access_denied'
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
|
|
|
|
|
WHERE `username` = :username");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
|
|
|
if (!empty($num_results)) {
|
|
|
|
|
if (!verify_hash($row['password'], $_data["confirm_password"])) {
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
'type' => 'danger',
|
|
|
|
|
'log' => array(__FUNCTION__, $_data_log),
|
|
|
|
|
'msg' => 'access_denied'
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// check for empty user and role
|
|
|
|
|
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) $access_denied = true;
|
|
|
|
|
|
|
|
|
|
// check admin confirm password
|
|
|
|
|
if ($access_denied === null) {
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
|
|
|
|
|
WHERE `username` = :username");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
if ($row) {
|
|
|
|
|
if (!verify_hash($row['password'], $_data["confirm_password"])) $access_denied = true;
|
|
|
|
|
else $access_denied = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check mailbox confirm password
|
|
|
|
|
if ($access_denied === null) {
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
|
|
|
|
|
WHERE `username` = :username");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
if ($row) {
|
|
|
|
|
if (!verify_hash($row['password'], $_data["confirm_password"])) $access_denied = true;
|
|
|
|
|
else $access_denied = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set access_denied error
|
|
|
|
|
if ($access_denied){
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
'type' => 'danger',
|
|
|
|
|
'log' => array(__FUNCTION__, $_data_log),
|
|
|
|
|
'msg' => 'access_denied'
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ($_data["tfa_method"]) {
|
|
|
|
|
case "yubi_otp":
|
|
|
|
@@ -1265,9 +1270,6 @@ function set_tfa($_data) {
|
|
|
|
|
case "webauthn":
|
|
|
|
|
$key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"];
|
|
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `authmech` != 'webauthn'");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`, `active`)
|
|
|
|
|
VALUES (?, ?, 'webauthn', ?, ?, ?, ?, '1')");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
@@ -1439,25 +1441,27 @@ function unset_tfa_key($_data) {
|
|
|
|
|
global $pdo;
|
|
|
|
|
global $lang;
|
|
|
|
|
$_data_log = $_data;
|
|
|
|
|
$access_denied = null;
|
|
|
|
|
$id = intval($_data['unset_tfa_key']);
|
|
|
|
|
$username = $_SESSION['mailcow_cc_username'];
|
|
|
|
|
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
'type' => 'danger',
|
|
|
|
|
'log' => array(__FUNCTION__, $_data_log),
|
|
|
|
|
'msg' => 'access_denied'
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check for empty user and role
|
|
|
|
|
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) $access_denied = true;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (!is_numeric($id)) {
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
if (!is_numeric($id)) $access_denied = true;
|
|
|
|
|
|
|
|
|
|
// set access_denied error
|
|
|
|
|
if ($access_denied){
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
|
'type' => 'danger',
|
|
|
|
|
'log' => array(__FUNCTION__, $_data_log),
|
|
|
|
|
'msg' => 'access_denied'
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if it's last key
|
|
|
|
|
$stmt = $pdo->prepare("SELECT COUNT(*) AS `keys` FROM `tfa`
|
|
|
|
|
WHERE `username` = :username AND `active` = '1'");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
@@ -1470,6 +1474,8 @@ function unset_tfa_key($_data) {
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delete key
|
|
|
|
|
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `id` = :id");
|
|
|
|
|
$stmt->execute(array(':username' => $username, ':id' => $id));
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
@@ -1487,7 +1493,7 @@ function unset_tfa_key($_data) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function get_tfa($username = null) {
|
|
|
|
|
function get_tfa($username = null, $key_id = null) {
|
|
|
|
|
global $pdo;
|
|
|
|
|
if (isset($_SESSION['mailcow_cc_username'])) {
|
|
|
|
|
$username = $_SESSION['mailcow_cc_username'];
|
|
|
|
@@ -1495,92 +1501,116 @@ function get_tfa($username = null) {
|
|
|
|
|
elseif (empty($username)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$stmt = $pdo->prepare("SELECT * FROM `tfa`
|
|
|
|
|
WHERE `username` = :username AND `active` = '1'");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
|
|
|
|
|
if (isset($row["authmech"])) {
|
|
|
|
|
switch ($row["authmech"]) {
|
|
|
|
|
case "yubi_otp":
|
|
|
|
|
$data['name'] = "yubi_otp";
|
|
|
|
|
$data['pretty'] = "Yubico OTP";
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
|
':username' => $username,
|
|
|
|
|
));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
while($row = array_shift($rows)) {
|
|
|
|
|
$data['additional'][] = $row;
|
|
|
|
|
if (!isset($key_id)){
|
|
|
|
|
// fetch all tfa methods - just get information about possible authenticators
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `authmech` FROM `tfa`
|
|
|
|
|
WHERE `username` = :username AND `active` = '1'");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
|
|
|
|
|
// no tfa methods found
|
|
|
|
|
if (count($results) == 0) {
|
|
|
|
|
$data['name'] = 'none';
|
|
|
|
|
$data['pretty'] = "-";
|
|
|
|
|
$data['additional'] = array();
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data['additional'] = $results;
|
|
|
|
|
return $data;
|
|
|
|
|
} else {
|
|
|
|
|
// fetch specific authenticator details by key_id
|
|
|
|
|
$stmt = $pdo->prepare("SELECT * FROM `tfa`
|
|
|
|
|
WHERE `username` = :username AND `active` = '1'");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
|
|
|
|
|
if (isset($row["authmech"])) {
|
|
|
|
|
switch ($row["authmech"]) {
|
|
|
|
|
case "yubi_otp":
|
|
|
|
|
$data['name'] = "yubi_otp";
|
|
|
|
|
$data['pretty'] = "Yubico OTP";
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
|
':username' => $username,
|
|
|
|
|
));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
while($row = array_shift($rows)) {
|
|
|
|
|
$data['additional'][] = $row;
|
|
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
// u2f - deprecated, should be removed
|
|
|
|
|
case "u2f":
|
|
|
|
|
$data['name'] = "u2f";
|
|
|
|
|
$data['pretty'] = "Fido U2F";
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
|
':username' => $username,
|
|
|
|
|
));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
while($row = array_shift($rows)) {
|
|
|
|
|
$data['additional'][] = $row;
|
|
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
case "hotp":
|
|
|
|
|
$data['name'] = "hotp";
|
|
|
|
|
$data['pretty'] = "HMAC-based OTP";
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
case "totp":
|
|
|
|
|
$data['name'] = "totp";
|
|
|
|
|
$data['pretty'] = "Time-based OTP";
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
|
':username' => $username,
|
|
|
|
|
));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
while($row = array_shift($rows)) {
|
|
|
|
|
$data['additional'][] = $row;
|
|
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
case "webauthn":
|
|
|
|
|
$data['name'] = "webauthn";
|
|
|
|
|
$data['pretty'] = "WebAuthn";
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
|
':username' => $username,
|
|
|
|
|
));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
while($row = array_shift($rows)) {
|
|
|
|
|
$data['additional'][] = $row;
|
|
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
$data['name'] = 'none';
|
|
|
|
|
$data['pretty'] = "-";
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
// u2f - deprecated, should be removed
|
|
|
|
|
case "u2f":
|
|
|
|
|
$data['name'] = "u2f";
|
|
|
|
|
$data['pretty'] = "Fido U2F";
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
|
':username' => $username,
|
|
|
|
|
));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
while($row = array_shift($rows)) {
|
|
|
|
|
$data['additional'][] = $row;
|
|
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
case "hotp":
|
|
|
|
|
$data['name'] = "hotp";
|
|
|
|
|
$data['pretty'] = "HMAC-based OTP";
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
case "totp":
|
|
|
|
|
$data['name'] = "totp";
|
|
|
|
|
$data['pretty'] = "Time-based OTP";
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
|
':username' => $username,
|
|
|
|
|
));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
while($row = array_shift($rows)) {
|
|
|
|
|
$data['additional'][] = $row;
|
|
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
case "webauthn":
|
|
|
|
|
$data['name'] = "webauthn";
|
|
|
|
|
$data['pretty'] = "WebAuthn";
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(
|
|
|
|
|
':username' => $username,
|
|
|
|
|
));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
while($row = array_shift($rows)) {
|
|
|
|
|
$data['additional'][] = $row;
|
|
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$data['name'] = 'none';
|
|
|
|
|
$data['pretty'] = "-";
|
|
|
|
|
return $data;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$data['name'] = 'none';
|
|
|
|
|
$data['pretty'] = "-";
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function verify_tfa_login($username, $_data, $WebAuthn) {
|
|
|
|
|
global $pdo;
|
|
|
|
|
global $yubi;
|
|
|
|
|
global $u2f;
|
|
|
|
|
global $tfa;
|
|
|
|
|
function verify_tfa_login($username, $_data) {
|
|
|
|
|
global $pdo;
|
|
|
|
|
global $yubi;
|
|
|
|
|
global $u2f;
|
|
|
|
|
global $tfa;
|
|
|
|
|
global $WebAuthn;
|
|
|
|
|
|
|
|
|
|
if ($_data['tfa_method'] != 'u2f'){
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
|
|
|
|
|
WHERE `username` = :username AND `active` = '1'");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
WHERE `username` = :username AND `key_id` = :key_id AND `active` = '1'");
|
|
|
|
|
$stmt->execute(array(':username' => $username, ':key_id' => $_data['key_id']));
|
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
|
|
|
|
|
switch ($row["authmech"]) {
|
|
|
|
@@ -1597,9 +1627,10 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
|
|
|
|
|
WHERE `username` = :username
|
|
|
|
|
AND `authmech` = 'yubi_otp'
|
|
|
|
|
AND `key_id` = ':key_id'
|
|
|
|
|
AND `active`='1'
|
|
|
|
|
AND `secret` LIKE :modhex");
|
|
|
|
|
$stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
|
|
|
|
|
$stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id, ':key_id' => $_data['key_id']));
|
|
|
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
$yubico_auth = explode(':', $row['secret']);
|
|
|
|
|
$yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]);
|
|
|
|
@@ -1636,8 +1667,9 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
|
|
|
|
|
WHERE `username` = :username
|
|
|
|
|
AND `authmech` = 'totp'
|
|
|
|
|
AND `key_id` = :key_id
|
|
|
|
|
AND `active`='1'");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$stmt->execute(array(':username' => $username, ':key_id' => $_data['key_id']));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
foreach ($rows as $row) {
|
|
|
|
|
if ($tfa->verifyCode($row['secret'], $_data['token']) === true) {
|
|
|
|
@@ -1666,13 +1698,6 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
// u2f - deprecated, should be removed
|
|
|
|
|
case "u2f":
|
|
|
|
|
// delete old keys that used u2f
|
|
|
|
|
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = :authmech AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(':authmech' => 'u2f', ':username' => $username));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
case "webauthn":
|
|
|
|
|
$tokenData = json_decode($_data['token']);
|
|
|
|
|
$clientDataJSON = base64_decode($tokenData->clientDataJSON);
|
|
|
|
@@ -1681,7 +1706,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
|
|
|
|
|
$id = base64_decode($tokenData->id);
|
|
|
|
|
$challenge = $_SESSION['challenge'];
|
|
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
|
|
|
|
|
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
|
|
|
|
|
$stmt->execute(array(':tokenId' => $tokenData->id));
|
|
|
|
|
$process_webauthn = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
|
|
|
|
|
@@ -1738,7 +1763,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$_SESSION["mailcow_cc_username"] = $process_webauthn['username'];
|
|
|
|
|
$_SESSION['tfa_id'] = $process_webauthn['key_id'];
|
|
|
|
|
$_SESSION['tfa_id'] = $process_webauthn['id'];
|
|
|
|
|
$_SESSION['authReq'] = null;
|
|
|
|
|
unset($_SESSION["challenge"]);
|
|
|
|
|
$_SESSION['return'][] = array(
|
|
|
|
@@ -1759,6 +1784,17 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
// delete old keys that used u2f
|
|
|
|
|
$stmt = $pdo->prepare("SELECT * FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
if (count($rows) == 0) return false;
|
|
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
|
|
|
|
|
$stmt->execute(array(':username' => $username));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function admin_api($access, $action, $data = null) {
|
|
|
|
|
global $pdo;
|
|
|
|
|