• Модуль: main
  • Путь к файлу: ~/bitrix/modules/main/classes/general/user.php
  • Класс: CAllUser
  • Вызов: CAllUser::LoginInternal
static function LoginInternal(&$arParams, &$result_message = true, $context = null)
{
	global $DB, $APPLICATION;

	$user_id = 0;
	$message = GetMessage("WRONG_LOGIN");
	$errorType = "LOGIN";

	$strSql =
		"SELECT U.ID, U.LOGIN, U.ACTIVE, U.BLOCKED, U.PASSWORD, U.PASSWORD_EXPIRED, U.LOGIN_ATTEMPTS, U.CONFIRM_CODE, U.EMAIL " .
		"FROM b_user U  " .
		"WHERE U.LOGIN='" . $DB->ForSQL($arParams["LOGIN"]) . "' ";

	if (isset($arParams["EXTERNAL_AUTH_ID"]) && $arParams["EXTERNAL_AUTH_ID"] != '')
	{
		//external user
		$strSql .= " AND EXTERNAL_AUTH_ID='" . $DB->ForSql($arParams["EXTERNAL_AUTH_ID"]) . "'";
	}
	else
	{
		//internal user (by default)
		$strSql .= " AND (EXTERNAL_AUTH_ID IS NULL OR EXTERNAL_AUTH_ID='') ";
	}

	$result = $DB->Query($strSql);

	if (($arUser = $result->Fetch()))
	{
		$passwordCorrect = false;
		$policy = null;
		$applicationId = null;
		$original = isset($arParams["PASSWORD_ORIGINAL"]) && $arParams["PASSWORD_ORIGINAL"] === 'Y';
		$loginAttempts = intval($arUser["LOGIN_ATTEMPTS"]) + 1;

		if ($arUser["BLOCKED"] != 'Y')
		{
			$policy = static::getPolicy($arUser["ID"]);

			//show captcha after a serial of incorrect login attempts
			$correctCaptcha = true;
			$policyLoginAttempts = (int)$policy->getLoginAttempts();
			if ($policyLoginAttempts > 0 && $loginAttempts > $policyLoginAttempts)
			{
				$APPLICATION->SetNeedCAPTHA(true);
				if (!$APPLICATION->CaptchaCheckCode($_REQUEST["captcha_word"] ?? '', $_REQUEST["captcha_sid"] ?? ''))
				{
					$correctCaptcha = false;
				}
			}

			if ($correctCaptcha)
			{
				$passwordCorrect = Password::equals($arUser["PASSWORD"], $arParams["PASSWORD"], $original);

				if (!$passwordCorrect)
				{
					if (isset($arParams["OTP"]) && $arParams["OTP"] != '' && $original)
					{
						// maybe we have OTP added to the password
						$passwordWithoutOtp = mb_substr($arParams["PASSWORD"], 0, -6);
						$passwordCorrect = Password::equals($arUser["PASSWORD"], $passwordWithoutOtp);
					}
				}
				else
				{
					//this password has no added otp for sure
					$arParams["OTP"] = '';
				}

				if (!$passwordCorrect)
				{
					//let's try to find application password
					if (($appPassword = ApplicationPasswordTable::findPassword($arUser["ID"], $arParams["PASSWORD"], $original)) !== false)
					{
						$passwordCorrect = true;
						$applicationId = $appPassword["APPLICATION_ID"];

						if ($context instanceof AuthenticationContext)
						{
							$context
								->setApplicationId($applicationId)
								->setApplicationPasswordId($appPassword["ID"])
							;
						}
					}
				}
			}

			if (!$passwordCorrect)
			{
				//block the user after numerous incorrect login attempts
				$policyBlockAttempts = (int)$policy->getBlockLoginAttempts();
				$policyBlockTime = (int)$policy->getBlockTime();
				if ($policyBlockAttempts > 0 && $policyBlockTime > 0 && $loginAttempts >= $policyBlockAttempts)
				{
					if ($arUser["ACTIVE"] == 'Y')
					{
						static::blockUser($arUser["ID"], $policyBlockTime, $loginAttempts);
					}
				}
			}
		}

		if ($passwordCorrect)
		{
			//applied only to "human" passwords
			if ($applicationId === null)
			{
				//only for original passwords
				if ($original)
				{
					//update the old password hash to the new one with a salt
					if (Password::needRehash($arUser["PASSWORD"]))
					{
						$newPassword = Password::hash($arParams["PASSWORD"]);
						$DB->Query("UPDATE b_user SET PASSWORD='" . $DB->ForSQL($newPassword) . "', TIMESTAMP_X = TIMESTAMP_X WHERE ID = " . intval($arUser["ID"]));
					}

					//update digest hash for http digest authorization
					if (Option::get('main', 'use_digest_auth', 'N') == 'Y')
					{
						static::UpdateDigest($arUser["ID"], $arParams["PASSWORD"]);
					}
				}

				$passwordExpired = false;
				if ($arUser['PASSWORD_EXPIRED'] == 'Y')
				{
					//require to change the password right now
					$passwordExpired = true;
				}
				if (!$passwordExpired && $original && $policy->getPasswordCheckPolicy())
				{
					$passwordErrors = static::CheckPasswordAgainstPolicy($arParams["PASSWORD"], $policy->getValues());
					if (!empty($passwordErrors))
					{
						//require to change the password because it doesn't match the group policy
						$passwordExpired = true;
					}
				}
				if (!$passwordExpired)
				{
					$policyChangeDays = (int)$policy->getPasswordChangeDays();
					if ($policyChangeDays > 0)
					{
						//require to change the password after N days
						if (UserPasswordTable::passwordExpired($arUser["ID"], $policyChangeDays))
						{
							$passwordExpired = true;
						}
					}
				}

				if ($passwordExpired)
				{
					$passwordCorrect = false;
					$message = GetMessage("MAIN_LOGIN_CHANGE_PASSWORD");
					$errorType = "CHANGE_PASSWORD";
				}
			}

			if ($passwordCorrect)
			{
				if ($arUser["ACTIVE"] == 'Y')
				{
					//success
					$user_id = $arUser["ID"];
				}
				else
				{
					//something wrong with the inactive user
					if ($arUser["CONFIRM_CODE"] != '')
					{
						//unconfirmed email registration
						$message = GetMessage("MAIN_LOGIN_EMAIL_CONFIRM", ["#EMAIL#" => $arUser["EMAIL"]]);
					}
					else
					{
						//user deactivated
						$message = GetMessage("LOGIN_BLOCK");

						//or possibly unconfirmed phone registration
						if (Option::get('main', 'new_user_phone_auth', 'N') == 'Y')
						{
							$row = MainUserPhoneAuthTable::getRowById($arUser["ID"]);
							if ($row && $row["CONFIRMED"] == 'N')
							{
								$message = GetMessage("main_login_need_phone_confirmation", ["#PHONE#" => $row["PHONE_NUMBER"]]);
							}
						}
					}
				}
			}
		}
		else
		{
			//incorrect password
			$DB->Query("UPDATE b_user SET LOGIN_ATTEMPTS = " . $loginAttempts . ", TIMESTAMP_X = TIMESTAMP_X WHERE ID = " . intval($arUser["ID"]));
		}
	}

	if ($user_id == 0)
	{
		$APPLICATION->ThrowException($message);
		$result_message = ["MESSAGE" => $message . "
", "TYPE" => "ERROR", "ERROR_TYPE" => $errorType]; } return $user_id; }