141 lines
5.0 KiB
PHP
141 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Inquiry;
|
|
use App\Models\TenantEntitlement;
|
|
use App\Models\TenantSetupToken;
|
|
use App\Jobs\ProvisionTenantJob;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use App\Models\Tenant;
|
|
use Tests\TestCase;
|
|
|
|
class TenantInvitationSetupTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_provisioning_dispatches_one_time_token_and_does_not_use_default_passwords(): void
|
|
{
|
|
Mail::fake();
|
|
|
|
$inquiry = Inquiry::create([
|
|
'company_name' => 'Secure Org',
|
|
'contact_name' => 'Org Admin',
|
|
'email' => 'admin@secureorg.com',
|
|
'desired_subdomain' => 'secure-org-tenant',
|
|
'employee_count' => 25,
|
|
'requested_features' => ['payroll'],
|
|
'email_verified_at' => now(),
|
|
'status' => 'approved',
|
|
]);
|
|
|
|
$job = new ProvisionTenantJob($inquiry);
|
|
$job->handle();
|
|
|
|
$tenant = Tenant::find('secure-org-tenant');
|
|
$this->assertNotNull($tenant);
|
|
|
|
// 1. Verify state transition to active
|
|
$this->assertEquals('active', $inquiry->fresh()->status);
|
|
|
|
// 2. Verify TenantEntitlement created in central DB
|
|
$entitlement = TenantEntitlement::where('tenant_id', 'secure-org-tenant')->first();
|
|
$this->assertNotNull($entitlement);
|
|
$this->assertEquals(25, $entitlement->max_employees);
|
|
|
|
// 3. Verify TenantSetupToken generated with unexpired hashed token
|
|
$setupToken = TenantSetupToken::where('tenant_id', 'secure-org-tenant')->first();
|
|
$this->assertNotNull($setupToken);
|
|
$this->assertEquals('admin@secureorg.com', $setupToken->email);
|
|
$this->assertFalse($setupToken->isExpired());
|
|
$this->assertFalse($setupToken->isUsed());
|
|
|
|
// 4. Verify email invitation was dispatched
|
|
Mail::assertSent(\App\Mail\TenantSetupInvitationMail::class, function ($mail) {
|
|
return $mail->hasTo('admin@secureorg.com');
|
|
});
|
|
|
|
// 5. Verify admin account inside tenant DB uses default password '12345678'
|
|
$tenant->run(function () {
|
|
$user = \App\Models\User::where('email', 'admin@secureorg.com')->first();
|
|
$this->assertNotNull($user);
|
|
$this->assertEquals('active', $user->status);
|
|
$this->assertTrue(\Illuminate\Support\Facades\Hash::check('12345678', $user->password));
|
|
});
|
|
}
|
|
|
|
public function test_admin_can_set_password_via_token_and_token_expires_after_use(): void
|
|
{
|
|
$tenantId = 'setup-token-test';
|
|
$email = 'tokenadmin@acme.com';
|
|
|
|
$dbFile = database_path('tenant_' . $tenantId);
|
|
if (!file_exists($dbFile)) {
|
|
touch($dbFile);
|
|
}
|
|
|
|
Tenant::create([
|
|
'id' => $tenantId,
|
|
'tenancy_db_name' => 'tenant_' . $tenantId,
|
|
'email' => $email,
|
|
]);
|
|
|
|
$rawToken = 'valid_raw_test_token_123456';
|
|
$tokenHash = hash('sha256', $rawToken);
|
|
|
|
$setupToken = TenantSetupToken::create([
|
|
'tenant_id' => $tenantId,
|
|
'email' => $email,
|
|
'token_hash' => $tokenHash,
|
|
'expires_at' => now()->addHours(24),
|
|
]);
|
|
|
|
$tenant = Tenant::find($tenantId);
|
|
$tenant->run(function () use ($dbFile, $email) {
|
|
config(['database.connections.tenant.database' => $dbFile]);
|
|
\Illuminate\Support\Facades\DB::purge('tenant');
|
|
\Illuminate\Support\Facades\DB::reconnect('tenant');
|
|
|
|
\Illuminate\Support\Facades\Artisan::call('migrate', [
|
|
'--database' => 'tenant',
|
|
'--path' => 'database/migrations/tenant',
|
|
'--force' => true,
|
|
]);
|
|
|
|
\App\Models\User::updateOrCreate(
|
|
['email' => $email],
|
|
[
|
|
'name' => 'Token Admin',
|
|
'password' => \Illuminate\Support\Facades\Hash::make('temp_random_hash'),
|
|
'status' => 'inactive',
|
|
]
|
|
);
|
|
});
|
|
|
|
// Execute setup request
|
|
$controller = new \App\Http\Controllers\TenantSetupController();
|
|
$request = \Illuminate\Http\Request::create('/setup-admin', 'POST', [
|
|
'token' => $rawToken,
|
|
'password' => 'NewSecurePassword123!',
|
|
'password_confirmation' => 'NewSecurePassword123!',
|
|
]);
|
|
|
|
$response = $tenant->run(function () use ($controller, $request) {
|
|
return $controller->completeSetup($request);
|
|
});
|
|
|
|
$this->assertEquals(302, $response->getStatusCode());
|
|
|
|
// Verify token is marked used
|
|
$this->assertTrue($setupToken->fresh()->isUsed());
|
|
|
|
// Verify admin account is active and password updated inside tenant DB
|
|
$tenant->run(function () use ($email) {
|
|
$user = \App\Models\User::where('email', $email)->first();
|
|
$this->assertEquals('active', $user->status);
|
|
$this->assertTrue(\Illuminate\Support\Facades\Hash::check('NewSecurePassword123!', $user->password));
|
|
});
|
|
}
|
|
}
|