148 lines
4.2 KiB
PHP
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();
|
|
});
|