1
<?php
2
declare(strict_types=1);
3
4
use Machweis\Backend\AuditService;
5
use Machweis\Backend\CompanyProfileService;
6
use Machweis\Backend\Config;
7
use Machweis\Backend\EmployeeProfileService;
8
use Machweis\Backend\PermissionService;
9
10
require dirname(__DIR__) . '/src/autoload.php';
11
12
function permissionCheck(bool $condition, string $message): void { if (!$condition) throw new RuntimeException($message); }
13
function permissionUuid(): string { $hex = bin2hex(random_bytes(16)); return substr($hex, 0, 8) . '-' . substr($hex, 8, 4) . '-4' . substr($hex, 13, 3) . '-8' . substr($hex, 17, 3) . '-' . substr($hex, 20); }
14
15
$config = new Config('test', false, (string) getenv('DB_HOST'), (int) getenv('DB_PORT'), (string) getenv('DB_NAME'), (string) getenv('DB_USER'), (string) getenv('DB_PASSWORD'), [], true, str_repeat('permissions-secret-', 2));
16
$pdo = new PDO(sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $config->dbHost, $config->dbPort, $config->dbName), $config->dbUser, $config->dbPassword, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false]);
17
$tenantA = permissionUuid(); $tenantB = permissionUuid(); $owner = permissionUuid(); $target = permissionUuid();
18
$pdo->prepare('INSERT INTO tenants (id,name,status,created_at) VALUES (?, ?, ?, UTC_TIMESTAMP()), (?, ?, ?, UTC_TIMESTAMP())')->execute([$tenantA, 'Berechtigung A', 'active', $tenantB, 'Berechtigung B', 'active']);
19
$ownerRole = $pdo->query("SELECT id FROM roles WHERE code = 'owner'")->fetchColumn(); $supervisorRole = $pdo->query("SELECT id FROM roles WHERE code = 'supervisor'")->fetchColumn();
20
$pdo->prepare('INSERT INTO users (id,email,password_hash,status,created_at) VALUES (?, ?, ?, ?, UTC_TIMESTAMP()), (?, ?, ?, ?, UTC_TIMESTAMP())')->execute([$owner, 'owner-' . $owner . '@example.test', 'hash', 'active', $target, 'target-' . $target . '@example.test', 'hash', 'active']);
21
$pdo->prepare('INSERT INTO tenant_memberships (id,tenant_id,user_id,role_id,status,created_at) VALUES (?, ?, ?, ?, ?, UTC_TIMESTAMP()), (?, ?, ?, ?, ?, UTC_TIMESTAMP())')->execute([permissionUuid(), $tenantA, $owner, $ownerRole, 'active', permissionUuid(), $tenantA, $target, $supervisorRole, 'active']);
22
$profileId = permissionUuid();
23
$pdo->prepare('INSERT INTO employee_profiles (id,tenant_id,user_id,employee_number,first_name,last_name,email,phone,is_active,created_at,updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, TRUE, UTC_TIMESTAMP(), UTC_TIMESTAMP())')->execute([$profileId, $tenantA, $target, 'P-100', 'Test', 'Mitarbeiter', 'target@example.test', '',]);
24
25
$permissions = new PermissionService($pdo);
26
permissionCheck($permissions->allows($tenantA, 'owner', 'reports.create'), 'owner defaults must allow report creation');
27
permissionCheck($permissions->allows($tenantA, 'technician', 'reports.create') === false, 'technician defaults must deny report creation');
28
permissionCheck($permissions->allows($tenantB, 'office', 'reports.send'), 'tenant defaults must be independent');
29
$changed = $permissions->set($tenantA, $owner, 'owner', 'office', 'reports.send', false);
30
permissionCheck($changed['granted'] === false && $changed['overridden'] === true, 'permission override must be persisted');
31
permissionCheck($permissions->allows($tenantA, 'office', 'reports.send') === false, 'tenant permission override must be enforced');
32
permissionCheck($permissions->allows($tenantB, 'office', 'reports.send'), 'permission override must not cross tenants');
33
try { $permissions->set($tenantA, $target, 'supervisor', 'office', 'reports.send', true); throw new RuntimeException('unauthorized permission change accepted'); } catch (Machweis\Backend\Auth\AuthorizationException) {}
34
35
$employees = new EmployeeProfileService($pdo);
36
$updated = $employees->changeRole($tenantA, $profileId, $owner, 'owner', 'technician');
37
permissionCheck($updated['role'] === 'technician', 'role change must update the active membership');
38
try { $employees->changeRole($tenantA, $profileId, $target, 'technician', 'office'); throw new RuntimeException('unauthorized role change accepted'); } catch (Machweis\Backend\Auth\AuthorizationException) {}
39
40
$company = new CompanyProfileService($pdo);
41
$company->update($tenantA, ['name' => 'Berechtigung A Neu'], $owner);
42
$audit = (new AuditService($pdo))->list($tenantA);
43
$types = array_column($audit, 'event_type');
44
permissionCheck(in_array('permission_changed', $types, true), 'permission changes must be audited');
45
permissionCheck(in_array('role_changed', $types, true), 'role changes must be audited');
46
permissionCheck(in_array('company_profile_updated', $types, true), 'company profile changes must be audited');
47
permissionCheck((new AuditService($pdo))->list($tenantB) === [], 'audit list must remain tenant isolated');
48
49
fwrite(STDOUT, "permissions_contract: OK\n");
50