327 lines
10 KiB
PHP
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);
|
|
}
|
|
}
|