previousSession = $_SESSION ?? []; $_SESSION = []; } protected function tearDown(): void { $_SESSION = $this->previousSession; parent::tearDown(); } public function testStoreAndConsumeIsSingleUse(): void { $store = new MicrosoftOidcStateStoreService(new SessionStore(), 600, 50); $store->store('state-a', ['tenant_id' => 5, 'nonce' => 'n1']); $first = $store->consume('state-a'); $this->assertTrue($first['ok']); $this->assertSame(5, (int) (($first['entry']['tenant_id'] ?? 0))); $second = $store->consume('state-a'); $this->assertFalse($second['ok']); $this->assertSame('state_invalid', (string) $second['error']); } public function testConsumeReturnsExpiredForOldState(): void { $store = new MicrosoftOidcStateStoreService(new SessionStore(), 1, 50); $store->store('state-old', [ 'tenant_id' => 9, 'created_at' => time() - 120, ]); $result = $store->consume('state-old'); $this->assertFalse($result['ok']); $this->assertSame('state_expired', (string) $result['error']); } public function testStoreRespectsMaxEntriesAndPrunesOldStates(): void { $store = new MicrosoftOidcStateStoreService(new SessionStore(), 600, 2); $store->store('state-1', ['created_at' => time() - 3]); $store->store('state-2', ['created_at' => time() - 2]); $store->store('state-3', ['created_at' => time() - 1]); $invalid = $store->consume('state-1'); $this->assertFalse($invalid['ok']); $this->assertSame('state_invalid', (string) $invalid['error']); $valid2 = $store->consume('state-2'); $this->assertTrue($valid2['ok']); $valid3 = $store->consume('state-3'); $this->assertTrue($valid3['ok']); } }