security: Rechteausweitung schließen & Admin-Panel feingranular gaten (K1, H1, H2, M8)

- users:manage/roles:manage auf allen User-/Rollen-Masken erzwungen;
  is_super_admin aus $fillable entfernt und nur per autorisiertem
  forceFill setzbar; zentraler Gate::before-Super-Admin-Kurzschluss (K1/M8).
- Nicht-Super-Admins können Super-Admin-Konten nicht mehr bearbeiten (Fix#2);
  Impersonation mit Rangprüfung, keine Token-Erstellung während Impersonation (H1).
- Destruktive/verwaltende Admin-Aktionen (CRM/Billing/Compliance/Struktur)
  hängen an neuen admin-only Permissions; Editor behält reine Content-Rechte (H2).
- Kanonischer Permission-Katalog (App\Authorization\Permission) als Single
  Source of Truth für Seeder und Monitoring.

Deployment: `php artisan db:seed --class=RolesAndPermissionsSeeder` auf allen
Umgebungen ausführen (neue Permissions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-14 13:48:50 +00:00
parent 39e13d6d84
commit 77f8f9cb35
34 changed files with 748 additions and 100 deletions

View file

@ -70,6 +70,8 @@ new #[Layout('components.layouts.app'), Title('Benutzer anlegen')] class extends
public function mount(): void
{
$this->authorize('users:manage');
$this->portal = Portal::Both->value;
$this->registrationType = RegistrationType::ExistingLegacy->value;
}
@ -110,6 +112,8 @@ new #[Layout('components.layouts.app'), Title('Benutzer anlegen')] class extends
public function save(): void
{
$this->authorize('users:manage');
$validated = $this->validate([
...$this->userIdentityRules(),
...$this->userRolesAndCompaniesRules(),
@ -124,10 +128,15 @@ new #[Layout('components.layouts.app'), Title('Benutzer anlegen')] class extends
'registration_type' => $validated['registrationType'],
'language' => $validated['language'],
'is_active' => $this->isActive,
'is_super_admin' => $this->isSuperAdmin,
'password' => null,
]);
// Super-Admin-Rang darf nur ein Super-Admin vergeben (is_super_admin ist
// nicht mass-assignable, siehe User::$fillable).
if ($this->isSuperAdmin && auth()->user()->is_super_admin) {
$user->forceFill(['is_super_admin' => true])->save();
}
$user->syncRoles($validated['selectedRoles']);
$user->syncCompaniesWithRoles($validated['linkedCompanyIds'], $validated['companyRoles']);