[Web] add verify selected tfa
This commit is contained in:
		@@ -1493,7 +1493,7 @@ function unset_tfa_key($_data) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
function get_tfa($username = null, $key_id = null) {
 | 
			
		||||
function get_tfa($username = null, $id = null) {
 | 
			
		||||
  global $pdo;
 | 
			
		||||
  if (isset($_SESSION['mailcow_cc_username'])) {
 | 
			
		||||
    $username = $_SESSION['mailcow_cc_username'];
 | 
			
		||||
@@ -1502,7 +1502,7 @@ function get_tfa($username = null, $key_id = null) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!isset($key_id)){
 | 
			
		||||
  if (!isset($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'");
 | 
			
		||||
@@ -1520,10 +1520,10 @@ function get_tfa($username = null, $key_id = null) {
 | 
			
		||||
    $data['additional'] = $results;
 | 
			
		||||
    return $data;
 | 
			
		||||
  } else {
 | 
			
		||||
    // fetch specific authenticator details by key_id
 | 
			
		||||
    // fetch specific authenticator details by id
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT * FROM `tfa`
 | 
			
		||||
    WHERE `username` = :username AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
    WHERE `username` = :username AND `id` = :id AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username, ':id' => $id));
 | 
			
		||||
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
 | 
			
		||||
    if (isset($row["authmech"])) {
 | 
			
		||||
@@ -1531,9 +1531,10 @@ function get_tfa($username = null, $key_id = null) {
 | 
			
		||||
          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 = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username AND `id` = :id");
 | 
			
		||||
            $stmt->execute(array(
 | 
			
		||||
              ':username' => $username,
 | 
			
		||||
              ':id' => $id
 | 
			
		||||
            ));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            while($row = array_shift($rows)) {
 | 
			
		||||
@@ -1545,9 +1546,10 @@ function get_tfa($username = null, $key_id = null) {
 | 
			
		||||
          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 = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username AND `id` = :id");
 | 
			
		||||
            $stmt->execute(array(
 | 
			
		||||
              ':username' => $username,
 | 
			
		||||
              ':id' => $id
 | 
			
		||||
            ));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            while($row = array_shift($rows)) {
 | 
			
		||||
@@ -1563,9 +1565,10 @@ function get_tfa($username = null, $key_id = null) {
 | 
			
		||||
          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 = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username AND `id` = :id");
 | 
			
		||||
            $stmt->execute(array(
 | 
			
		||||
              ':username' => $username,
 | 
			
		||||
              ':id' => $id
 | 
			
		||||
            ));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            while($row = array_shift($rows)) {
 | 
			
		||||
@@ -1576,9 +1579,10 @@ function get_tfa($username = null, $key_id = null) {
 | 
			
		||||
          case "webauthn":
 | 
			
		||||
            $data['name'] = "webauthn";
 | 
			
		||||
            $data['pretty'] = "WebAuthn";
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username");
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username AND `id` = :id");
 | 
			
		||||
            $stmt->execute(array(
 | 
			
		||||
              ':username' => $username,
 | 
			
		||||
              ':id' => $id
 | 
			
		||||
            ));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            while($row = array_shift($rows)) {
 | 
			
		||||
@@ -1609,8 +1613,8 @@ function verify_tfa_login($username, $_data) {
 | 
			
		||||
 | 
			
		||||
  if ($_data['tfa_method'] != 'u2f'){
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
 | 
			
		||||
        WHERE `username` = :username AND `key_id` = :key_id AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username, ':key_id' => $_data['key_id']));
 | 
			
		||||
        WHERE `username` = :username AND `id` = :id AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username, ':id' => $_data['id']));
 | 
			
		||||
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
 | 
			
		||||
    switch ($row["authmech"]) {
 | 
			
		||||
@@ -1627,10 +1631,10 @@ function verify_tfa_login($username, $_data) {
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
 | 
			
		||||
                WHERE `username` = :username
 | 
			
		||||
                AND `authmech` = 'yubi_otp'
 | 
			
		||||
                AND `key_id` = ':key_id'
 | 
			
		||||
                AND `id` = ':id'
 | 
			
		||||
                AND `active`='1'
 | 
			
		||||
                AND `secret` LIKE :modhex");
 | 
			
		||||
            $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id, ':key_id' => $_data['key_id']));
 | 
			
		||||
            $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id, ':id' => $_data['id']));
 | 
			
		||||
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
            $yubico_auth = explode(':', $row['secret']);
 | 
			
		||||
            $yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]);
 | 
			
		||||
@@ -1667,9 +1671,9 @@ function verify_tfa_login($username, $_data) {
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
 | 
			
		||||
                WHERE `username` = :username
 | 
			
		||||
                AND `authmech` = 'totp'
 | 
			
		||||
                AND `key_id` = :key_id
 | 
			
		||||
                AND `id` = :id
 | 
			
		||||
                AND `active`='1'");
 | 
			
		||||
            $stmt->execute(array(':username' => $username, ':key_id' => $_data['key_id']));
 | 
			
		||||
            $stmt->execute(array(':username' => $username, ':id' => $_data['id']));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            foreach ($rows as $row) {
 | 
			
		||||
              if ($tfa->verifyCode($row['secret'], $_data['token']) === true) {
 | 
			
		||||
@@ -1706,13 +1710,20 @@ function verify_tfa_login($username, $_data) {
 | 
			
		||||
            $id = base64_decode($tokenData->id);
 | 
			
		||||
            $challenge = $_SESSION['challenge'];
 | 
			
		||||
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
 | 
			
		||||
            $stmt->execute(array(':tokenId' => $tokenData->id));
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `id` = :id");
 | 
			
		||||
            $stmt->execute(array(':id' => $_data['id']));
 | 
			
		||||
            $process_webauthn = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
 | 
			
		||||
            if (empty($process_webauthn) || empty($process_webauthn['publicKey']) || empty($process_webauthn['username'])) return false;
 | 
			
		||||
            if (empty($process_webauthn)){
 | 
			
		||||
              $_SESSION['return'][] =  array(
 | 
			
		||||
                  'type' => 'danger',
 | 
			
		||||
                  'log' => array(__FUNCTION__, $username, '*'),
 | 
			
		||||
                  'msg' => array('webauthn_verification_failed', 'authenticator not found')
 | 
			
		||||
              );
 | 
			
		||||
              return false;
 | 
			
		||||
            } 
 | 
			
		||||
            
 | 
			
		||||
            if ($process_webauthn['publicKey'] === false) {
 | 
			
		||||
            if (empty($process_webauthn['publicKey']) || $process_webauthn['publicKey'] === false) {
 | 
			
		||||
                $_SESSION['return'][] =  array(
 | 
			
		||||
                    'type' => 'danger',
 | 
			
		||||
                    'log' => array(__FUNCTION__, $username, '*'),
 | 
			
		||||
 
 | 
			
		||||
@@ -194,8 +194,8 @@ function recursiveBase64StrToArrayBuffer(obj) {
 | 
			
		||||
      $(".yubi-authenticator-selection").removeClass("active");
 | 
			
		||||
      $(this).addClass("active");
 | 
			
		||||
 | 
			
		||||
      var key_id = $(this).children('span').first().text();
 | 
			
		||||
      $("#yubi_selected_key_id").val(key_id);
 | 
			
		||||
      var id = $(this).children('input').first().val();
 | 
			
		||||
      $("#yubi_selected_id").val(id);
 | 
			
		||||
 | 
			
		||||
      $("#collapseYubiTFA").collapse('show');
 | 
			
		||||
    });
 | 
			
		||||
@@ -211,8 +211,8 @@ function recursiveBase64StrToArrayBuffer(obj) {
 | 
			
		||||
      $(".totp-authenticator-selection").removeClass("active");
 | 
			
		||||
      $(this).addClass("active");
 | 
			
		||||
      
 | 
			
		||||
      var key_id = $(this).children('span').first().text();
 | 
			
		||||
      $("#totp_selected_key_id").val(key_id);
 | 
			
		||||
      var id = $(this).children('input').first().val();
 | 
			
		||||
      $("#totp_selected_id").val(id);
 | 
			
		||||
 | 
			
		||||
      $("#collapseTotpTFA").collapse('show');
 | 
			
		||||
    });
 | 
			
		||||
@@ -228,8 +228,8 @@ function recursiveBase64StrToArrayBuffer(obj) {
 | 
			
		||||
      $(".webauthn-authenticator-selection").removeClass("active");
 | 
			
		||||
      $(this).addClass("active");
 | 
			
		||||
      
 | 
			
		||||
      var key_id = $(this).children('span').first().text();
 | 
			
		||||
      $("#webauthn_selected_key_id").val(key_id);
 | 
			
		||||
      var id = $(this).children('input').first().val();
 | 
			
		||||
      $("#webauthn_selected_id").val(id);
 | 
			
		||||
      
 | 
			
		||||
      $("#collapseWebAuthnTFA").collapse('show');
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -139,7 +139,7 @@
 | 
			
		||||
    <div class="modal-content">
 | 
			
		||||
      <div class="modal-header">
 | 
			
		||||
        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
 | 
			
		||||
        <h3 class="modal-title">2-Factor-Authentication</h3>
 | 
			
		||||
        <h3 class="modal-title">{{ lang.tfa.tfa }}</h3>
 | 
			
		||||
      </div>
 | 
			
		||||
      
 | 
			
		||||
        <ul class="nav nav-tabs" id="tabContent">
 | 
			
		||||
@@ -173,7 +173,7 @@
 | 
			
		||||
                    <form role="form" method="post" id="webauthn_auth_form">
 | 
			
		||||
                      <legend>
 | 
			
		||||
                          <i class="bi bi-shield-fill-check"></i>
 | 
			
		||||
                          Available Authenticators
 | 
			
		||||
                          Authenticators
 | 
			
		||||
                      </legend>
 | 
			
		||||
                      <div class="list-group">
 | 
			
		||||
                        {% for authenticator in pending_tfa_methods %}
 | 
			
		||||
@@ -181,6 +181,7 @@
 | 
			
		||||
                            <a href="#" class="list-group-item webauthn-authenticator-selection">
 | 
			
		||||
                              <i class="bi bi-key-fill" style="margin-right: 5px"></i>
 | 
			
		||||
                              <span>{{ authenticator["key_id"] }}</span>
 | 
			
		||||
                              <input type="hidden" value="{{ authenticator["id"] }}" /><br/>
 | 
			
		||||
                            </a>
 | 
			
		||||
                          {% endif %}
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
@@ -192,7 +193,7 @@
 | 
			
		||||
                      <input type="hidden" name="token" id="webauthn_auth_data"/>
 | 
			
		||||
                      <input type="hidden" name="tfa_method" value="webauthn">
 | 
			
		||||
                      <input type="hidden" name="verify_tfa_login"/><br/>
 | 
			
		||||
                      <input type="hidden" name="key_id" id="webauthn_selected_key_id" /><br/>
 | 
			
		||||
                      <input type="hidden" name="id" id="webauthn_selected_id" /><br/>
 | 
			
		||||
                    </form>
 | 
			
		||||
                  </div>
 | 
			
		||||
              </div>
 | 
			
		||||
@@ -205,7 +206,7 @@
 | 
			
		||||
                    <form role="form" method="post">
 | 
			
		||||
                      <legend>
 | 
			
		||||
                          <i class="bi bi-shield-fill-check"></i>
 | 
			
		||||
                          Available Authenticators
 | 
			
		||||
                          Authenticators
 | 
			
		||||
                      </legend>
 | 
			
		||||
                      <div class="list-group">
 | 
			
		||||
                        {% for authenticator in pending_tfa_methods %}
 | 
			
		||||
@@ -213,6 +214,7 @@
 | 
			
		||||
                            <a href="#" class="list-group-item yubi-authenticator-selection">
 | 
			
		||||
                              <i class="bi bi-key-fill" style="margin-right: 5px"></i>
 | 
			
		||||
                              <span>{{ authenticator["key_id"] }}</span>
 | 
			
		||||
                              <input type="hidden" value="{{ authenticator["id"] }}" />
 | 
			
		||||
                            </a>
 | 
			
		||||
                          {% endif %}
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
@@ -223,7 +225,7 @@
 | 
			
		||||
                            <span class="input-group-addon" id="yubi-addon"><img alt="Yubicon Icon" src="/img/yubi.ico"></span>
 | 
			
		||||
                            <input type="text" name="token" class="form-control" autocomplete="off" placeholder="Touch Yubikey" aria-describedby="yubi-addon">
 | 
			
		||||
                            <input type="hidden" name="tfa_method" value="yubi_otp">
 | 
			
		||||
                            <input type="hidden" name="key_id" id="yubi_selected_key_id" />
 | 
			
		||||
                            <input type="hidden" name="id" id="yubi_selected_id" />
 | 
			
		||||
                          </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-default" type="submit" name="verify_tfa_login">{{ lang.login.login }}</button>
 | 
			
		||||
@@ -240,7 +242,7 @@
 | 
			
		||||
                    <form role="form" method="post">        
 | 
			
		||||
                      <legend>
 | 
			
		||||
                          <i class="bi bi-shield-fill-check"></i>
 | 
			
		||||
                          Available Authenticators
 | 
			
		||||
                          Authenticators
 | 
			
		||||
                      </legend>
 | 
			
		||||
                      <div class="list-group">
 | 
			
		||||
                        {% for authenticator in pending_tfa_methods %}
 | 
			
		||||
@@ -248,6 +250,7 @@
 | 
			
		||||
                            <a href="#" class="list-group-item totp-authenticator-selection">
 | 
			
		||||
                              <i class="bi bi-key-fill" style="margin-right: 5px"></i>
 | 
			
		||||
                              <span>{{ authenticator["key_id"] }}</span>
 | 
			
		||||
                              <input type="hidden" value="{{ authenticator["id"] }}" />
 | 
			
		||||
                            </a>
 | 
			
		||||
                          {% endif %}
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
@@ -258,7 +261,7 @@
 | 
			
		||||
                            <span class="input-group-addon" id="tfa-addon"><i class="bi bi-shield-lock-fill"></i></span>
 | 
			
		||||
                            <input type="number" min="000000" max="999999" name="token" class="form-control" placeholder="123456" autocomplete="one-time-code" aria-describedby="tfa-addon">
 | 
			
		||||
                            <input type="hidden" name="tfa_method" value="totp">
 | 
			
		||||
                            <input type="hidden" name="key_id" id="totp_selected_key_id" /><br/>
 | 
			
		||||
                            <input type="hidden" name="id" id="totp_selected_id" /><br/>
 | 
			
		||||
                          </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" type="submit" name="verify_tfa_login">{{ lang.login.login }}</button>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user