# Route Authorization System Dokumentation des namespace-basierten Route Authorization Systems. ## Übersicht Das Route Authorization System ermöglicht die Zugangskontrolle für Routes auf Basis von: 1. **Legacy `#[Auth]` Attribute** - Backward compatibility 2. **Namespace-basierte Blockierung** - Blockiere ganze Controller-Namespaces (z.B. `App\Application\Admin\*`) 3. **Namespace-basierte IP-Restrictions** - IP-basierte Zugriffskontrolle per Namespace 4. **Route-spezifische `#[IpAuth]` Attribute** - Feinkörnige IP-Kontrolle per Route ## Architektur ``` RouteAuthorizationService ├── checkLegacyAuthAttribute() ├── checkNamespaceAccessPolicy() [NEU] ├── checkNamespaceIpRestrictions() └── checkRouteIpAuthAttribute() ``` Der Service wird in der `RoutingMiddleware` **nach dem Routing** aufgerufen, sodass die gematchte Route bekannt ist. ## Konfiguration ### Initializer-basierte Konfiguration **Location**: `src/Framework/Auth/RouteAuthorizationServiceInitializer.php` ```php #[Initializer] public function __invoke(Container $container): RouteAuthorizationService { $namespaceConfig = [ // Namespace Pattern => Configuration 'App\Application\Admin\*' => [ 'visibility' => 'admin', // IP-based restriction 'access_policy' => NamespaceAccessPolicy::blocked() ], ]; return new RouteAuthorizationService( config: $this->config, namespaceConfig: $namespaceConfig ); } ``` ### Namespace Patterns **Wildcard-basierte Patterns**: - `App\Application\Admin\*` - Matched alle Admin-Controller - `App\Application\Api\*` - Matched alle API-Controller - `App\Application\*` - Matched alle Application-Controller **Exact Match**: - `App\Application\Admin\Dashboard` - Nur exakt dieser Namespace ## Use Cases ### 1. Admin-Bereich komplett blockieren ```php $namespaceConfig = [ 'App\Application\Admin\*' => [ 'access_policy' => NamespaceAccessPolicy::blocked() ], ]; ``` **Ergebnis**: Alle Admin-Controller werfen `RouteNotFound` (404) ### 2. Admin-Bereich mit Allowlist ```php use App\Application\Admin\LoginController; use App\Application\Admin\HealthCheckController; $namespaceConfig = [ 'App\Application\Admin\*' => [ 'access_policy' => NamespaceAccessPolicy::blockedExcept( LoginController::class, HealthCheckController::class ) ], ]; ``` **Ergebnis**: - ✅ `LoginController` und `HealthCheckController` öffentlich erreichbar - ❌ Alle anderen Admin-Controller blockiert ### 3. Kombination: IP-Restriction + Namespace-Blocking ```php $namespaceConfig = [ 'App\Application\Admin\*' => [ 'visibility' => 'admin', // Nur Admin-IPs erlaubt 'access_policy' => NamespaceAccessPolicy::blockedExcept( LoginController::class // Aber Login ist public ) ], ]; ``` **Ergebnis**: - ✅ `LoginController` - öffentlich erreichbar (trotz admin visibility) - 🔒 Alle anderen Admin-Controller - nur von Admin-IPs ### 4. API-Bereich mit IP-Restriction (ohne Blocking) ```php $namespaceConfig = [ 'App\Application\Api\*' => [ 'visibility' => 'local', // Nur localhost/private IPs // Kein access_policy - keine Namespace-Blockierung ], ]; ``` **Ergebnis**: API nur von localhost/private IPs erreichbar ### 5. Mehrere Namespace-Policies ```php $namespaceConfig = [ // Admin komplett gesperrt 'App\Application\Admin\*' => [ 'access_policy' => NamespaceAccessPolicy::blocked() ], // API nur von localhost 'App\Application\Api\*' => [ 'visibility' => 'local' ], // Internal Tools nur admin IPs 'App\Application\Internal\*' => [ 'visibility' => 'admin', 'access_policy' => NamespaceAccessPolicy::blocked() ], ]; ``` ## Value Objects ### NamespaceAccessPolicy ```php // Alle Controller im Namespace blockieren NamespaceAccessPolicy::blocked() // Alle blockieren außer spezifische Controller NamespaceAccessPolicy::blockedExcept( LoginController::class, HealthCheckController::class ) // Alle erlauben (default) NamespaceAccessPolicy::allowed() // Prüfen ob Controller blockiert ist $policy->isControllerBlocked(Dashboard::class) // true/false ``` ## Visibility Modes (IP-Restrictions) **Predefined Modes**: - `public` - Keine IP-Restrictions - `admin` - Nur Admin-IPs (WireGuard, etc.) - `local` - Nur localhost/127.0.0.1 - `development` - Development-IPs - `private` - Alias für `local` - `custom` - Custom IP-Liste via Config ## Execution Order 1. **Legacy Auth Attribute** - Backward compatibility check 2. **Namespace Access Policy** - Block/Allow basierend auf Controller-Klasse 3. **Namespace IP Restrictions** - IP-basierte Zugriffskontrolle 4. **Route IP Auth Attribute** - Feinkörnige Route-Level IP-Kontrolle Alle Checks werfen `RouteNotFound` bei Failure (versteckt Route-Existenz). ## Testing ### Unit Test Beispiel ```php use App\Framework\Auth\RouteAuthorizationService; use App\Framework\Auth\ValueObjects\NamespaceAccessPolicy; it('blocks admin controllers except allowlist', function () { $config = ['App\Application\Admin\*' => [ 'access_policy' => NamespaceAccessPolicy::blockedExcept( LoginController::class ) ]]; $service = new RouteAuthorizationService( config: $this->config, namespaceConfig: $config ); // Should throw RouteNotFound for Dashboard expect(fn() => $service->authorize($request, $dashboardRoute)) ->toThrow(RouteNotFound::class); // Should allow LoginController expect(fn() => $service->authorize($request, $loginRoute)) ->not->toThrow(RouteNotFound::class); }); ``` ## Best Practices ### 1. Namespace-Blocking für Production - Blockiere Admin/Internal-Bereiche in Production - Nutze Allowlist nur für wirklich öffentliche Endpoints (Login, Health) ### 2. IP-Restrictions für Sensitive Bereiche - Kombiniere Namespace-Blocking mit IP-Restrictions - Nutze `visibility: 'admin'` für maximale Sicherheit ### 3. Graceful Error Handling - Alle Checks werfen `RouteNotFound` (404) - Versteckt Route-Existenz vor Angreifern - Keine Information Leakage ### 4. Konfiguration via Initializer - Zentrale Konfiguration in `RouteAuthorizationServiceInitializer` - Environment-spezifische Configs möglich (dev vs. production) - Type-safe via Value Objects ## Migration Guide ### Von altem System (RoutingMiddleware::withNamespaceConfig) **Alt**: ```php RoutingMiddleware::withNamespaceConfig( $router, $dispatcher, $config, $performance, $container, namespaceConfig: [ 'App\Application\Admin\*' => ['visibility' => 'admin'] ] ); ``` **Neu**: ```php // In RouteAuthorizationServiceInitializer $namespaceConfig = [ 'App\Application\Admin\*' => [ 'visibility' => 'admin', 'access_policy' => NamespaceAccessPolicy::blocked() // NEU ] ]; ``` ## Troubleshooting ### Problem: Route wirft 404 obwohl sie erreichbar sein sollte **Debugging**: 1. Prüfe `RouteAuthorizationServiceInitializer` Config 2. Check ob Controller-Namespace in `namespaceConfig` matched 3. Prüfe `access_policy` - ist Controller in Allowlist? 4. Check IP-Restrictions (`visibility`) ### Problem: Allowlist funktioniert nicht **Ursache**: Controller-Klasse exakt mit `::class` angeben ```php // ❌ Falsch NamespaceAccessPolicy::blockedExcept('LoginController') // ✅ Korrekt NamespaceAccessPolicy::blockedExcept( \App\Application\Admin\LoginController::class ) ``` ## Framework Integration - **Automatic Discovery**: Service wird via `#[Initializer]` automatisch registriert - **DI Container**: Alle Dependencies werden automatisch injected - **Type Safety**: Value Objects für alle Policies - **Readonly Classes**: Unveränderliche Policies für Thread-Safety - **Framework-konform**: Nutzt bestehende Patterns (IpAuthPolicy, RouteNotFound)