Quelltext des aktuellen Standes
<?php
declare(strict_types=1);
use OpenNIT\Authorization\AccessControl;
/**
* Deckt die Weitergabe von Rechten über Rollenzuweisungen ab.
*
* Eine Zuweisung trägt immer den Geltungsbereich, den der Vergebende wählt.
* Standortgebundene Rechte darf deshalb nur weitergeben, wer sie selbst
* uneingeschränkt besitzt – sonst ließe sich die eigene Standortgrenze durch
* eine globale Selbstzuweisung derselben Rolle aufheben.
*/
return static function (): void {
/**
* Erzeugt eine AccessControl-Instanz mit vorgegebenem Rechtebestand.
*
* @param string[] $effektiv Namen der effektiv besitzten Rechte
* @param array<string,true|int[]> $standort Standort-Zugriff je Rechtename
*/
$bau = static function (array $effektiv, array $standort): AccessControl {
$checker = new class ($effektiv, $standort) extends \OpenNIT\Authorization\CapabilityChecker {
public function __construct(private array $effektiv, private array $standort)
{
// Keine Datenbank nötig – die beiden gefragten Methoden antworten selbst.
}
public function getUserCapabilities(int $userId, ?int $topicId = null): array
{
return array_map(static fn(string $n): array => ['name' => $n], $this->effektiv);
}
public function locationAccess(int $userId, string $capability)
{
return $this->standort[$capability] ?? [];
}
};
$klasse = new ReflectionClass(AccessControl::class);
$ac = $klasse->newInstanceWithoutConstructor();
$feld = $klasse->getProperty('capabilityChecker');
$feld->setAccessible(true);
$feld->setValue($ac, $checker);
return $ac;
};
test('Ein global vergebenes Standortrecht bleibt weitergebbar', function () use ($bau) {
$ac = $bau(
['manage_users', 'manage_tickets', 'manage_assets'],
['manage_tickets' => true, 'manage_assets' => true]
);
$namen = $ac->getGrantableCapabilityNames(1);
assertTrue(in_array('manage_tickets', $namen, true));
assertTrue(in_array('manage_assets', $namen, true));
});
test('Ein nur für Standorte vergebenes Recht ist nicht weitergebbar', function () use ($bau) {
// Der Akteur verwaltet Tickets nur an Standort 5 – global vergeben würde
// die Zuweisung ihm selbst Zugriff auf alle Standorte verschaffen.
$ac = $bau(
['manage_users', 'manage_tickets'],
['manage_tickets' => [5, 9]]
);
$namen = $ac->getGrantableCapabilityNames(1);
assertFalse(in_array('manage_tickets', $namen, true));
// Die effektiv besitzten Rechte bleiben davon unberührt – sie steuern
// unter anderem die Auswahl startbarer Workflows.
assertTrue(in_array('manage_tickets', $ac->getOwnedCapabilityNames(1), true));
});
test('Rechte ohne Standortbezug bleiben unverändert weitergebbar', function () use ($bau) {
$ac = $bau(['manage_users', 'manage_contracts', 'view_budgets'], []);
assertSame(
['manage_users', 'manage_contracts', 'view_budgets'],
$ac->getGrantableCapabilityNames(1)
);
});
test('Ohne Standortrecht irgendwo bleibt die Liste leer statt global', function () use ($bau) {
$ac = $bau(['view_assets'], ['view_assets' => []]);
assertSame([], $ac->getGrantableCapabilityNames(1));
});
};