bootApp(['oidc_enabled' => true]); } public function testCallbackSuccessSetsSessionAndRedirectsToMe(): void { $this->bindOidcAuthenticator(new class () implements OidcAuthenticator { public function authenticate(): OidcClaims { return new OidcClaims( subject: 'sub-1', email: 'alice@example.com', displayName: 'Alice', groups: ['group-admin'], ); } }); $this->enqueueApiResponse(200, [ 'user_id' => 99, 'role' => 'admin', 'email' => 'alice@example.com', 'display_name' => 'Alice', 'is_local' => false, ]); $response = $this->request('GET', '/oidc/callback'); self::assertSame(302, $response->getStatusCode()); self::assertSame('/app/dashboard', $response->getHeaderLine('Location')); self::assertSame(99, $_SESSION['_user']['user_id'] ?? null); self::assertSame('admin', $_SESSION['_user']['role']); } public function testNoneRoleRedirectsToNoAccess(): void { $this->bindOidcAuthenticator(new class () implements OidcAuthenticator { public function authenticate(): OidcClaims { return new OidcClaims('sub-x', 'x@x', 'X', []); } }); $this->enqueueApiResponse(200, [ 'user_id' => 0, 'role' => 'none', 'email' => 'x@x', 'display_name' => 'X', 'is_local' => false, ]); $response = $this->request('GET', '/oidc/callback'); self::assertSame(302, $response->getStatusCode()); self::assertSame('/no-access', $response->getHeaderLine('Location')); self::assertArrayNotHasKey('_user', $_SESSION); } public function testHandshakeFailureRedirectsToLogin(): void { $this->bindOidcAuthenticator(new class () implements OidcAuthenticator { public function authenticate(): OidcClaims { throw new OidcException('state mismatch'); } }); $response = $this->request('GET', '/oidc/callback'); self::assertSame(302, $response->getStatusCode()); self::assertSame('/login', $response->getHeaderLine('Location')); $flash = $_SESSION['_flash'] ?? []; self::assertNotEmpty($flash); self::assertSame('error', $flash[0]['type']); } public function testApiUnreachableDuringUpsertFlashesAndRedirects(): void { $this->bindOidcAuthenticator(new class () implements OidcAuthenticator { public function authenticate(): OidcClaims { return new OidcClaims('sub-1', null, 'Alice', []); } }); $this->enqueueApiException(new \GuzzleHttp\Exception\ConnectException( 'down', new \GuzzleHttp\Psr7\Request('POST', '/'), )); $this->enqueueApiException(new \GuzzleHttp\Exception\ConnectException( 'down', new \GuzzleHttp\Psr7\Request('POST', '/'), )); $response = $this->request('GET', '/oidc/callback'); self::assertSame(302, $response->getStatusCode()); self::assertSame('/login', $response->getHeaderLine('Location')); } }