security: enforce global 2FA toggles on login challenges and controller endpoints
This commit is contained in:
@@ -35,8 +35,25 @@ class AuthenticatedSessionController extends Controller
|
|||||||
|
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
||||||
// If user has 2FA enabled, redirect to challenge screen
|
// Check global 2FA toggles
|
||||||
if ($user->two_factor_confirmed_at && $user->two_factor_secret) {
|
$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_user_id', $user->id);
|
||||||
$request->session()->put('two_factor_type', 'totp');
|
$request->session()->put('two_factor_type', 'totp');
|
||||||
Auth::guard('web')->logout();
|
Auth::guard('web')->logout();
|
||||||
@@ -45,8 +62,8 @@ class AuthenticatedSessionController extends Controller
|
|||||||
return redirect()->route('two-factor.challenge');
|
return redirect()->route('two-factor.challenge');
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user has Email 2FA enabled, redirect to email challenge
|
// If user has Email 2FA enabled, and it's globally allowed, redirect to email challenge
|
||||||
if ($user->email_2fa_enabled) {
|
if ($emailAllowed && $user->email_2fa_enabled) {
|
||||||
$code = str_pad(mt_rand(100000, 999999), 6, '0', STR_PAD_LEFT);
|
$code = str_pad(mt_rand(100000, 999999), 6, '0', STR_PAD_LEFT);
|
||||||
$user->update([
|
$user->update([
|
||||||
'email_2fa_code' => $code,
|
'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.
|
* Confirm & enable 2FA.
|
||||||
*/
|
*/
|
||||||
public function enable(Request $request)
|
public function enable(Request $request)
|
||||||
{
|
{
|
||||||
|
if (!$this->isTotpAllowed()) {
|
||||||
|
abort(403, 'Google Authenticator (TOTP) is globally disabled by the administrator.');
|
||||||
|
}
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'code' => 'required|string',
|
'code' => 'required|string',
|
||||||
]);
|
]);
|
||||||
@@ -111,6 +145,10 @@ class TwoFactorController extends Controller
|
|||||||
'enabled' => 'required|boolean',
|
'enabled' => 'required|boolean',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if ($request->enabled && !$this->isEmailAllowed()) {
|
||||||
|
abort(403, 'Email Two-Factor Authentication is globally disabled by the administrator.');
|
||||||
|
}
|
||||||
|
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
if ($request->enabled) {
|
if ($request->enabled) {
|
||||||
// Live-verify SMTP configuration by sending a test validation email
|
// Live-verify SMTP configuration by sending a test validation email
|
||||||
|
|||||||
Reference in New Issue
Block a user