function getRecoveryCodes($userId) { $codes = RecoveryCodesTable::getList(array('select' => array('CODE'), 'filter' => array('=USER_ID' => $userId, '=USED' => 'N'))); $normalizedCodes = array(); while ($code = $codes->fetch()) { $normalizedCodes[] = $code['CODE']; } return $normalizedCodes; }
?> </div> <?php echo EndNote(); ?> </div> </td> </tr> <?php } else { ?> <?php if (Otp::isRecoveryCodesEnabled()) { ?> <?php $codes = \Bitrix\Security\Mfa\RecoveryCodesTable::getList(array('select' => array('ID'), 'filter' => array('=USER_ID' => $ID), 'limit' => 1))->fetch(); if (!$codes) { ?> <tr data-role="otp-recovery-codes-warning"> <td colspan="2"> <?php CAdminMessage::ShowMessage(array("MESSAGE" => GetMessage('SEC_OTP_WARNING_RECOVERY_CODES'), "TYPE" => 'ERROR', "HTML" => true)); ?> </td> </tr> <?php } ?> <?php } ?>
protected function regenerateRecoveryCodes() { CUserOptions::SetOption('security', 'recovery_codes_generated', time()); RecoveryCodesTable::regenerateCodes($this->arParams['USER_ID']); return $this->getRecoveryCodes(false, false); }
function regenerateRecoveryCodes($userId) { if (!Otp::getByUser($userId)->isActivated()) { ShowError('OTP inactive'); } CUserOptions::SetOption('security', 'recovery_codes_generated', time()); RecoveryCodesTable::regenerateCodes($userId); return getRecoveryCodes($userId, false); }
/** * Most complex method, can check everything:-) * ToDo: describe after refactoring * * @param array $params * @throws ArgumentTypeException * @return bool */ public static function verifyUser(array $params) { /** @global \CMain $APPLICATION */ global $APPLICATION; if (!static::isOtpEnabled()) { // OTP disabled in settings return true; } $isSuccess = false; // ToDo: review and refactoring needed $otp = static::getByUser($params['USER_ID']); if (!$otp->isActivated()) { // User does not use OTP $isSuccess = true; if (static::isMandatoryUsing() && !$otp->canSkipMandatory()) { // Grace full period ends. We must reject authorization and defer reject reason if (!$otp->isDbRecordExists() && static::getSkipMandatoryDays()) { // If mandatory enabled and user never use OTP - let's deffer initialization $otp->defer(static::getSkipMandatoryDays()); // We forgive the user for the first time static::setDeferredParams(null); return true; } // Save a flag which indicates that a OTP is required, but user doesn't use it :-( $params[static::REJECTED_KEY] = static::REJECT_BY_MANDATORY; static::setDeferredParams($params); return false; } } if (!$isSuccess) { // User skip OTP on this browser by cookie $isSuccess = $otp->canSkipByCookie(); } if (!$isSuccess) { $isCaptchaChecked = !$otp->isAttemptsReached() || $APPLICATION->captchaCheckCode($params['CAPTCHA_WORD'], $params['CAPTCHA_SID']); $isRememberNeeded = $params['OTP_REMEMBER'] && Option::get('security', 'otp_allow_remember') === 'Y'; if (!$isCaptchaChecked && !$_SESSION['BX_LOGIN_NEED_CAPTCHA']) { // Backward compatibility with old login page $_SESSION['BX_LOGIN_NEED_CAPTCHA'] = true; } $isOtpPassword = (bool) preg_match('/^\\d{6}$/D', $params['OTP']); $isRecoveryCode = static::isRecoveryCodesEnabled() && (bool) preg_match(RecoveryCodesTable::CODE_PATTERN, $params['OTP']); if ($isCaptchaChecked && ($isOtpPassword || $isRecoveryCode)) { if ($isOtpPassword) { $isSuccess = $otp->verify($params['OTP'], true); } elseif ($isRecoveryCode) { $isSuccess = RecoveryCodesTable::useCode($otp->getUserId(), $params['OTP']); } else { $isSuccess = false; } if (!$isSuccess) { $otp->setAttempts($otp->getAttempts() + 1)->save(); } else { if ($otp->getAttempts() > 0) { // Clear OTP input attempts $otp->setAttempts(0)->save(); } if ($isRememberNeeded && $isOtpPassword) { // If user provide otp password (not recovery codes) // Sets cookie for bypass OTP checking $otp->setSkipCookie(); } } } } if ($isSuccess) { static::setDeferredParams(null); } else { // Save a flag which indicates that a form for OTP is required $params[static::REJECTED_KEY] = static::REJECT_BY_CODE; static::setDeferredParams($params); } return $isSuccess; }
/** * Clear recovery codes after delete user * * @param Entity\Event $event Our event. * @return void * @throws \Bitrix\Main\ArgumentTypeException */ public static function onAfterDelete(Entity\Event $event) { $primary = $event->getParameter('primary'); RecoveryCodesTable::clearByUser($primary['USER_ID']); }