Alternative implementation of passing totp to the legacy Minecraft authorization protocol to not break the yggdrasil's protocol [deploy]

This commit is contained in:
ErickSkrauch
2021-03-08 22:21:10 +01:00
parent 9a3534ea2b
commit 7a80c44cab
3 changed files with 65 additions and 26 deletions

View File

@@ -29,11 +29,6 @@ class AuthenticationForm extends ApiForm {
*/
public $password;
/**
* @var string
*/
public $totp;
/**
* @var string
*/
@@ -47,7 +42,6 @@ class AuthenticationForm extends ApiForm {
public function rules(): array {
return [
[['username', 'password', 'clientToken'], RequiredValidator::class],
[['totp'], 'string'],
[['clientToken'], ClientTokenValidator::class],
[['requestUser'], 'boolean'],
];
@@ -68,17 +62,31 @@ class AuthenticationForm extends ApiForm {
// so we keep such behavior
$attribute = strpos($this->username, '@') === false ? 'nickname' : 'email';
$password = $this->password;
$totp = null;
if (preg_match('/.{8,}:(\d{6})$/', $password, $matches) === 1) {
$totp = $matches[1];
$password = mb_substr($password, 0, -7); // :123456 - 7 chars
}
login:
$loginForm = new LoginForm();
$loginForm->login = $this->username;
$loginForm->password = $this->password;
$loginForm->totp = $this->totp;
if (!$loginForm->validate() || $loginForm->getAccount()->status === Account::STATUS_DELETED) {
$errors = $loginForm->getFirstErrors();
if (isset($errors['totp'])) {
Authserver::error("User with login = '{$this->username}' protected by two factor auth.");
throw new ForbiddenOperationException('Account protected with two factor auth.');
}
$loginForm->password = $password;
$loginForm->totp = $totp;
$isValid = $loginForm->validate();
// Handle case when user's password matches the template for totp via password
if (!$isValid && $totp !== null && $loginForm->getFirstError('password') === E::PASSWORD_INCORRECT) {
$password = "{$password}:{$totp}";
$totp = null;
goto login;
}
if (!$isValid || $loginForm->getAccount()->status === Account::STATUS_DELETED) {
$errors = $loginForm->getFirstErrors();
if (isset($errors['login'])) {
if ($errors['login'] === E::ACCOUNT_BANNED) {
Authserver::error("User with login = '{$this->username}' is banned");
@@ -88,9 +96,14 @@ class AuthenticationForm extends ApiForm {
Authserver::error("Cannot find user by login = '{$this->username}'");
} elseif (isset($errors['password'])) {
Authserver::error("User with login = '{$this->username}' passed wrong password.");
}
} elseif (isset($errors['totp'])) {
if ($errors['totp'] === E::TOTP_REQUIRED) {
Authserver::error("User with login = '{$this->username}' protected by two factor auth.");
throw new ForbiddenOperationException('Account protected with two factor auth.');
}
// TODO: эта логика дублируется с логикой в SignoutForm
Authserver::error("User with login = '{$this->username}' passed wrong totp token");
}
throw new ForbiddenOperationException("Invalid credentials. Invalid {$attribute} or password.");
}