demo_laravel_project/tests/Feature/Auth/OidcAuthenticationTest.php
2026-06-16 11:56:21 +00:00

148 lines
4.2 KiB
PHP

<?php
use App\Models\User;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\User as SocialiteUser;
beforeEach(function () {
// Clear oidc services config to mock config checks
config(['services.oidc.client_id' => 'mock_client_id']);
});
test('oidc login button is visible on login page when configured', function () {
$response = $this->get(route('login'));
$response->assertOk();
$response->assertSee('Log in with Single Sign-On');
});
test('oidc login button is hidden when client_id is not configured', function () {
config(['services.oidc.client_id' => null]);
$response = $this->get(route('login'));
$response->assertOk();
$response->assertDontSee('Log in with Single Sign-On');
});
test('oidc redirect endpoint redirects to identity provider', function () {
$mockDriver = Mockery::mock();
$mockDriver->shouldReceive('redirect')
->once()
->andReturn(redirect('https://mock-oidc-provider.com/auth'));
Socialite::shouldReceive('driver')
->with('oidc')
->once()
->andReturn($mockDriver);
$response = $this->get(route('oidc.redirect'));
$response->assertRedirect('https://mock-oidc-provider.com/auth');
});
test('oidc callback links account and logs in existing user', function () {
$user = User::factory()->create([
'email' => 'existing@example.com',
'oidc_sub' => null,
]);
$mockSocialiteUser = new SocialiteUser;
$mockSocialiteUser->map([
'id' => 'sub_12345',
'email' => 'existing@example.com',
'name' => 'Existing User',
]);
$mockDriver = Mockery::mock();
$mockDriver->shouldReceive('user')
->once()
->andReturn($mockSocialiteUser);
Socialite::shouldReceive('driver')
->with('oidc')
->once()
->andReturn($mockDriver);
$response = $this->get(route('oidc.callback'));
$response->assertSessionHasNoErrors();
$response->assertRedirect(route('dashboard', absolute: false));
$this->assertAuthenticatedAs($user);
expect($user->fresh()->oidc_sub)->toBe('sub_12345');
});
test('oidc callback logs in linked user directly by oidc_sub', function () {
$user = User::factory()->create([
'email' => 'existing@example.com',
'oidc_sub' => 'sub_12345',
]);
$mockSocialiteUser = new SocialiteUser;
$mockSocialiteUser->map([
'id' => 'sub_12345',
'email' => 'existing@example.com',
'name' => 'Existing User',
]);
$mockDriver = Mockery::mock();
$mockDriver->shouldReceive('user')
->once()
->andReturn($mockSocialiteUser);
Socialite::shouldReceive('driver')
->with('oidc')
->once()
->andReturn($mockDriver);
$response = $this->get(route('oidc.callback'));
$response->assertSessionHasNoErrors();
$response->assertRedirect(route('dashboard', absolute: false));
$this->assertAuthenticatedAs($user);
});
test('oidc callback rejects authentication if user does not exist', function () {
$mockSocialiteUser = new SocialiteUser;
$mockSocialiteUser->map([
'id' => 'sub_99999',
'email' => 'nonexistent@example.com',
'name' => 'New User',
]);
$mockDriver = Mockery::mock();
$mockDriver->shouldReceive('user')
->once()
->andReturn($mockSocialiteUser);
Socialite::shouldReceive('driver')
->with('oidc')
->once()
->andReturn($mockDriver);
$response = $this->get(route('oidc.callback'));
$response->assertRedirect(route('login'));
$response->assertSessionHasErrors(['email' => 'Account not found. Please contact an administrator.']);
$this->assertGuest();
});
test('oidc callback handles socialite exceptions gracefully', function () {
$mockDriver = Mockery::mock();
$mockDriver->shouldReceive('user')
->once()
->andThrow(new Exception('OIDC server error'));
Socialite::shouldReceive('driver')
->with('oidc')
->once()
->andReturn($mockDriver);
$response = $this->get(route('oidc.callback'));
$response->assertRedirect(route('login'));
$response->assertSessionHasErrors(['email' => 'Authentication failed: OIDC server error']);
$this->assertGuest();
});