145 lines
4.9 KiB
PHP
145 lines
4.9 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\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(),
|
|
'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', [
|
|
'raw_user' => $azureUser->user,
|
|
'token' => substr((string) $azureUser->token, 0, 12).'…',
|
|
'refresh_token' => $azureUser->refreshToken ? 'present' : 'absent',
|
|
'expires_in' => $azureUser->expiresIn,
|
|
'avatar' => $azureUser->getAvatar(),
|
|
'nickname' => $azureUser->getNickname(),
|
|
]);
|
|
|
|
$user = User::query()->updateOrCreate(
|
|
['email' => $azureUser->getEmail()],
|
|
[
|
|
'name' => $azureUser->getName(),
|
|
'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')),
|
|
]
|
|
);
|
|
|
|
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')]);
|
|
|
|
return redirect('/');
|
|
}
|
|
}
|