M0: Skelett + Auth-Grundgerüst (Keycloak-OIDC + API-Token)
- Symfony 7.4 LTS, PHP 8.4, FrankenPHP, SQLite (3-Layer src/UI|Logic|Data) - Auth: manueller OidcClient (Authorization-Code) im UI-Layer, kein Security-Bundle/league; Session-Gate via SessionAuthSubscriber - API-Guard via statischem X-Api-Token (ApiTokenSubscriber); ExceptionSubscriber - UserEntity (Auto-Provision) + Init-Migration - Docker (php:8.4-frankenphp) + compose (essen.ljh31.de, traefik-net external) - SmokeTests (7) grün: Redirect-Fälle, API-Token, Auth-Render, Logout Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\BrowserKit\Cookie;
|
||||
|
||||
final class SmokeTest extends WebTestCase
|
||||
{
|
||||
private const AUTH_KEYS = [
|
||||
'auth_sub' => 'test-sub',
|
||||
'auth_name' => 'Jens',
|
||||
'auth_email' => 'jens@ljh31.de',
|
||||
];
|
||||
|
||||
private static function client(): KernelBrowser
|
||||
{
|
||||
$client = self::createClient();
|
||||
$client->followRedirects(false);
|
||||
return $client;
|
||||
}
|
||||
|
||||
/** Client, dessen Session bereits eine eingeloggte Identität enthält. */
|
||||
private static function authedClient(): KernelBrowser
|
||||
{
|
||||
$client = self::client();
|
||||
$session = self::getContainer()->get('session.factory')->createSession();
|
||||
$session->start();
|
||||
foreach (self::AUTH_KEYS as $k => $v) {
|
||||
$session->set($k, $v);
|
||||
}
|
||||
$session->save();
|
||||
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
|
||||
return $client;
|
||||
}
|
||||
|
||||
public function testRootRedirectsToLoginWithoutSession(): void
|
||||
{
|
||||
self::client()->request('GET', '/');
|
||||
|
||||
self::assertResponseStatusCodeSame(302);
|
||||
self::assertResponseRedirects('/login?redirect=/');
|
||||
}
|
||||
|
||||
public function testLoginRedirectsToKeycloakAuthorizeEndpoint(): void
|
||||
{
|
||||
$client = self::client();
|
||||
$client->request('GET', '/login');
|
||||
|
||||
self::assertResponseStatusCodeSame(302);
|
||||
$location = (string) $client->getResponse()->headers->get('Location');
|
||||
self::assertStringContainsString('/protocol/openid-connect/auth', $location);
|
||||
self::assertStringContainsString('client_id=essens-test', $location);
|
||||
}
|
||||
|
||||
public function testCallbackWithWrongStateRedirectsBackToLogin(): void
|
||||
{
|
||||
self::client()->request('GET', '/auth/callback?code=xyz&state=falsch-state');
|
||||
|
||||
self::assertResponseStatusCodeSame(302);
|
||||
self::assertResponseRedirects('/login');
|
||||
}
|
||||
|
||||
public function testApiWithoutTokenReturns401Json(): void
|
||||
{
|
||||
$client = self::client();
|
||||
$client->request('GET', '/api/today');
|
||||
|
||||
self::assertResponseStatusCodeSame(401);
|
||||
$body = json_decode((string) $client->getResponse()->getContent(), true);
|
||||
self::assertIsArray($body);
|
||||
self::assertArrayHasKey('error', $body);
|
||||
}
|
||||
|
||||
public function testApiWithValidTokenGets404Not401(): void
|
||||
{
|
||||
// /api/today existiert in M0 noch nicht (M4) → Guard lässt durch, Router gibt 404.
|
||||
$client = self::client();
|
||||
$client->request('GET', '/api/today', server: ['HTTP_X_API_TOKEN' => 'test-api-token']);
|
||||
|
||||
self::assertSame(404, $client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testRootRendersForAuthenticatedSession(): void
|
||||
{
|
||||
self::authedClient()->request('GET', '/');
|
||||
|
||||
self::assertResponseIsSuccessful();
|
||||
self::assertSelectorTextContains('h1', 'Jens');
|
||||
}
|
||||
|
||||
public function testLogoutRedirectsToLogin(): void
|
||||
{
|
||||
self::authedClient()->request('GET', '/logout');
|
||||
|
||||
self::assertResponseStatusCodeSame(302);
|
||||
self::assertResponseRedirects('/login');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user