'Admin User', 'email' => 'admin@company.com', 'role' => 'admin', ]); $user = User::create([ 'name' => 'Standard User', 'email' => 'user@sentientgeeks.com', 'role' => 'user', ]); // Unauthenticated user is redirected to login $this->get('/admin/dashboard') ->assertRedirect(route('login')); // Admin can access admin dashboard $this->actingAs($admin) ->get('/admin/dashboard') ->assertStatus(200); // Standard user gets allowed standard user access to dashboard (our middleware handles this) $this->actingAs($user) ->get('/admin/dashboard') ->assertRedirect(route('dashboard')); } /** * Test blocked users are forced to logout and redirected. */ public function test_blocked_user_cannot_access_dashboard_and_gets_logged_out(): void { $user = User::create([ 'name' => 'Standard User', 'email' => 'user@sentientgeeks.com', 'role' => 'user', 'is_blocked' => true, ]); // Attempting to access dashboard logs them out and redirects $this->actingAs($user) ->get('/dashboard') ->assertRedirect(route('login')); $this->assertFalse(auth()->check()); } /** * Test restricted services are hidden from specific users via deny overrides. */ public function test_restricted_service_is_not_displayed_to_the_restricted_user(): void { $user = User::create([ 'name' => 'Standard User', 'email' => 'user@sentientgeeks.com', 'role' => 'user', ]); $app1 = App::create([ 'name' => 'Outlook', 'url' => 'https://outlook.office.com', 'color' => '#0078d4', 'tag' => 'Microsoft 365' ]); $app2 = App::create([ 'name' => 'Keka HR', 'url' => 'https://sentientgeeks.keka.com', 'color' => '#f27059', 'tag' => 'HR Portal' ]); // Create a role and associate both apps $role = Role::create(['name' => 'Employee']); $role->apps()->sync([$app1->id, $app2->id]); // Assign role to user $user->roles()->sync([$role->id]); // Restrict user from Keka HR using override UserAppOverride::create([ 'user_id' => $user->id, 'app_id' => $app2->id, 'type' => 'deny', ]); $response = $this->actingAs($user) ->get('/dashboard'); $response->assertStatus(200); $response->assertSee('Outlook'); $response->assertDontSee('Keka HR'); } /** * Test additional services are displayed to specific users via allow overrides. */ public function test_additional_service_is_displayed_to_the_user(): void { $user = User::create([ 'name' => 'Standard User', 'email' => 'user@sentientgeeks.com', 'role' => 'user', ]); $app1 = App::create([ 'name' => 'Outlook', 'url' => 'https://outlook.office.com', 'color' => '#0078d4', 'tag' => 'Microsoft 365' ]); $app2 = App::create([ 'name' => 'Keka HR', 'url' => 'https://sentientgeeks.keka.com', 'color' => '#f27059', 'tag' => 'HR Portal' ]); // Create a role that only has Outlook $role = Role::create(['name' => 'Intern']); $role->apps()->sync([$app1->id]); // Assign role to user $user->roles()->sync([$role->id]); // Add Keka HR as extra service using override UserAppOverride::create([ 'user_id' => $user->id, 'app_id' => $app2->id, 'type' => 'allow', ]); $response = $this->actingAs($user) ->get('/dashboard'); $response->assertStatus(200); $response->assertSee('Outlook'); $response->assertSee('Keka HR'); } /** * Test admin user cannot authenticate via Microsoft OAuth callback. */ public function test_admin_cannot_authenticate_via_microsoft_oauth_callback(): void { $admin = User::create([ 'name' => 'Admin User', 'email' => 'admin@company.com', 'role' => 'admin', 'microsoft_id' => 'admin-microsoft-id-999' ]); $mockSocialite = \Mockery::mock('Laravel\Socialite\Contracts\Provider'); $mockUser = \Mockery::mock('Laravel\Socialite\Two\User'); $mockUser->shouldReceive('getId')->andReturn('admin-microsoft-id-999'); $mockUser->shouldReceive('getEmail')->andReturn('admin@company.com'); $mockUser->shouldReceive('getName')->andReturn('Admin User'); $mockUser->shouldReceive('getAvatar')->andReturn(null); $mockSocialite->shouldReceive('user')->andReturn($mockUser); \Laravel\Socialite\Facades\Socialite::shouldReceive('driver')->with('microsoft')->andReturn($mockSocialite); $response = $this->get('/auth/microsoft/callback'); $response->assertRedirect(route('admin.login')); $response->assertSessionHas('error', 'Security protocol: Administrators are restricted to email and password authentication only.'); $this->assertFalse(auth()->check()); } public function test_user_logout_redirects_to_microsoft_logout_page(): void { $user = User::create([ 'name' => 'Standard User', 'email' => 'user@sentientgeeks.com', 'role' => 'user', ]); $response = $this->actingAs($user) ->get('/logout'); // supports GET for testing $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()); } /** * Test Microsoft Front-channel logout callback terminates local session. */ public function test_microsoft_front_channel_logout_clears_session(): void { $user = User::create([ 'name' => 'Standard User', 'email' => 'user@sentientgeeks.com', 'role' => 'user', ]); $this->actingAs($user); $this->assertTrue(auth()->check()); $response = $this->get('/auth/microsoft/logout'); $response->assertStatus(200); $response->assertSee('Logged out from SingleLogin'); $this->assertFalse(auth()->check()); } /** * Test that launching any service (like Keka) routes through Microsoft SSO flow * if the user is Microsoft-linked. */ public function test_sso_launch_redirects_to_microsoft_for_all_services_if_user_is_microsoft_linked(): void { $user = User::create([ 'name' => 'Standard User', 'email' => 'user@sentientgeeks.com', 'role' => 'user', 'microsoft_id' => 'user-microsoft-id-123', ]); $app = App::create([ 'name' => 'Keka HR', 'url' => 'https://sentientgeeks.keka.com', 'color' => '#f27059', 'tag' => 'HR Portal' ]); // Assign role with the app to user $role = Role::create(['name' => 'Employee']); $role->apps()->sync([$app->id]); $user->roles()->sync([$role->id]); $mockSocialite = \Mockery::mock('Laravel\Socialite\Contracts\Provider'); $mockSocialite->shouldReceive('redirectUrl')->with(route('sso.callback'))->andReturnSelf(); $mockSocialite->shouldReceive('with')->with([ 'login_hint' => $user->email, 'domain_hint' => 'organizations', 'prompt' => 'none' ])->andReturnSelf(); $mockSocialite->shouldReceive('redirect') ->andReturn(redirect('https://login.microsoftonline.com/common/oauth2/v2.0/authorize')); \Laravel\Socialite\Facades\Socialite::shouldReceive('driver')->with('microsoft')->andReturn($mockSocialite); $response = $this->actingAs($user) ->get(route('sso.launch', $app->id)); $response->assertRedirect('https://login.microsoftonline.com/common/oauth2/v2.0/authorize'); } /** * Test user with multiple roles including Admin logs in via general route, * sees user dashboard, displays all roles, and has Go to Admin Dashboard target_blank link. */ public function test_user_multiple_roles_admin_link(): void { $user = User::create([ 'name' => 'Multi Role User', 'email' => 'multi@sentientgeeks.com', 'role' => 'user', ]); $pmRole = Role::create(['name' => 'Project Manager']); $adminRole = Role::create(['name' => 'Admin']); $user->roles()->sync([$pmRole->id, $adminRole->id]); // User dashboard can be accessed $response = $this->actingAs($user) ->get('/dashboard'); $response->assertStatus(200); // At the top they will see other role i.e. admin $response->assertSee('Project Manager, Admin'); // And they will see a link Go to Admin Dashboard which has target="_blank" $response->assertSee('href="' . route('admin.dashboard') . '" target="_blank" class="nav-action-btn admin"', false); $response->assertSee('Go to Admin Dashboard'); // And they can access the Admin Dashboard $responseAdmin = $this->actingAs($user) ->get('/admin/dashboard'); $responseAdmin->assertStatus(200); } /** * Test that new user registration / login defaults to the configured role. */ public function test_new_user_registration_default_role(): void { // 1. Initially configuration fallback is Developer $devRole = Role::create(['name' => 'Developer']); $otherRole = Role::create(['name' => 'Team Lead']); // Mock Socialite callback for a brand new user $mockSocialite = \Mockery::mock('Laravel\Socialite\Contracts\Provider'); $mockUser = \Mockery::mock('Laravel\Socialite\Two\User'); $mockUser->shouldReceive('getId')->andReturn('new-microsoft-id-888'); $mockUser->shouldReceive('getEmail')->andReturn('newuser@sentientgeeks.com'); $mockUser->shouldReceive('getName')->andReturn('New User'); $mockUser->shouldReceive('getAvatar')->andReturn(null); $mockSocialite->shouldReceive('user')->andReturn($mockUser); \Laravel\Socialite\Facades\Socialite::shouldReceive('driver')->with('microsoft')->andReturn($mockSocialite); // Login as new user $response = $this->get('/auth/microsoft/callback'); $response->assertRedirect(route('dashboard')); $newUser = User::where('email', 'newuser@sentientgeeks.com')->first(); $this->assertNotNull($newUser); $this->assertTrue($newUser->hasRole('Developer')); $this->assertFalse($newUser->hasRole('Team Lead')); } /** * Test that new user registration / login defaults to the custom configured role. */ public function test_new_user_registration_custom_default_role(): void { $devRole = Role::create(['name' => 'Developer']); $otherRole = Role::create(['name' => 'Team Lead']); // Admin updates the configuration $admin = User::create([ 'name' => 'Admin User', 'email' => 'admin@company.com', 'role' => 'admin', ]); $this->withoutMiddleware(\Illuminate\Foundation\Http\Middleware\PreventRequestForgery::class); $this->actingAs($admin) ->post(route('admin.settings.default-role'), [ 'default_role' => 'Team Lead', ]) ->assertRedirect(route('admin.dashboard')); $this->assertEquals('Team Lead', \App\Models\Setting::get('default_role')); // Mock Socialite callback for second new user $mockSocialite2 = \Mockery::mock('Laravel\Socialite\Contracts\Provider'); $mockUser2 = \Mockery::mock('Laravel\Socialite\Two\User'); $mockUser2->shouldReceive('getId')->andReturn('new-microsoft-id-999'); $mockUser2->shouldReceive('getEmail')->andReturn('anotheruser@sentientgeeks.com'); $mockUser2->shouldReceive('getName')->andReturn('Another User'); $mockUser2->shouldReceive('getAvatar')->andReturn(null); $mockSocialite2->shouldReceive('user')->andReturn($mockUser2); \Laravel\Socialite\Facades\Socialite::shouldReceive('driver')->with('microsoft')->andReturn($mockSocialite2); // Login as second new user $response2 = $this->get('/auth/microsoft/callback'); $response2->assertRedirect(route('dashboard')); $anotherUser = User::where('email', 'anotheruser@sentientgeeks.com')->first(); $this->assertNotNull($anotherUser); $this->assertTrue($anotherUser->hasRole('Team Lead')); $this->assertFalse($anotherUser->hasRole('Developer')); } /** * Test granting and revoking admin privileges to/from other users. */ public function test_admin_toggle_privileges(): void { $admin = User::create([ 'name' => 'Admin User', 'email' => 'admin@company.com', 'role' => 'admin', ]); $targetUser = User::create([ 'name' => 'Regular Dev', 'email' => 'dev@sentientgeeks.com', 'role' => 'user', ]); $this->withoutMiddleware(\Illuminate\Foundation\Http\Middleware\PreventRequestForgery::class); // 1. Grant admin privilege $response = $this->actingAs($admin) ->post(route('admin.users.toggle-admin', $targetUser->id)); $response->assertRedirect(route('admin.dashboard')); $targetUser = $targetUser->fresh(); $this->assertTrue($targetUser->isAdmin()); $this->assertEquals('admin', $targetUser->role); $this->assertTrue($targetUser->hasRole('Admin')); // 2. Revoke admin privilege $response2 = $this->actingAs($admin) ->post(route('admin.users.toggle-admin', $targetUser->id)); $response2->assertRedirect(route('admin.dashboard')); $targetUser = $targetUser->fresh(); $this->assertFalse($targetUser->isAdmin()); $this->assertEquals('user', $targetUser->role); $this->assertFalse($targetUser->hasRole('Admin')); // 3. Security: Prevent toggling self $response3 = $this->actingAs($admin) ->post(route('admin.users.toggle-admin', $admin->id)); $response3->assertRedirect(route('admin.dashboard')); $this->assertTrue($admin->fresh()->isAdmin()); } }