Merge pull request 'implement single login system' (#3) from subhajit_changes_06_07 into main
Reviewed-on: #3
This commit is contained in:
commit
1269da494b
@ -48,12 +48,13 @@ public function launchSSO($id)
|
||||
? 'organizations'
|
||||
: 'consumers';
|
||||
|
||||
// Redirect to Microsoft OAuth authorize page with login_hint, domain_hint and custom callback
|
||||
// Redirect to Microsoft OAuth authorize page with login_hint, domain_hint, prompt=none and custom callback
|
||||
return Socialite::driver('microsoft')
|
||||
->redirectUrl(route('sso.callback'))
|
||||
->with([
|
||||
'login_hint' => $user->email,
|
||||
'domain_hint' => $domainHint
|
||||
'domain_hint' => $domainHint,
|
||||
'prompt' => 'none'
|
||||
])
|
||||
->redirect();
|
||||
} catch (\Exception $e) {
|
||||
@ -74,6 +75,14 @@ public function launchSSO($id)
|
||||
*/
|
||||
public function handleSSOCallback(Request $request)
|
||||
{
|
||||
// If Microsoft returns an error (user logged out or session expired)
|
||||
if ($request->has('error')) {
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
return redirect()->route('login')->with('error', 'You have been signed out because your Microsoft session is no longer active.');
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
try {
|
||||
@ -87,12 +96,20 @@ public function handleSSOCallback(Request $request)
|
||||
'microsoft_token' => $microsoftUser->token,
|
||||
'microsoft_refresh_token' => $microsoftUser->refreshToken ?? $user->microsoft_refresh_token,
|
||||
]);
|
||||
|
||||
// Update verification timestamp
|
||||
session(['ms_session_last_checked' => now()]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::error('Microsoft SSO callback failed', [
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
// If callback fails but we have target URL, we can still try to redirect
|
||||
|
||||
// Treat token exchange failure as an expired session
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
return redirect()->route('login')->with('error', 'Your Microsoft session has expired. Please log in again.');
|
||||
}
|
||||
|
||||
$targetUrl = session('sso_target_url', 'https://outlook.office.com/mail/');
|
||||
@ -110,6 +127,53 @@ public function handleSSOCallback(Request $request)
|
||||
return redirect($targetUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle silent session verification callback from Microsoft.
|
||||
*/
|
||||
public function handleSessionCheckCallback(Request $request)
|
||||
{
|
||||
// If Microsoft returns an error (user logged out or session expired)
|
||||
if ($request->has('error')) {
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
return redirect()->route('login')->with('error', 'You have been signed out because you signed out of your Microsoft account.');
|
||||
}
|
||||
|
||||
try {
|
||||
$microsoftUser = Socialite::driver('microsoft')
|
||||
->redirectUrl(route('sso.callback-check'))
|
||||
->user();
|
||||
|
||||
$user = Auth::user();
|
||||
if ($microsoftUser && $user) {
|
||||
// Update active tokens in DB
|
||||
$user->update([
|
||||
'microsoft_token' => $microsoftUser->token,
|
||||
'microsoft_refresh_token' => $microsoftUser->refreshToken ?? $user->microsoft_refresh_token,
|
||||
]);
|
||||
|
||||
// Update verification timestamp
|
||||
session(['ms_session_last_checked' => now()]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::error('Microsoft session check callback failed', [
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
|
||||
// Treat token exchange failure as an expired session
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
return redirect()->route('login')->with('error', 'Your Microsoft session has expired. Please log in again.');
|
||||
}
|
||||
|
||||
// Redirect back to the page they were trying to access
|
||||
$origin = session('sso_check_origin', route('dashboard'));
|
||||
session()->forget('sso_check_origin');
|
||||
return redirect($origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the desktop application launcher page with web fallback.
|
||||
*/
|
||||
|
||||
57
app/Http/Middleware/VerifyMicrosoftSession.php
Normal file
57
app/Http/Middleware/VerifyMicrosoftSession.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class VerifyMicrosoftSession
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
// Only check if user is authenticated and has a Microsoft ID linked
|
||||
if ($user && $user->microsoft_id) {
|
||||
$lastChecked = session('ms_session_last_checked');
|
||||
|
||||
// Check every 30 seconds upon page access/refresh
|
||||
if (!$lastChecked || now()->diffInSeconds($lastChecked) > 30) {
|
||||
// Set timestamp immediately to prevent redirect loop
|
||||
session(['ms_session_last_checked' => now()]);
|
||||
|
||||
// Store target URL to return to after silent verification
|
||||
session(['sso_check_origin' => $request->fullUrl()]);
|
||||
|
||||
// Determine domain hint based on user's email domain
|
||||
$domainHint = (str_ends_with($user->email, '.onmicrosoft.com') || (str_contains($user->email, '@') && !str_ends_with($user->email, 'outlook.com') && !str_ends_with($user->email, 'hotmail.com') && !str_ends_with($user->email, 'live.com')))
|
||||
? 'organizations'
|
||||
: 'consumers';
|
||||
|
||||
try {
|
||||
// Redirect to Microsoft with prompt=none to check session status
|
||||
return Socialite::driver('microsoft')
|
||||
->redirectUrl(route('sso.callback-check'))
|
||||
->with([
|
||||
'login_hint' => $user->email,
|
||||
'domain_hint' => $domainHint,
|
||||
'prompt' => 'none'
|
||||
])
|
||||
->redirect();
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::error('Microsoft session silent verification failed', [
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,7 @@
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
$middleware->alias([
|
||||
'role' => \App\Http\Middleware\EnsureRole::class,
|
||||
'verify-ms-session' => \App\Http\Middleware\VerifyMicrosoftSession::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
|
||||
BIN
public/Screenshot_5.png
Normal file
BIN
public/Screenshot_5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 123 KiB |
BIN
public/Screenshot_6.png
Normal file
BIN
public/Screenshot_6.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 150 KiB |
@ -19,16 +19,23 @@
|
||||
Route::get('/auth/microsoft/logout', [LoginController::class, 'frontChannelLogout'])->name('auth.microsoft.logout');
|
||||
|
||||
// User Dashboard Portal (requires standard user role or admin access)
|
||||
Route::middleware(['auth', 'role:user'])->group(function () {
|
||||
Route::middleware(['auth', 'role:user', 'verify-ms-session'])->group(function () {
|
||||
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
|
||||
});
|
||||
|
||||
Route::middleware(['auth', 'role:user'])->group(function () {
|
||||
Route::get('/sso/launch/{id}', [DashboardController::class, 'launchSSO'])->name('sso.launch');
|
||||
Route::get('/sso/callback', [DashboardController::class, 'handleSSOCallback'])->name('sso.callback');
|
||||
Route::get('/sso/launch-app', [DashboardController::class, 'launchApp'])->name('sso.launch-app');
|
||||
});
|
||||
|
||||
Route::middleware('auth')->group(function () {
|
||||
Route::get('/sso/check-session-callback', [DashboardController::class, 'handleSessionCheckCallback'])->name('sso.callback-check');
|
||||
});
|
||||
|
||||
// Admin Control Panel (requires admin role)
|
||||
Route::middleware(['auth', 'role:admin'])->group(function () {
|
||||
Route::get('/admin/dashboard', [AdminController::class, 'index'])->name('admin.dashboard');
|
||||
Route::get('/admin/dashboard', [AdminController::class, 'index'])->name('admin.dashboard')->middleware('verify-ms-session');
|
||||
Route::post('/admin/apps', [AdminController::class, 'storeApp'])->name('admin.apps.store');
|
||||
Route::delete('/admin/apps/{id}', [AdminController::class, 'destroyApp'])->name('admin.apps.destroy');
|
||||
Route::post('/admin/users/{id}/toggle-block', [AdminController::class, 'toggleBlockUser'])->name('admin.users.toggle-block');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user