Files
go-no-go/app/Http/Controllers/Auth/SocialiteController.php

148 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\Role;
use App\Models\User;
use App\Services\ActivityLogger;
use Illuminate\Database\QueryException;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use Laravel\Socialite\Facades\Socialite;
final class SocialiteController extends Controller
{
/**
* Redirect the user to the Azure AD authentication page.
* Logs the Azure config (client_id prefix, redirect URI, tenant) and generated redirect URL.
*/
public function redirect(): RedirectResponse
{
$azureConfig = config('services.azure');
Log::info('[Azure SSO] Initiating redirect', [
'client_id_prefix' => substr((string) Arr::get($azureConfig, 'client_id', ''), 0, 4),
'redirect_uri' => Arr::get($azureConfig, 'redirect'),
'tenant' => Arr::get($azureConfig, 'tenant'),
]);
$response = Socialite::driver('azure')->redirect();
Log::info('[Azure SSO] Redirect URL generated', [
'redirect_url' => $response->getTargetUrl(),
]);
return $response;
}
/**
* Handle the callback from Azure AD after authentication.
* Logs request parameters, the resolved Azure user, and the upserted local user.
* Wraps the entire flow in a try/catch to capture and log any exceptions.
*/
public function callback(): RedirectResponse
{
try {
return $this->processCallback();
} catch (\Throwable $e) {
Log::error('[Azure SSO] Exception during callback', [
'message' => $e->getMessage(),
'exception' => $e->getTraceAsString(),
]);
throw $e;
}
}
/**
* Log the user out and redirect to landing page.
*/
public function logout(Request $request): RedirectResponse
{
ActivityLogger::log('logout', auth()->id());
auth()->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
/**
* Execute the full Azure AD callback flow: resolve the user, upsert the local record,
* assign a default role if needed, log the user in, and record the activity.
*/
private function processCallback(): RedirectResponse
{
Log::info('[Azure SSO] Callback received', [
'query_code' => substr((string) request()->query('code', ''), 0, 8).'…',
'query_state' => request()->query('state'),
'query_error' => request()->query('error'),
'query_error_description' => request()->query('error_description'),
]);
$azureUser = Socialite::driver('azure')->user();
Log::info('[Azure SSO] Azure user resolved', [
'azure_id' => $azureUser->getId(),
'email' => $azureUser->getEmail(),
'mail' => Arr::get($azureUser->user, 'mail'),
'name' => $azureUser->getName(),
'job_title' => Arr::get($azureUser->user, 'jobTitle'),
'department' => Arr::get($azureUser->user, 'department'),
'company' => Arr::get($azureUser->user, 'companyName'),
]);
Log::info('[Azure SSO] Full Azure user dump', json_decode(json_encode($azureUser), true));
try {
$user = User::query()->updateOrCreate(
['username' => $azureUser->getEmail()],
[
'name' => $azureUser->getName(),
'email' => $azureUser->user['mail'] ?? $azureUser->getEmail(),
'azure_id' => $azureUser->getId(),
'photo' => $azureUser->getAvatar(),
'job_title' => Arr::get($azureUser->user, 'jobTitle'),
'department' => Arr::get($azureUser->user, 'department'),
'company_name' => Arr::get($azureUser->user, 'companyName'),
'phone' => Arr::get($azureUser->user, 'mobilePhone', Arr::get($azureUser->user, 'businessPhones.0')),
'email_verified_at' => now(),
]
);
Log::info('[Azure SSO] Local user upserted', [
'user_id' => $user->id,
'email' => $user->email,
'was_recent' => $user->wasRecentlyCreated,
'role_id' => $user->role_id,
]);
if ($user->role_id === null) {
$user->update(['role_id' => Role::where('name', 'user')->first()->id]);
Log::info('[Azure SSO] Default role assigned', [
'user_id' => $user->id,
'role_id' => $user->role_id,
]);
}
auth()->login($user);
ActivityLogger::log('login', $user->id, metadata: ['email' => $user->email, 'firm_name' => Arr::get($azureUser->user, 'companyName')]);
} catch (QueryException $e) {
Log::error('[Azure SSO] Database error during user upsert', ['message' => $e->getMessage(), 'email' => $azureUser->getEmail()]);
return redirect('/')->with('error', 'Something went wrong during sign-in. Please try again or contact support.');
}
return redirect('/');
}
}