Files
timebank-cc-public/tests/Feature/Security/Authorization/LivewireMethodAuthorizationTest.php
Ronald Huynen 2547717edb Initial commit
2026-03-23 21:37:59 +01:00

327 lines
10 KiB
PHP

<?php
namespace Tests\Feature\Security\Authorization;
use App\Http\Livewire\Mailings\Manage as MailingsManage;
use App\Http\Livewire\Profiles\Create as ProfilesCreate;
use App\Http\Livewire\Tags\Create as TagsCreate;
use App\Models\Admin;
use App\Models\Bank;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;
/**
* Livewire Method-Level Authorization Tests
*
* Tests critical method-level authorization to prevent Livewire direct method invocation attacks.
* Focuses on the two newly discovered critical vulnerabilities and authorization patterns.
*
* @group security
* @group authorization
* @group livewire
* @group critical
*/
class LivewireMethodAuthorizationTest extends TestCase
{
use RefreshDatabase;
// ===========================================
// TAGS/CREATE.PHP - AUTHORIZATION TESTS
// ===========================================
/** @test */
public function admin_can_call_tags_create_method()
{
$admin = Admin::factory()->create();
$this->actingAs($admin, 'admin');
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(200);
}
/** @test */
public function central_bank_can_call_tags_create_method()
{
$bank = Bank::factory()->create(['level' => 0]);
$this->actingAs($bank, 'bank');
session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(200);
}
/** @test */
public function regular_bank_cannot_call_tags_create_method()
{
$bank = Bank::factory()->create(['level' => 1]);
$this->actingAs($bank, 'bank');
session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
/** @test */
public function user_cannot_call_tags_create_method()
{
$user = User::factory()->create();
$this->actingAs($user, 'web');
session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
/** @test */
public function organization_cannot_call_tags_create_method()
{
$org = Organization::factory()->create();
$this->actingAs($org, 'organization');
session(['activeProfileType' => Organization::class, 'activeProfileId' => $org->id]);
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
// ===========================================
// PROFILES/CREATE.PHP - CRITICAL VULNERABILITY FIX
// This was a CRITICAL vulnerability - unauthorized profile creation
// ===========================================
/** @test */
public function admin_can_access_profiles_create_component()
{
$admin = Admin::factory()->create();
$this->actingAs($admin, 'admin');
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);
$component = Livewire::test(ProfilesCreate::class);
$component->assertStatus(200);
}
/** @test */
public function central_bank_can_access_profiles_create_component()
{
$bank = Bank::factory()->create(['level' => 0]);
$this->actingAs($bank, 'bank');
session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);
$component = Livewire::test(ProfilesCreate::class);
$component->assertStatus(200);
}
/** @test */
public function user_cannot_access_profiles_create_component()
{
$user = User::factory()->create();
$this->actingAs($user, 'web');
session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);
$component = Livewire::test(ProfilesCreate::class);
$component->assertStatus(403);
}
/** @test */
public function organization_cannot_access_profiles_create_component()
{
$org = Organization::factory()->create();
$this->actingAs($org, 'organization');
session(['activeProfileType' => Organization::class, 'activeProfileId' => $org->id]);
$component = Livewire::test(ProfilesCreate::class);
$component->assertStatus(403);
}
// ===========================================
// MAILINGS/MANAGE.PHP - CRITICAL VULNERABILITY FIX
// bulkDeleteMailings() method was unprotected
// ===========================================
/** @test */
public function admin_can_access_mailings_manage_component()
{
$admin = Admin::factory()->create();
$this->actingAs($admin, 'admin');
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);
$component = Livewire::test(MailingsManage::class);
$component->assertStatus(200);
}
/** @test */
public function central_bank_can_access_mailings_manage_component()
{
$bank = Bank::factory()->create(['level' => 0]);
$this->actingAs($bank, 'bank');
session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);
$component = Livewire::test(MailingsManage::class);
$component->assertStatus(200);
}
/** @test */
public function user_cannot_access_mailings_manage_component()
{
$user = User::factory()->create();
$this->actingAs($user, 'web');
session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);
$component = Livewire::test(MailingsManage::class);
$component->assertStatus(403);
}
/** @test */
public function organization_cannot_access_mailings_manage_component()
{
$org = Organization::factory()->create();
$this->actingAs($org, 'organization');
session(['activeProfileType' => Organization::class, 'activeProfileId' => $org->id]);
$component = Livewire::test(MailingsManage::class);
$component->assertStatus(403);
}
// ===========================================
// CROSS-GUARD ATTACK PREVENTION TESTS
// ===========================================
/** @test */
public function user_authenticated_on_wrong_guard_cannot_access_admin_components()
{
$user = User::factory()->create();
$this->actingAs($user, 'web');
// Try to fake being an admin by setting wrong session
$admin = Admin::factory()->create();
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);
// Should be blocked because guard doesn't match
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
/** @test */
public function admin_cannot_access_other_admins_session()
{
$admin1 = Admin::factory()->create();
$admin2 = Admin::factory()->create();
$this->actingAs($admin1, 'admin');
// Try to fake session to access admin2's context
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin2->id]);
// Should be blocked by ProfileAuthorizationHelper IDOR prevention
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
/** @test */
public function unauthenticated_user_cannot_access_admin_components()
{
// No authentication at all - expect redirect or 403
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
/** @test */
public function user_with_no_session_cannot_access_admin_components()
{
$user = User::factory()->create();
$this->actingAs($user, 'web');
// Don't set session variables - this simulates a corrupted or missing session
// Set minimal session to prevent "No active profile" error
// but make it point to a non-existent or wrong profile
session([
'activeProfileType' => User::class,
'activeProfileId' => $user->id,
'active_guard' => 'web',
]);
// User (web guard) should not be able to access admin components
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
// ===========================================
// AUTHORIZATION CACHING TESTS
// ===========================================
/** @test */
public function authorization_is_cached_within_same_request()
{
$admin = Admin::factory()->create();
$this->actingAs($admin, 'admin');
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);
$component = Livewire::test(TagsCreate::class);
// First check happens in mount()
$component->assertStatus(200);
// Component can be used multiple times - caching works
$component->assertStatus(200);
}
// ===========================================
// BANK LEVEL VALIDATION TESTS
// ===========================================
/** @test */
public function only_central_bank_level_zero_can_access_admin_functions()
{
// Test level 0 (central bank) - should work
$centralBank = Bank::factory()->create(['level' => 0]);
$this->actingAs($centralBank, 'bank');
session(['activeProfileType' => Bank::class, 'activeProfileId' => $centralBank->id]);
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(200);
}
/** @test */
public function bank_level_one_cannot_access_admin_functions()
{
$bank = Bank::factory()->create(['level' => 1]);
$this->actingAs($bank, 'bank');
session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
/** @test */
public function bank_level_two_cannot_access_admin_functions()
{
$bank = Bank::factory()->create(['level' => 2]);
$this->actingAs($bank, 'bank');
session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);
$component = Livewire::test(TagsCreate::class);
$component->assertStatus(403);
}
}