mirror of
https://github.com/coollabsio/coolify.git
synced 2026-10-29 18:12:53 +08:00
Add OauthLoginException, which carries a translation key for the message shown on the login page. The exception message only goes to the log. OauthLoginService now throws it for an unverified email, an account that is already linked to another identity, and disabled registration. OauthController shows the matching message for each case. Other HttpExceptions fall back to a generic OAuth failure message. The email verification check now runs before the linked-identity check, so an unverified email cannot reveal that an account is already linked. Add translations for the new auth.failed.oauth* keys in all locales and cover the new error messages with feature tests.
76 lines
2.7 KiB
PHP
76 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Exceptions\OauthLoginException;
|
|
use App\Models\OauthSetting;
|
|
use App\Services\Auth\OauthLoginService;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
|
|
|
class OauthController extends Controller
|
|
{
|
|
public function redirect(string $provider)
|
|
{
|
|
$oauthSetting = $this->enabledProvider($provider);
|
|
$socialiteProvider = get_socialite_provider($oauthSetting->provider);
|
|
|
|
return $socialiteProvider->redirect();
|
|
}
|
|
|
|
public function callback(string $provider, OauthLoginService $oauthLoginService)
|
|
{
|
|
try {
|
|
$oauthSetting = $this->enabledProvider($provider);
|
|
$oauthUser = get_socialite_provider($oauthSetting->provider)->user();
|
|
$user = $oauthLoginService->login($oauthSetting->provider, $oauthUser, $oauthSetting);
|
|
|
|
if ($oauthLoginService->requiresTwoFactorChallenge($user)) {
|
|
return redirect()->route('two-factor.login');
|
|
}
|
|
|
|
return redirect('/');
|
|
} catch (\Exception $e) {
|
|
$this->logCallbackFailure($provider, $e);
|
|
|
|
$errorCode = match (true) {
|
|
$e instanceof OauthLoginException => $e->userMessageKey,
|
|
$e instanceof HttpException => 'auth.failed.oauth',
|
|
default => 'auth.failed.callback',
|
|
};
|
|
|
|
return redirect()->route('login')->withErrors([__($errorCode)]);
|
|
}
|
|
}
|
|
|
|
private function logCallbackFailure(string $provider, \Throwable $exception): void
|
|
{
|
|
auditLog('auth.oauth.callback_failed', [
|
|
'provider' => $provider,
|
|
'exception_class' => $exception::class,
|
|
'reason' => $exception instanceof HttpException ? 'access_denied' : 'callback_error',
|
|
], 'warning');
|
|
Log::error('OAuth callback failed.', [
|
|
'provider' => $provider,
|
|
'exception_class' => $exception::class,
|
|
'exception_message' => $exception->getMessage(),
|
|
'request_error' => request()->query('error'),
|
|
'request_error_description' => request()->query('error_description'),
|
|
'has_code' => request()->query->has('code'),
|
|
'has_state' => request()->query->has('state'),
|
|
'ip' => request()->ip(),
|
|
'exception' => $exception,
|
|
]);
|
|
}
|
|
|
|
private function enabledProvider(string $provider): OauthSetting
|
|
{
|
|
$oauthSetting = OauthSetting::where('provider', $provider)->first();
|
|
if (! $oauthSetting || ! $oauthSetting->enabled || ! $oauthSetting->couldBeEnabled()) {
|
|
throw new HttpException(403, 'OAuth provider is not enabled');
|
|
}
|
|
|
|
return $oauthSetting;
|
|
}
|
|
}
|