diff --git a/app/Http/Controllers/LoginController.php b/app/Http/Controllers/LoginController.php index 14373ff..6d832af 100644 --- a/app/Http/Controllers/LoginController.php +++ b/app/Http/Controllers/LoginController.php @@ -148,11 +148,10 @@ public function handleMicrosoftCallback(Request $request) return $this->redirectUserBasedOnRole($user); } - /** - * Log the user out of the application. - */ public function logout(Request $request) { + $user = Auth::user(); + Auth::logout(); $request->session()->invalidate(); @@ -160,7 +159,19 @@ public function logout(Request $request) // Redirect to Microsoft's logout URL to log the user out of Microsoft as well try { - $microsoftLogoutUrl = Socialite::driver('microsoft')->getLogoutUrl(route('login')); + $tenant = config('services.microsoft.tenant', 'common'); + $logoutUrl = "https://login.microsoftonline.com/{$tenant}/oauth2/v2.0/logout"; + + $params = [ + 'post_logout_redirect_uri' => route('login'), + ]; + + if ($user && $user->email) { + // Pass logout_hint to bypass Microsoft's "Pick an account" selection screen + $params['logout_hint'] = $user->email; + } + + $microsoftLogoutUrl = $logoutUrl . '?' . http_build_query($params); return redirect($microsoftLogoutUrl); } catch (\Exception $e) { return redirect()->route('login')->with('success', 'Logged out successfully.'); diff --git a/public/Screenshot_7.png b/public/Screenshot_7.png new file mode 100644 index 0000000..5917944 Binary files /dev/null and b/public/Screenshot_7.png differ diff --git a/tests/Feature/SecurityAndAdminTest.php b/tests/Feature/SecurityAndAdminTest.php index 383448f..1460828 100644 --- a/tests/Feature/SecurityAndAdminTest.php +++ b/tests/Feature/SecurityAndAdminTest.php @@ -189,9 +189,6 @@ public function test_admin_cannot_authenticate_via_microsoft_oauth_callback(): v $this->assertFalse(auth()->check()); } - /** - * Test local logout redirects to Microsoft global logout endpoint. - */ public function test_user_logout_redirects_to_microsoft_logout_page(): void { $user = User::create([ @@ -200,17 +197,16 @@ public function test_user_logout_redirects_to_microsoft_logout_page(): void 'role' => 'user', ]); - $mockSocialite = \Mockery::mock('Laravel\Socialite\Contracts\Provider'); - $mockSocialite->shouldReceive('getLogoutUrl') - ->with(route('login')) - ->andReturn('https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri=' . urlencode(route('login'))); - - \Laravel\Socialite\Facades\Socialite::shouldReceive('driver')->with('microsoft')->andReturn($mockSocialite); - $response = $this->actingAs($user) ->get('/logout'); // supports GET for testing - $response->assertRedirect('https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri=' . urlencode(route('login'))); + $tenant = config('services.microsoft.tenant', 'common'); + $expectedRedirect = "https://login.microsoftonline.com/{$tenant}/oauth2/v2.0/logout?" . http_build_query([ + 'post_logout_redirect_uri' => route('login'), + 'logout_hint' => 'user@sentientgeeks.com', + ]); + + $response->assertRedirect($expectedRedirect); $this->assertFalse(auth()->check()); } @@ -264,7 +260,8 @@ public function test_sso_launch_redirects_to_microsoft_for_all_services_if_user_ $mockSocialite->shouldReceive('redirectUrl')->with(route('sso.callback'))->andReturnSelf(); $mockSocialite->shouldReceive('with')->with([ 'login_hint' => $user->email, - 'domain_hint' => 'organizations' + 'domain_hint' => 'organizations', + 'prompt' => 'none' ])->andReturnSelf(); $mockSocialite->shouldReceive('redirect') ->andReturn(redirect('https://login.microsoftonline.com/common/oauth2/v2.0/authorize'));