security: enforce global 2FA toggles on login challenges and controller endpoints

This commit is contained in:
2026-05-21 22:06:26 +07:00
parent 1a30122c3d
commit bf42ca956d
2 changed files with 59 additions and 4 deletions
@@ -35,8 +35,25 @@ class AuthenticatedSessionController extends Controller
$user = Auth::user();
// If user has 2FA enabled, redirect to challenge screen
if ($user->two_factor_confirmed_at && $user->two_factor_secret) {
// Check global 2FA toggles
$totpAllowed = true;
$emailAllowed = true;
try {
$settings = \Illuminate\Support\Facades\Cache::rememberForever('system_settings', function () {
return \App\Models\Setting::all()->pluck('value', 'key')->toArray();
});
if (isset($settings['two_factor_totp_enabled'])) {
$totpAllowed = $settings['two_factor_totp_enabled'] === '1' || $settings['two_factor_totp_enabled'] === true;
}
if (isset($settings['two_factor_email_enabled'])) {
$emailAllowed = $settings['two_factor_email_enabled'] === '1' || $settings['two_factor_email_enabled'] === true;
}
} catch (\Exception $e) {
// DB not ready or migrated
}
// If user has 2FA enabled, and it's globally allowed, redirect to challenge screen
if ($totpAllowed && $user->two_factor_confirmed_at && $user->two_factor_secret) {
$request->session()->put('two_factor_user_id', $user->id);
$request->session()->put('two_factor_type', 'totp');
Auth::guard('web')->logout();
@@ -45,8 +62,8 @@ class AuthenticatedSessionController extends Controller
return redirect()->route('two-factor.challenge');
}
// If user has Email 2FA enabled, redirect to email challenge
if ($user->email_2fa_enabled) {
// If user has Email 2FA enabled, and it's globally allowed, redirect to email challenge
if ($emailAllowed && $user->email_2fa_enabled) {
$code = str_pad(mt_rand(100000, 999999), 6, '0', STR_PAD_LEFT);
$user->update([
'email_2fa_code' => $code,
@@ -56,11 +56,45 @@ class TwoFactorController extends Controller
]);
}
private function isTotpAllowed(): bool
{
try {
$settings = \Illuminate\Support\Facades\Cache::rememberForever('system_settings', function () {
return \App\Models\Setting::all()->pluck('value', 'key')->toArray();
});
if (isset($settings['two_factor_totp_enabled'])) {
return $settings['two_factor_totp_enabled'] === '1' || $settings['two_factor_totp_enabled'] === true;
}
} catch (\Exception $e) {
// DB not ready or migrated
}
return true;
}
private function isEmailAllowed(): bool
{
try {
$settings = \Illuminate\Support\Facades\Cache::rememberForever('system_settings', function () {
return \App\Models\Setting::all()->pluck('value', 'key')->toArray();
});
if (isset($settings['two_factor_email_enabled'])) {
return $settings['two_factor_email_enabled'] === '1' || $settings['two_factor_email_enabled'] === true;
}
} catch (\Exception $e) {
// DB not ready or migrated
}
return true;
}
/**
* Confirm & enable 2FA.
*/
public function enable(Request $request)
{
if (!$this->isTotpAllowed()) {
abort(403, 'Google Authenticator (TOTP) is globally disabled by the administrator.');
}
$request->validate([
'code' => 'required|string',
]);
@@ -111,6 +145,10 @@ class TwoFactorController extends Controller
'enabled' => 'required|boolean',
]);
if ($request->enabled && !$this->isEmailAllowed()) {
abort(403, 'Email Two-Factor Authentication is globally disabled by the administrator.');
}
$user = auth()->user();
if ($request->enabled) {
// Live-verify SMTP configuration by sending a test validation email