[Web] Feature (beta): Add WebAuthn support for administrators and domain administrators
This commit is contained in:
@@ -924,20 +924,10 @@ function set_tfa($_data) {
|
||||
case "totp":
|
||||
$key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"];
|
||||
if ($tfa->verifyCode($_POST['totp_secret'], $_POST['totp_confirm_token']) === true) {
|
||||
try {
|
||||
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `secret`, `active`) VALUES (?, ?, 'totp', ?, '1')");
|
||||
$stmt->execute(array($username, $key_id, $_POST['totp_secret']));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_data_log),
|
||||
@@ -953,18 +943,142 @@ function set_tfa($_data) {
|
||||
}
|
||||
break;
|
||||
case "none":
|
||||
try {
|
||||
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_data_log),
|
||||
'msg' => array('object_modified', htmlspecialchars($username))
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
function fido2($_data) {
|
||||
global $pdo;
|
||||
$_data_log = $_data;
|
||||
// Not logging registration data, only actions
|
||||
// Silent errors for "get" requests
|
||||
switch ($_data["action"]) {
|
||||
case "register":
|
||||
$username = $_SESSION['mailcow_cc_username'];
|
||||
if ($_SESSION['mailcow_cc_role'] != "domainadmin" &&
|
||||
$_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_data["action"]),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("INSERT INTO `fido2` (`username`, `rpId`, `credentialPublicKey`, `certificateChain`, `certificate`, `certificateIssuer`, `certificateSubject`, `signatureCounter`, `AAGUID`, `credentialId`)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute(array(
|
||||
$username,
|
||||
$_data['registration']->rpId,
|
||||
$_data['registration']->credentialPublicKey,
|
||||
$_data['registration']->certificateChain,
|
||||
$_data['registration']->certificate,
|
||||
$_data['registration']->certificateIssuer,
|
||||
$_data['registration']->certificateSubject,
|
||||
$_data['registration']->signatureCounter,
|
||||
$_data['registration']->AAGUID,
|
||||
$_data['registration']->credentialId)
|
||||
);
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_data["action"]),
|
||||
'msg' => array('object_modified', $username)
|
||||
);
|
||||
break;
|
||||
case "get_user_cids":
|
||||
// Used to exclude existing CredentialIds while registering
|
||||
$username = $_SESSION['mailcow_cc_username'];
|
||||
if ($_SESSION['mailcow_cc_role'] != "domainadmin" &&
|
||||
$_SESSION['mailcow_cc_role'] != "admin") {
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT `credentialId` FROM `fido2` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while($row = array_shift($rows)) {
|
||||
$cids[] = $row['credentialId'];
|
||||
}
|
||||
return $cids;
|
||||
break;
|
||||
case "get_all_cids":
|
||||
// Only needed when using fido2 with username
|
||||
$stmt = $pdo->query("SELECT `credentialId` FROM `fido2`");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while($row = array_shift($rows)) {
|
||||
$cids[] = $row['credentialId'];
|
||||
}
|
||||
return $cids;
|
||||
break;
|
||||
case "get_pub_key":
|
||||
if (!isset($_data['cid']) || empty($_data['cid'])) {
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT `certificateSubject`, `username`, `credentialPublicKey` FROM `fido2` WHERE TO_BASE64(`credentialId`) = :cid");
|
||||
$stmt->execute(array(':cid' => $_data['cid']));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (empty($row) || empty($row['credentialPublicKey']) || empty($row['username'])) {
|
||||
return false;
|
||||
}
|
||||
$data['pub_key'] = $row['credentialPublicKey'];
|
||||
$data['username'] = $row['username'];
|
||||
$data['key_id'] = $row['certificateSubject'];
|
||||
return $data;
|
||||
break;
|
||||
case "get_friendly_names":
|
||||
$username = $_SESSION['mailcow_cc_username'];
|
||||
if ($_SESSION['mailcow_cc_role'] != "domainadmin" &&
|
||||
$_SESSION['mailcow_cc_role'] != "admin") {
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT `certificateSubject`, `friendlyName` FROM `fido2` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while($row = array_shift($rows)) {
|
||||
$fns[] = array("subject" => $row['certificateSubject'], "fn" => $row['friendlyName']);
|
||||
}
|
||||
return $fns;
|
||||
break;
|
||||
case "unset_fido2_key":
|
||||
$username = $_SESSION['mailcow_cc_username'];
|
||||
if ($_SESSION['mailcow_cc_role'] != "domainadmin" &&
|
||||
$_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_data["action"]),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username AND `certificateSubject` = :certificateSubject");
|
||||
$stmt->execute(array(':username' => $username, ':certificateSubject' => $_data['post_data']['unset_fido2_key']));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_data_log),
|
||||
'msg' => array('object_modified', htmlspecialchars($username))
|
||||
);
|
||||
break;
|
||||
case "edit_fn":
|
||||
$username = $_SESSION['mailcow_cc_username'];
|
||||
if ($_SESSION['mailcow_cc_role'] != "domainadmin" &&
|
||||
$_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_data["action"]),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("UPDATE `fido2` SET `friendlyName` = :friendlyName WHERE `certificateSubject` = :certificateSubject AND `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':friendlyName' => $_data['fido2_attrs']['fido2_fn'],
|
||||
':certificateSubject' => base64_decode($_data['fido2_attrs']['fido2_subject'])
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_data_log),
|
||||
|
Reference in New Issue
Block a user