b29a268b1d
- Move completed plan files to .plans/done/ - Move 18 open plan files to .plans/open/ - Update .gitignore to exclude .verified_plans temp file - Verified all 18 open plans still describe unimplemented issues
74 lines
2.0 KiB
Markdown
74 lines
2.0 KiB
Markdown
# Issue #207: Authorization Middleware Uses instanceof Chains
|
|
|
|
## Problem
|
|
|
|
The `AuthorizationMiddleware::getAdminMethods()` method uses a chain of `instanceof` checks to determine admin-only methods:
|
|
|
|
```php
|
|
private function getAdminMethods($controller): ?array {
|
|
if ($controller instanceof FeeController) {
|
|
return self::ADMIN_METHODS_FEE;
|
|
}
|
|
if ($controller instanceof StufeController) {
|
|
return self::ADMIN_METHODS_STUFE;
|
|
}
|
|
if ($controller instanceof ExportController) {
|
|
return self::ADMIN_METHODS_EXPORT;
|
|
}
|
|
if ($controller instanceof MemberController) {
|
|
return self::ADMIN_METHODS_MEMBER;
|
|
}
|
|
// ... more controllers
|
|
return null;
|
|
}
|
|
```
|
|
|
|
This pattern violates Open/Closed Principle — adding a new controller requires modifying the middleware.
|
|
|
|
## Impact
|
|
|
|
- Hard to maintain as controller count grows
|
|
- Easy to forget to add a new controller to the chain
|
|
- Mixing of concerns (controller identity vs. permissions)
|
|
|
|
## Solution
|
|
|
|
Use PHP attributes to declare permissions on controller methods:
|
|
|
|
```php
|
|
#[Attribute]
|
|
class RequiresAdmin implements \Attribute {}
|
|
|
|
#[RequiresAdmin]
|
|
public function createRule(): JSONResponse { ... }
|
|
```
|
|
|
|
Then scan for attributes in middleware:
|
|
|
|
```php
|
|
public function beforeController($controller, $methodName): void {
|
|
$method = new \ReflectionMethod($controller, $methodName);
|
|
if ($method->getAttributes(RequiresAdmin::class)) {
|
|
if (!$this->permissionService->isAdmin($userId)) {
|
|
throw new \RuntimeException('Authorization: admin required');
|
|
}
|
|
}
|
|
// ... rest of checks
|
|
}
|
|
```
|
|
|
|
## Tasks
|
|
|
|
- [ ] Create `RequiresRead` and `RequiresWrite` attributes
|
|
- [ ] Create `RequiresAdmin` attribute
|
|
- [ ] Add attributes to all controller methods
|
|
- [ ] Refactor `AuthorizationMiddleware` to use reflection + attributes
|
|
- [ ] Remove `ADMIN_METHODS_*` constants and `getAdminMethods()` method
|
|
- [ ] Test all permission levels still work correctly
|
|
|
|
## Labels
|
|
|
|
- refactoring
|
|
- backend
|
|
- priority:medium
|
|
- architecture |