| @@ -269,6 +269,7 @@ code { | ||||
|   padding: 10px; | ||||
|   background: #fbfbfb; | ||||
|   border: 1px solid #ededed; | ||||
|   min-height: 110px; | ||||
| } | ||||
|  | ||||
| .tag-box { | ||||
|   | ||||
| @@ -937,22 +937,33 @@ function check_login($user, $pass, $app_passwd_data = false) { | ||||
|   } | ||||
|   foreach ($rows as $row) { | ||||
|     // verify password | ||||
|     if (verify_hash($row['password'], $pass) !== false) { | ||||
|       // 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'] = "user"; | ||||
|         $_SESSION['pending_tfa_methods'] = $authenticators['additional']; | ||||
|         unset($_SESSION['ldelay']); | ||||
|         $_SESSION['return'][] =  array( | ||||
|           'type' => 'success', | ||||
|           'log' => array(__FUNCTION__, $user, '*'), | ||||
|           'msg' => array('logged_in_as', $user) | ||||
|         ); | ||||
|         return "pending"; | ||||
|       } else { | ||||
|         if ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) { | ||||
|     if ($app_passwd_data['eas'] !== true && $app_passwd_data['dav'] !== true){ | ||||
|       if (verify_hash($row['password'], $pass) !== false) { | ||||
|         // 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'] = "user"; | ||||
|           $_SESSION['pending_tfa_methods'] = $authenticators['additional']; | ||||
|           unset($_SESSION['ldelay']); | ||||
|           $_SESSION['return'][] =  array( | ||||
|             'type' => 'success', | ||||
|             'log' => array(__FUNCTION__, $user, '*'), | ||||
|             'msg' => array('logged_in_as', $user) | ||||
|           ); | ||||
|           return "pending"; | ||||
|         } else { | ||||
|           // Reactivate TFA if it was set to "deactivate TFA for next login" | ||||
|           $stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user"); | ||||
|           $stmt->execute(array(':user' => $user)); | ||||
|  | ||||
|           unset($_SESSION['ldelay']); | ||||
|           return "user"; | ||||
|         } | ||||
|       } | ||||
|     } elseif ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) { | ||||
|       if (array_key_exists("app_passwd_id", $row)){ | ||||
|         if (verify_hash($row['password'], $pass) !== false) { | ||||
|           $service = ($app_passwd_data['eas'] === true) ? 'EAS' : 'DAV'; | ||||
|           $stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES (:service, :app_id, :username, :remote_addr)"); | ||||
|           $stmt->execute(array( | ||||
| @@ -961,13 +972,10 @@ function check_login($user, $pass, $app_passwd_data = false) { | ||||
|             ':username' => $user, | ||||
|             ':remote_addr' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']) | ||||
|           )); | ||||
|         } | ||||
|  | ||||
|         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"); | ||||
|         $stmt->execute(array(':user' => $user)); | ||||
|         return "user"; | ||||
|           unset($_SESSION['ldelay']); | ||||
|           return "user"; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -1626,12 +1634,8 @@ function verify_tfa_login($username, $_data) { | ||||
|   global $WebAuthn; | ||||
|  | ||||
|   if ($_data['tfa_method'] != 'u2f'){ | ||||
|     $stmt = $pdo->prepare("SELECT `authmech` FROM `tfa` | ||||
|         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"]) { | ||||
|     switch ($_data["tfa_method"]) { | ||||
|         case "yubi_otp": | ||||
|             if (!ctype_alnum($_data['token']) || strlen($_data['token']) != 44) { | ||||
|                 $_SESSION['return'][] =  array( | ||||
| @@ -1645,10 +1649,9 @@ function verify_tfa_login($username, $_data) { | ||||
|             $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa` | ||||
|                 WHERE `username` = :username | ||||
|                 AND `authmech` = 'yubi_otp' | ||||
|                 AND `id` = :id | ||||
|                 AND `active` = '1' | ||||
|                 AND `secret` LIKE :modhex"); | ||||
|             $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id, ':id' => $_data['id'])); | ||||
|             $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id)); | ||||
|             $row = $stmt->fetch(PDO::FETCH_ASSOC); | ||||
|             $yubico_auth = explode(':', $row['secret']); | ||||
|             $yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]); | ||||
|   | ||||
| @@ -182,30 +182,19 @@ function recursiveBase64StrToArrayBuffer(obj) { | ||||
|       keyboard: false | ||||
|     }); | ||||
|  | ||||
|     // validate Yubi OTP tfa | ||||
|     $("#pending_tfa_tab_yubi_otp").click(function(){ | ||||
|       $(".totp-authenticator-selection").removeClass("active"); | ||||
|       $(".webauthn-authenticator-selection").removeClass("active"); | ||||
|  | ||||
|       $("#collapseTotpTFA").collapse('hide'); | ||||
|       $("#collapseWebAuthnTFA").collapse('hide'); | ||||
|     }); | ||||
|     $(".yubi-authenticator-selection").click(function(){ | ||||
|       $(".yubi-authenticator-selection").removeClass("active"); | ||||
|       $(this).addClass("active"); | ||||
|  | ||||
|       var id = $(this).children('input').first().val(); | ||||
|       $("#yubi_selected_id").val(id); | ||||
|  | ||||
|       $("#collapseYubiTFA").collapse('show'); | ||||
|     }); | ||||
|     // validate Time based OTP tfa | ||||
|     $("#pending_tfa_tab_totp").click(function(){ | ||||
|       $(".yubi-authenticator-selection").removeClass("active"); | ||||
|       $(".webauthn-authenticator-selection").removeClass("active"); | ||||
|  | ||||
|       $("#collapseYubiTFA").collapse('hide'); | ||||
|       $("#collapseWebAuthnTFA").collapse('hide'); | ||||
|  | ||||
|       // select default if only one authenticator exists | ||||
|       if ($('.totp-authenticator-selection').length == 1){ | ||||
|         $('.totp-authenticator-selection').addClass("active"); | ||||
|         var id = $('.totp-authenticator-selection').children('input').first().val(); | ||||
|         $("#totp_selected_id").val(id); | ||||
|         $("#collapseTotpTFA").collapse('show'); | ||||
|       } | ||||
|     }); | ||||
|     $(".totp-authenticator-selection").click(function(){ | ||||
|       $(".totp-authenticator-selection").removeClass("active"); | ||||
| @@ -216,13 +205,37 @@ function recursiveBase64StrToArrayBuffer(obj) { | ||||
|  | ||||
|       $("#collapseTotpTFA").collapse('show'); | ||||
|     }); | ||||
|     if ($('.totp-authenticator-selection').length == 1 && | ||||
|         $('#pending_tfa_tab_yubi_otp').length == 0 && | ||||
|         $('.webauthn-authenticator-selection').length == 0){ | ||||
|        | ||||
|       // select default if only one authenticator exists | ||||
|       $('.totp-authenticator-selection').addClass("active"); | ||||
|  | ||||
|       var id = $('.totp-authenticator-selection').children('input').first().val(); | ||||
|       $("#totp_selected_id").val(id); | ||||
|  | ||||
|       $("#collapseTotpTFA").collapse('show'); | ||||
|       setTimeout(function() { $("#collapseTotpTFA").find('input[name="token"]').focus(); }, 1000); | ||||
|     } | ||||
|     $('#pending_tfa_tab_totp').on('shown.bs.tab', function() { | ||||
|       // autofocus | ||||
|       setTimeout(function() { $("#collapseTotpTFA").find('input[name="token"]').focus(); }, 200); | ||||
|     });     | ||||
|     // validate Yubi OTP tfa | ||||
|     if ($('.webauthn-authenticator-selection').length == 0){ | ||||
|       // autofocus | ||||
|       setTimeout(function() { $("#collapseYubiTFA").find('input[name="token"]').focus(); }, 1000); | ||||
|     } | ||||
|     $('#pending_tfa_tab_yubi_otp').on('shown.bs.tab', function() { | ||||
|       // autofocus | ||||
|       $("#collapseYubiTFA").find('input[name="token"]').focus(); | ||||
|     }); | ||||
|     // validate WebAuthn tfa | ||||
|     $("#pending_tfa_tab_webauthn").click(function(){ | ||||
|       $(".totp-authenticator-selection").removeClass("active"); | ||||
|       $(".yubi-authenticator-selection").removeClass("active"); | ||||
|  | ||||
|       $("#collapseTotpTFA").collapse('hide'); | ||||
|       $("#collapseYubiTFA").collapse('hide'); | ||||
|     }); | ||||
|     $(".webauthn-authenticator-selection").click(function(){ | ||||
|       $(".webauthn-authenticator-selection").removeClass("active"); | ||||
|   | ||||
| @@ -206,20 +206,9 @@ | ||||
|                     <form role="form" method="post"> | ||||
|                       <legend> | ||||
|                           <i class="bi bi-shield-fill-check"></i> | ||||
|                           Authenticators | ||||
|                           Authenticate | ||||
|                       </legend> | ||||
|                       <div class="list-group"> | ||||
|                         {% for authenticator in pending_tfa_methods %} | ||||
|                           {% if authenticator["authmech"] == "yubi_otp" %} | ||||
|                             <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 %} | ||||
|                       </div> | ||||
|                       <div class="collapse pending-tfa-collapse" id="collapseYubiTFA"> | ||||
|                       <div class="collapse in pending-tfa-collapse" id="collapseYubiTFA"> | ||||
|                         <div class="form-group"> | ||||
|                           <div class="input-group"> | ||||
|                             <span class="input-group-addon" id="yubi-addon"><img alt="Yubicon Icon" src="/img/yubi.ico"></span> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user