// @ts-check // Fix #147: Vor der Änderung konnte jeder eingeloggte Benutzer über // /useradmin beliebige Konten anlegen, Passwörter setzen oder löschen // (Privilege Escalation). Dieser Test prüft die Durchsetzung auf HTTP-Ebene, // die die PHP-Suite nicht erreicht (Router-Guard, Redirect, Nav-Rendering). const { test, expect } = require('@playwright/test') const { uniqueTag, gotoOk, acceptDialogs } = require('../helpers/app') test.describe('Autorisierung: Benutzerverwaltung nur für Admins (Fix #147)', () => { test('Neu angelegter Benutzer ohne Admin-Rolle wird von /useradmin ausgesperrt', async ({ page, browser }) => { const username = uniqueTag('noadmin').toLowerCase().replace(/[^a-z0-9-]/g, '').slice(0, 64) const password = 'TempPass123!' await gotoOk(page, '/useradmin') await page.fill('#field-username', username) await page.fill('#field-password', password) await page.click('#submit-btn') await page.waitForURL('/useradmin') await expect(page.locator('body')).toContainText('Benutzer angelegt.') const row = page.locator('tr', { hasText: username }) await expect(row).toBeVisible() try { // Eigener, unangemeldeter Kontext: Der neu angelegte Benutzer meldet // sich selbst an und ist per Default kein Admin. const context = await browser.newContext({ storageState: { cookies: [], origins: [] } }) const userPage = await context.newPage() await userPage.goto('/login') await userPage.fill('#username', username) await userPage.fill('#password', password) await userPage.click('form[action="/login"] button[type="submit"]') await userPage.waitForURL(url => !url.pathname.startsWith('/login')) // Kosmetischer Schutz: der Nav-Link ist für Nicht-Admins ausgeblendet. await expect(userPage.locator('a[href="/useradmin"]')).toHaveCount(0) // Serverseitige Durchsetzung: direkter Aufruf bleibt trotzdem gesperrt. const response = await userPage.goto('/useradmin') expect(response?.status()).toBe(403) await expect(userPage.locator('body')).toContainText('Kein Zugriff') await context.close() } finally { acceptDialogs(page) const delForm = row.locator('form[action$="/delete"]') if (await delForm.count() > 0) { await delForm.locator('button[type="submit"]').click() await page.waitForLoadState('networkidle') } } }) })