coolify/tests/Feature/Authorization/ApiTokenPermissionTest.php
Andras Bacsai 66dc1515d4 fix(security): prevent snapshot replay in API token permission checks
Never trust Livewire component properties for authorization decisions, as
snapshots can be replayed from another user's session. Re-evaluate all
permission checks fresh using auth()->user()->can() against current policies
to ensure the authenticated user is being authorized, not a replayed copy.

- Replace cached canUse* booleans with fresh policy evaluation
- Add comprehensive security tests for token creation permissions
- Update API authorization tests to verify middleware blocking behavior
2026-02-27 22:58:44 +01:00

78 lines
2.4 KiB
PHP

<?php
use App\Models\InstanceSettings;
use App\Models\Team;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
InstanceSettings::updateOrCreate(['id' => 0], ['is_api_enabled' => true]);
$this->team = Team::factory()->create();
$this->user = User::factory()->create();
$this->team->members()->attach($this->user->id, ['role' => 'owner']);
session(['currentTeam' => $this->team]);
});
describe('POST /api/v1/projects', function () {
test('read-only token cannot create a project', function () {
$token = $this->user->createToken('read-only', ['read']);
$response = $this->withHeaders([
'Authorization' => 'Bearer '.$token->plainTextToken,
'Content-Type' => 'application/json',
])->postJson('/api/v1/projects', [
'name' => 'Test Project',
]);
$response->assertStatus(403);
});
test('write token can create a project', function () {
$token = $this->user->createToken('write-token', ['write']);
$response = $this->withHeaders([
'Authorization' => 'Bearer '.$token->plainTextToken,
'Content-Type' => 'application/json',
])->postJson('/api/v1/projects', [
'name' => 'Test Project',
]);
$response->assertStatus(201);
$response->assertJsonStructure(['uuid']);
});
test('root token can create a project', function () {
$token = $this->user->createToken('root-token', ['root']);
$response = $this->withHeaders([
'Authorization' => 'Bearer '.$token->plainTextToken,
'Content-Type' => 'application/json',
])->postJson('/api/v1/projects', [
'name' => 'Test Project',
]);
$response->assertStatus(201);
$response->assertJsonStructure(['uuid']);
});
});
describe('POST /api/v1/servers', function () {
test('read-only token cannot create a server', function () {
$token = $this->user->createToken('read-only', ['read']);
$response = $this->withHeaders([
'Authorization' => 'Bearer '.$token->plainTextToken,
'Content-Type' => 'application/json',
])->postJson('/api/v1/servers', [
'name' => 'Test Server',
'ip' => '1.2.3.4',
'private_key_uuid' => 'fake-uuid',
]);
$response->assertStatus(403);
});
});