242 lines
7.9 KiB
PHP
242 lines
7.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Security\Authorization;
|
|
|
|
use App\Models\User;
|
|
use App\Models\Organization;
|
|
use App\Models\Bank;
|
|
use App\Models\Admin;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Profile Deletion Authorization Tests
|
|
*
|
|
* Tests that users can only delete their own profiles and cannot delete
|
|
* profiles they don't own or have access to.
|
|
*
|
|
* @group security
|
|
* @group authorization
|
|
* @group critical
|
|
*/
|
|
class ProfileDeletionAuthorizationTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
/**
|
|
* Test user cannot delete another user's profile
|
|
*
|
|
* @test
|
|
*/
|
|
public function user_cannot_delete_another_users_profile()
|
|
{
|
|
// Arrange: Create two users
|
|
$user1 = User::factory()->create(['password' => bcrypt('password123')]);
|
|
$user2 = User::factory()->create();
|
|
|
|
// Act: Login as user1 and try to delete user2's profile
|
|
$this->actingAs($user1);
|
|
|
|
// Create session as if user1 is trying to delete user2
|
|
session(['activeProfileType' => 'App\\Models\\User']);
|
|
session(['activeProfileId' => $user2->id]); // Malicious attempt
|
|
session(['active_guard' => 'web']);
|
|
|
|
// Attempt deletion
|
|
$response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
|
|
->set('password', 'password123')
|
|
->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard());
|
|
|
|
// Assert: The operation should fail or delete user1 (not user2)
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $user2->id,
|
|
'deleted_at' => null,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test user cannot delete organization they don't have access to
|
|
*
|
|
* @test
|
|
*/
|
|
public function user_cannot_delete_organization_they_dont_own()
|
|
{
|
|
// Arrange: Create user and two organizations
|
|
$user = User::factory()->create(['password' => bcrypt('password123')]);
|
|
$org1 = Organization::factory()->create(['password' => bcrypt('orgpass123')]);
|
|
$org2 = Organization::factory()->create();
|
|
|
|
// Link user to org1 only
|
|
$user->organizations()->attach($org1->id);
|
|
|
|
// Act: Login as user and try to delete org2
|
|
$this->actingAs($user);
|
|
|
|
session(['activeProfileType' => 'App\\Models\\Organization']);
|
|
session(['activeProfileId' => $org2->id]); // Malicious attempt
|
|
session(['active_guard' => 'organization']);
|
|
|
|
// Attempt deletion
|
|
$response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
|
|
->set('password', 'password123')
|
|
->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard('organization'));
|
|
|
|
// Assert: org2 should NOT be deleted
|
|
$this->assertDatabaseHas('organizations', [
|
|
'id' => $org2->id,
|
|
'deleted_at' => null,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test central bank (level 0) cannot be deleted
|
|
*
|
|
* @test
|
|
*/
|
|
public function central_bank_cannot_be_deleted()
|
|
{
|
|
// Arrange: Create central bank
|
|
$centralBank = Bank::factory()->create([
|
|
'level' => 0,
|
|
'password' => bcrypt('bankpass123')
|
|
]);
|
|
|
|
$user = User::factory()->create();
|
|
$user->banks()->attach($centralBank->id);
|
|
|
|
// Act: Login and try to delete central bank
|
|
$this->actingAs($user);
|
|
auth()->guard('bank')->login($centralBank);
|
|
|
|
session(['activeProfileType' => 'App\\Models\\Bank']);
|
|
session(['activeProfileId' => $centralBank->id]);
|
|
session(['active_guard' => 'bank']);
|
|
|
|
// Attempt deletion
|
|
$response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
|
|
->set('password', 'bankpass123')
|
|
->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard('bank'));
|
|
|
|
// Assert: Deletion should fail with validation error
|
|
$response->assertHasErrors(['password']);
|
|
|
|
// Assert: Central bank still exists
|
|
$this->assertDatabaseHas('banks', [
|
|
'id' => $centralBank->id,
|
|
'level' => 0,
|
|
'deleted_at' => null,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test final admin cannot be deleted
|
|
*
|
|
* @test
|
|
*/
|
|
public function final_admin_cannot_be_deleted()
|
|
{
|
|
// Arrange: Create single admin
|
|
$admin = Admin::factory()->create(['password' => bcrypt('adminpass123')]);
|
|
$user = User::factory()->create();
|
|
$user->admins()->attach($admin->id);
|
|
|
|
// Act: Login and try to delete the only admin
|
|
$this->actingAs($user);
|
|
auth()->guard('admin')->login($admin);
|
|
|
|
session(['activeProfileType' => 'App\\Models\\Admin']);
|
|
session(['activeProfileId' => $admin->id]);
|
|
session(['active_guard' => 'admin']);
|
|
|
|
// Attempt deletion
|
|
$response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
|
|
->set('password', 'adminpass123')
|
|
->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard('admin'));
|
|
|
|
// Assert: Deletion should fail with validation error
|
|
$response->assertHasErrors(['password']);
|
|
|
|
// Assert: Admin still exists
|
|
$this->assertDatabaseHas('admins', [
|
|
'id' => $admin->id,
|
|
'deleted_at' => null,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test user can delete their own profile with correct password
|
|
*
|
|
* @test
|
|
*/
|
|
public function user_can_delete_own_profile_with_correct_password()
|
|
{
|
|
// Arrange: Create user
|
|
$user = User::factory()->create(['password' => bcrypt('password123')]);
|
|
|
|
// Act: Login and delete own profile
|
|
$this->actingAs($user);
|
|
|
|
session(['activeProfileType' => 'App\\Models\\User']);
|
|
session(['activeProfileId' => $user->id]);
|
|
session(['active_guard' => 'web']);
|
|
|
|
// Attempt deletion with correct password
|
|
$response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
|
|
->set('password', 'password123')
|
|
->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard());
|
|
|
|
// Assert: User is soft-deleted
|
|
$this->assertSoftDeleted('users', [
|
|
'id' => $user->id,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test user cannot delete profile with wrong password
|
|
*
|
|
* @test
|
|
*/
|
|
public function user_cannot_delete_profile_with_wrong_password()
|
|
{
|
|
// Arrange: Create user
|
|
$user = User::factory()->create(['password' => bcrypt('password123')]);
|
|
|
|
// Act: Login and try to delete with wrong password
|
|
$this->actingAs($user);
|
|
|
|
session(['activeProfileType' => 'App\\Models\\User']);
|
|
session(['activeProfileId' => $user->id]);
|
|
session(['active_guard' => 'web']);
|
|
|
|
// Attempt deletion with wrong password
|
|
$response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
|
|
->set('password', 'wrongpassword')
|
|
->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard());
|
|
|
|
// Assert: Deletion should fail with validation error
|
|
$response->assertHasErrors(['password']);
|
|
|
|
// Assert: User still exists
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $user->id,
|
|
'deleted_at' => null,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test unauthenticated user cannot access delete form
|
|
*
|
|
* @test
|
|
*/
|
|
public function unauthenticated_user_cannot_access_delete_form()
|
|
{
|
|
// Act: Try to render delete form without authentication
|
|
$response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class);
|
|
|
|
// Assert: Should fail (Laravel's auth middleware should prevent this)
|
|
// This test verifies the component requires authentication
|
|
$this->assertGuest();
|
|
}
|
|
}
|