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