demo_laravel_project/tests/Feature/Auth/OidcAuthenticationTest.php
= b8e5995c73
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
Add OIDC Socialite driver with configuration and provider tests
2026-06-17 07:17:05 +00:00

159 lines
4.6 KiB
PHP

<?php
use App\Models\User;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\User as SocialiteUser;
use SocialiteProviders\OIDC\Provider;
beforeEach(function () {
// Mock oidc services config
config([
'services.oidc.client_id' => 'mock_client_id',
'services.oidc.client_secret' => 'mock_client_secret',
'services.oidc.redirect' => 'https://mock-app.com/auth/oidc/callback',
'services.oidc.base_url' => 'https://mock-oidc-provider.com',
]);
});
test('oidc socialite driver resolves to the correct provider class', function () {
$driver = Socialite::driver('oidc');
expect($driver)->toBeInstanceOf(Provider::class);
});
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();
});