OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

GrantScopeTest.php

3 KB
<?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));
    });
};