Files
michaelschiemer/docs/claude/route-authorization.md
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

292 lines
7.8 KiB
Markdown

# 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)