Skip to content

Commit 5fc57eb

Browse files
feat: Harden login captcha gate by replacing request-body counter with server-side session counter (UserController::postLogin)
1 parent 9dda289 commit 5fc57eb

2 files changed

Lines changed: 14 additions & 10 deletions

File tree

app/Http/Controllers/UserController.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ public function postLogin()
396396
{
397397
$max_login_attempts_2_show_captcha = $this->server_configuration_service->getConfigValue("MaxFailed.LoginAttempts.2ShowCaptcha");
398398
$max_login_failed_attempts = intval($this->server_configuration_service->getConfigValue("MaxFailed.Login.Attempts"));
399-
$login_attempts = 0;
400-
$username = '';
399+
$login_attempts = (int) Session::get('login_attempts', 0);
400+
$username = '';
401401
$user = null;
402402

403403
try
@@ -411,7 +411,6 @@ public function postLogin()
411411
if (isset($data['password']))
412412
$data['password'] = trim($data['password']);
413413

414-
$login_attempts = intval(Request::input('login_attempts'));
415414
// Build the validation constraint set.
416415
$rules = [
417416
'username' => 'required|email',
@@ -436,7 +435,10 @@ public function postLogin()
436435
$connection = $data['connection'] ?? null;
437436

438437
try {
438+
$user = $this->auth_service->getUserByUsername($username);
439439
if ($flow == "password" && $this->auth_service->login($username, $password, $remember)) {
440+
$user->setLoginFailedAttempt(0);
441+
Session::forget('login_attempts');
440442
return $this->login_strategy->postLogin();
441443
}
442444

@@ -467,16 +469,20 @@ public function postLogin()
467469
}
468470

469471
$otpClaim = OAuth2OTP::fromParams($username, $connection, $password);
472+
470473
$this->auth_service->loginWithOTP($otpClaim, $client);
474+
$user?->setLoginFailedAttempt(0);
475+
Session::forget('login_attempts');
471476
return $this->login_strategy->postLogin();
472477
}
473478
} catch (AuthenticationException $ex) {
474479
// failed login attempt...
475480

476-
$user = $this->auth_service->getUserByUsername($username);
477-
if (!is_null($user)) {
478-
$login_attempts = $user->getLoginFailedAttempt();
479-
}
481+
$login_attempts = $user?->updateLoginFailedAttempt();
482+
Session::put('login_attempts', $login_attempts);
483+
484+
// User.loginFailedAttempt drives account lockout (persisted by auth_service).
485+
// $login_attempts intentionally NOT overwritten; session counter drives captcha gate.
480486

481487
return $this->login_strategy->errorLogin
482488
(
@@ -505,7 +511,7 @@ public function postLogin()
505511
'validator' => $validator,
506512
];
507513

508-
if (is_null($user) && isset($data['username'])) {
514+
if (is_null($user) && !empty($data['username'])) {
509515
$user = $this->auth_service->getUserByUsername($data['username']);
510516
}
511517

resources/js/login/login.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ const PasswordInputForm = ({
185185
<input type="hidden" value={userNameValue} id="username" name="username"/>
186186
<input type="hidden" value={csrfToken} id="_token" name="_token"/>
187187
<input type="hidden" value="password" id="flow" name="flow"/>
188-
<input type="hidden" value={loginAttempts} id="login_attempts" name="login_attempts"/>
189188
{shouldShowCaptcha() && captchaPublicKey &&
190189
<Turnstile
191190
className={styles.turnstile}
@@ -271,7 +270,6 @@ const OTPInputForm = ({
271270
<input type="hidden" value="otp" id="flow" name="flow"/>
272271
<input type="hidden" value={otpCode} id="password" name="password"/>
273272
<input type="hidden" value="email" id="connection" name="connection"/>
274-
<input type="hidden" value={loginAttempts} id="login_attempts" name="login_attempts"/>
275273
{shouldShowCaptcha() && captchaPublicKey &&
276274
<Turnstile
277275
className={styles.turnstile}

0 commit comments

Comments
 (0)