Leitfaden zu Berechtigungen & Sicherheit
Time cockpit setzt ein ausgefeiltes, mehrschichtiges Sicherheitssystem um, das rollenbasierte Zugriffskontrolle (RBAC) mit Sicherheit auf Zeilenebene (RLS) kombiniert und dafür dynamische Named Sets und Berechtigungsbedingungen verwendet.
Überblick über die Sicherheitsarchitektur
graph TD
User[Benutzer] --> UserDetail[APP_UserDetail]
UserDetail --> Roles[APP_UserDetailRole]
Roles --> Role[APP_UserRole]
Role --> Permissions[Berechtigungen auf Entitäten]
Permissions --> EntityPerm[Berechtigungen auf Entitätsebene]
Permissions --> PropertyPerm[Berechtigungen auf Eigenschaftsebene]
EntityPerm --> AccessTypes[Read/Write/Execute/Allowed]
EntityPerm --> Conditions[Berechtigungsbedingungen]
Conditions --> NamedSets[Named Sets]
Conditions --> TCQL[TCQL-Ausdrücke]
NamedSets --> DynamicData[Dynamische Auswertung der Daten]
TCQL --> CurrentUser[Environment.CurrentUser]
TCQL --> RowData[Daten der aktuellen Zeile]
Grundbegriffe der Berechtigungen
1. Zugriffsarten
Jede Berechtigung legt fest, welche Operationen sie steuert. Die zugrunde liegende Enumeration enthält sowohl das kombinierte Flag Write als auch die einzelnen CRUD-Bit-Flags:
| Zugriffsart | Wert | Beschreibung |
|---|---|---|
| Read | 1 | Daten der Entität anzeigen |
| Insert | 2 | Neue Datensätze anlegen; in Write enthalten |
| Update | 4 | Bestehende Datensätze ändern; in Write enthalten |
| Delete | 8 | Datensätze entfernen; in Write enthalten |
| Write | 15 | Kombinierte Schreibberechtigung für Daten; umfasst Read, Insert, Update und Delete |
| Execute | 16 | Aktionen ausführen; wird für Berechtigungen zur Ausführung von Aktionen verwendet |
| Allowed | 32 | Allgemeine Funktionsberechtigung, die vom Framework verwendet wird |
In der Dokumentation und in der Konfiguration von Mandanten sind die häufigsten Berechtigungsarten APP_ReadPermission, APP_WritePermission und die aktionsspezifische APP_ExecutePermission.
2. Ablauf der Berechtigungsprüfung
flowchart LR
Request[Anfrage des Benutzers] --> CheckEntity{Berechtigung<br/>für Entität<br/>definiert?}
CheckEntity -->|Keine Berechtigung| Deny[Zugriff verweigert]
CheckEntity -->|Berechtigungen vorhanden| EvalCondition{Jede Bedingung<br/>auswerten<br/>inkl. optionaler Rollenprüfung}
EvalCondition -->|Alle False| Deny
EvalCondition -->|Eine True\nODER-Semantik| CheckRow{Sicherheit auf<br/>Zeilenebene?}
CheckRow -->|Nicht erfüllt| DenyRow[Zugriff auf Zeile verweigert]
CheckRow -->|Erfüllt| Allow[Zugriff gewährt]
Mehrere Berechtigungen werden mit ODER verknüpft: Sind für eine Entität und Zugriffsart mehrere Berechtigungen definiert, wird der Zugriff gewährt, sobald irgendeine Bedingung
Trueergibt.
3. Named Sets
Named Sets sind dynamische Abfragen, die zur Laufzeit ausgewertet werden und so eine kontextabhängige Sicherheit ermöglichen:
Zweck: Listen von Entitäten vorab berechnen, auf die der aktuelle Benutzer zugreifen darf Auswertung: Erfolgt bei der Prüfung der Berechtigung Caching: Ergebnisse werden aus Performancegründen pro Anfrage zwischengespeichert
Standardrollen
Time cockpit enthält vordefinierte Rollen mit bestimmten Befugnissen:
Administratorrollen
BillingAdmin
- Vollzugriff auf Rechnungslegung, Projekte und Kunden
- Kann Rechnungen anlegen, bearbeiten und löschen
- Sieht alle Zeitbuchungen für die Verrechnung
-- Example: Invoice write permission
'BillingAdmin' In Set('CurrentUserRoles')
HumanResourcesAdmin
- Verwaltet Benutzer, Abteilungen und Arbeitszeit
- Genehmigt Abwesenheiten (Urlaub, Krankenstand)
- Sieht alle Mitarbeiterdaten
-- Example: UserDetail full access
'HumanResourcesAdmin' In Set('CurrentUserRoles')
BaseDataAdmin
- Verwaltet Stammdaten (Artikel, Einheiten, Kunden)
- Kann nicht auf Finanz- oder Mitarbeiterdaten zugreifen
- Pflegt Referenztabellen
Managerrollen
ProjectManager
- Sieht die Projekte, die er leitet
- Sieht die Zeitbuchungen auf seinen Projekten
- Kann Zeitbuchungen anderer nicht ändern
-- Example: Project manager sees their projects
'ProjectManager' In Set('CurrentUserRoles') And
(Current.APP_Manager1 = Environment.CurrentUser.UserDetailUuid Or
Current.APP_Manager2 = Environment.CurrentUser.UserDetailUuid)
DepartmentLead
- Verwaltet die Mitarbeiter der Abteilung
- Genehmigt Abwesenheiten für seine Abteilung
- Sieht die Zeitbuchungen der Abteilung
-- Named Set: APP_MyDepartmentsAsLead
From DL In APP_DepartmentLead
Where DL.APP_UserDetail = Environment.CurrentUser.UserDetailUuid
Select DL.APP_Department
-- Permission condition: Department lead sees their department
Current.APP_Department In Set('APP_MyDepartmentsAsLead')
Standardbenutzer
User (Basisrolle)
- Legt eigene Zeitbuchungen an
- Sieht nur eigene Daten
- Stellt Urlaubsanträge
Häufige Berechtigungsmuster
Muster 1: Eigene Daten + Administratoren
Anwendungsfall: Benutzer sehen ihre eigenen Datensätze, Administratoren sehen alle
Beispiel: Zeitbuchungen
:Iif(
'BillingAdmin' In Set('CurrentUserRoles') Or
'HumanResourcesAdmin' In Set('CurrentUserRoles'),
True, -- Admins see everything
Current.APP_UserDetail = Environment.CurrentUser.UserDetailUuid -- Users see own
) = True
Beispiel: Urlaubsanträge
:Iif(
'HumanResourcesAdmin' In Set('CurrentUserRoles'),
True, -- HR sees all absences
Current.APP_UserDetail = Environment.CurrentUser.UserDetailUuid -- Users see own
) = True
Muster 2: Hierarchischer Zugriff für Vorgesetzte
Anwendungsfall: Vorgesetzte sehen die Daten ihrer Mitarbeiter
Beispiel: Zugriff auf Zeitbuchungen nach Abteilung
:Iif(
'HumanResourcesAdmin' In Set('CurrentUserRoles'),
True, -- HR admin sees all
:Iif(
Current.APP_UserDetail = Environment.CurrentUser.UserDetailUuid,
True, -- Users see own timesheets
:Iif(
'DepartmentLead' In Set('CurrentUserRoles') And
Current.APP_UserDetail.APP_Department In Set('APP_MyDepartmentsAsLead'),
True, -- Department leads see their department
False
)
)
) = True
Muster 3: Projektbezogener Zugriff
Anwendungsfall: Projektleiter greifen auf projektbezogene Daten zu
Beispiel: Sichtbarkeit der Zeitbuchungen eines Projekts
:Iif(
'BillingAdmin' In Set('CurrentUserRoles'),
True,
:Iif(
Current.APP_UserDetail = Environment.CurrentUser.UserDetailUuid,
True, -- Own timesheets
:Iif(
'ProjectManager' In Set('CurrentUserRoles') And
(Current.APP_Project.APP_Manager1 = Environment.CurrentUser.UserDetailUuid Or
Current.APP_Project.APP_Manager2 = Environment.CurrentUser.UserDetailUuid),
True, -- Project manager's projects
False
)
)
) = True
Muster 4: Bedingter Schreibzugriff
Anwendungsfall: Änderungen abhängig vom Status einschränken
Beispiel: Verrechnete Zeitbuchungen können nicht bearbeitet werden
-- Read permission: see timesheet
'BillingAdmin' In Set('CurrentUserRoles') Or
Current.APP_UserDetail = Environment.CurrentUser.UserDetailUuid
-- Write permission: can only edit if not billed
:Iif(
'BillingAdmin' In Set('CurrentUserRoles'),
True, -- Admins can edit anything
:Iif(
Current.APP_UserDetail = Environment.CurrentUser.UserDetailUuid And
Current.APP_Billed = False, -- Not yet invoiced
True,
False
)
) = True
Beispiel: Nur eigene Zeitbuchungen abschließen
-- APP_DeviatingBookingCompletionDate property permission
:Iif(
'HumanResourcesAdmin' In Set('CurrentUserRoles'),
True,
:Iif(
Current.APP_UserDetailUuid = Environment.CurrentUser.UserDetailUuid And
(Current.APP_AllowDeviatingBookingCompletionDateUntil = Null Or
Current.APP_AllowDeviatingBookingCompletionDateUntil >= :Today()),
True,
False
)
) = True
Muster 5: Abhängig von Feature Flags
Anwendungsfall: Berechtigungen abhängig von Mandanteneinstellungen aktivieren oder deaktivieren
-- Disable default permissions if feature flag is off
:Iif(:IsFeatureFlagEnabled('APP_DefaultPermissions'), False, True)
Referenz der Named Sets
Integrierte Named Sets
CurrentUserRoles
Liefert die Rollen, die dem aktuellen Benutzer zugewiesen sind.
-- Definition
From R In APP_UserDetailRole
Where
R.APP_UserDetail = Environment.CurrentUser.UserDetailUuid
And (R.APP_ValidFrom = Null Or R.APP_ValidFrom <= :Today())
And (R.APP_ValidTo = Null Or R.APP_ValidTo >= :Today())
Select New With { R.APP_UserRole.APP_Code }
-- Usage
'BillingAdmin' In Set('CurrentUserRoles')
APP_MyDepartmentsAsLead
Liefert die Abteilungen, in denen der aktuelle Benutzer Abteilungsleiter ist.
-- Definition
From DL In APP_DepartmentLead
Where
DL.APP_UserDetail = Environment.CurrentUser.UserDetailUuid
Select DL.APP_Department
-- Usage
Current.APP_Department In Set('APP_MyDepartmentsAsLead')
APP_MyManagedProjects
Liefert die Projekte, bei denen der aktuelle Benutzer Manager1 oder Manager2 ist.
-- Definition
From P In APP_Project
Where
P.APP_Manager1 = Environment.CurrentUser.UserDetailUuid Or
P.APP_Manager2 = Environment.CurrentUser.UserDetailUuid
Select P
-- Usage
Current.APP_Project In Set('APP_MyManagedProjects')
Eigene Named Sets erstellen
Named Sets lassen sich programmgesteuert erstellen, um eigene Sicherheitsszenarien zu unterstützen:
Beispiel: Projekte, auf die der Benutzer Zeit gebucht hat
-- Named Set: APP_MyProjectsWithTime
From T In APP_Timesheet
Where T.APP_UserDetail = Environment.CurrentUser.UserDetailUuid
Select Distinct T.APP_Project
Berechtigungen auf Eigenschaftsebene
Schränken Sie den Zugriff auf bestimmte Eigenschaften (Felder) innerhalb einer Entität ein.
Anwendungsfall: Gehaltsinformationen vor Benutzern außerhalb von HR verbergen
-- APP_UserDetail.APP_HourlyRate property permission
:Iif(
'HumanResourcesAdmin' In Set('CurrentUserRoles') Or
'BillingAdmin' In Set('CurrentUserRoles'),
True, -- Admins can see/edit hourly rate
:Iif(
Current.APP_UserDetailUuid = Environment.CurrentUser.UserDetailUuid,
True, -- Users can see their own rate
False -- Others cannot see
)
) = True
Anwendungsfall: Rechnungsnummern nach dem Anlegen sperren
-- APP_Invoice.APP_InvoiceNumber - read-only after set
:Iif(
Current.APP_InvoiceNumberIsSet = True,
True, -- Read-only if already set
False -- Editable before set
)
Berechtigungen für Aktionen
Legen Sie fest, wer bestimmte Aktionen ausführen darf (z. B. Ausgangsrechnung anlegen, Urlaub genehmigen).
Beispiel: Rechnungslegung nur für Abrechnungsadministratoren
-- APP_CreateInvoiceAction execute permission
:Iif('BillingAdmin' In Set('CurrentUserRoles'), True, False) = True
Beispiel: Abteilungsleiter genehmigen Abwesenheiten
-- APP_ApproveAbsenceAction
-- Implemented in action code - checks department membership
'DepartmentLead' In Set('CurrentUserRoles') Or
'HumanResourcesAdmin' In Set('CurrentUserRoles')
Best Practices für die Sicherheit
1. Prinzip der minimalen Rechte
❌ Schlecht: Weitreichenden Zugriff gewähren
'User' In Set('CurrentUserRoles') -- Too permissive
✅ Gut: Gezielten Zugriff gewähren
:Iif(
'BillingAdmin' In Set('CurrentUserRoles'),
True,
Current.APP_UserDetail = Environment.CurrentUser.UserDetailUuid
) = True
2. Named Sets für komplexe Logik verwenden
❌ Schlecht: Komplexe Abfragen in jeder Berechtigung wiederholen
-- Repeated in multiple permissions
(From DL In APP_DepartmentLead
Where DL.APP_UserDetail = Environment.CurrentUser.UserDetailUuid
Select DL.APP_Department) Contains Current.APP_Department
✅ Gut: Einmal als Named Set definieren
Current.APP_Department In Set('APP_MyDepartmentsAsLead')
3. Grenzen der Berechtigungen testen
Testen Sie immer:
- ✅ Benutzer können auf ihre eigenen Daten zugreifen
- ✅ Benutzer können NICHT auf Daten anderer zugreifen
- ✅ Vorgesetzte können auf die Daten ihrer Mitarbeiter zugreifen
- ✅ Vorgesetzte können NICHT auf die Daten gleichrangiger Kollegen zugreifen
- ✅ Administratoren können auf alles zugreifen
4. Eigene Berechtigungen dokumentieren
/* Permission: ProjectManagerReadAccess
Purpose: Project managers see timesheets on projects they manage
Roles: ProjectManager, BillingAdmin
Condition: User is Manager1 or Manager2 of the project */
:Iif(
'BillingAdmin' In Set('CurrentUserRoles'),
True,
:Iif(
'ProjectManager' In Set('CurrentUserRoles') And
(Current.APP_Project.APP_Manager1 = Environment.CurrentUser.UserDetailUuid Or
Current.APP_Project.APP_Manager2 = Environment.CurrentUser.UserDetailUuid),
True,
False
)
) = True
5. Änderungen an Berechtigungen nachvollziehen
Wenn Sie Berechtigungen ändern:
- Dokumentieren Sie die Änderung und den Grund
- Testen Sie mit den betroffenen Benutzerrollen
- Stimmen Sie die Änderung mit dem Sicherheits- bzw. Compliance-Team ab
- Beobachten Sie, ob unbeabsichtigte Zugriffsmuster auftreten
Fehlerbehebung bei Berechtigungen
Fehler „Zugriff verweigert“
Schritt 1: Ermitteln Sie, welche Berechtigung fehlgeschlagen ist
- Auf Entitätsebene? (Die Entität kann gar nicht gelesen oder geschrieben werden)
- Auf Zeilenebene? (Einige Datensätze sind sichtbar, dieser aber nicht)
- Auf Eigenschaftsebene? (Ein bestimmtes Feld kann nicht angezeigt oder bearbeitet werden)
- Berechtigung für Aktionen? (Die Aktion kann nicht ausgeführt werden)
Schritt 2: Prüfen Sie die Rollen des Benutzers
-- Query current user's roles
From R In APP_UserDetailRole
Where R.APP_UserDetail = Environment.CurrentUser.UserDetailUuid
And (R.APP_ValidFrom = Null Or R.APP_ValidFrom <= :Today())
And (R.APP_ValidTo = Null Or R.APP_ValidTo >= :Today())
Select R.APP_UserRole.APP_Code
Schritt 3: Werten Sie die Berechtigungsbedingung manuell aus
Testen Sie die Bedingung mit bekannten Werten:
- Ersetzen Sie
Environment.CurrentUser.UserDetailUuiddurch die tatsächliche UUID - Ersetzen Sie
Current.XXXdurch die tatsächlichen Werte des Datensatzes - Prüfen Sie die Ergebnisse der Named Sets
Schritt 4: Prüfen Sie die Feature Flags
-- Is default permissions enabled?
:IsFeatureFlagEnabled('APP_DefaultPermissions')
Berechtigung funktioniert nicht wie erwartet
Häufige Ursachen:
Rolle nicht zugewiesen: Der Benutzer hat die erforderliche Rolle nicht
- Lösung: Rolle über
APP_UserDetailRolezuweisen
- Lösung: Rolle über
Rolle abgelaufen: Die Datumswerte
ValidFrom/ValidToschließen das heutige Datum aus- Lösung: Zeiträume aktualisieren
Named Set liefert kein Ergebnis: Die dynamische Abfrage liefert keine Treffer
- Lösung: Die Abfrage des Named Sets separat debuggen
Falsche Abteilung: Der Benutzer ist einer anderen Abteilung zugeordnet
- Lösung:
APP_UserDetail.APP_Departmentaktualisieren
- Lösung:
Berechtigung deaktiviert:
IsDisabledExpressionergibtTrue- Lösung: Feature Flags oder Bedingungen prüfen
Fortgeschritten: Eigene Sicherheitsszenarien
Szenario 1: Zeitabhängiger Zugriff
Bearbeitung auf den Zeitraum vor dem Buchungsabschluss beschränken:
-- Can only edit timesheets before booking completion date
:Iif(
'BillingAdmin' In Set('CurrentUserRoles'),
True,
:Iif(
Current.APP_UserDetail = Environment.CurrentUser.UserDetailUuid And
Current.APP_DateActual > :BookingCompletionDateOfUser(Environment.CurrentUser.UserDetailUuid),
True, -- Can edit recent timesheets
False -- Cannot edit old/closed timesheets
)
) = True
Szenario 2: Kundenspezifische Sichtbarkeit
Kundenbetreuer sehen nur die ihnen zugeordneten Kunden:
-- Custom Named Set: APP_MyManagedCustomers
From C In APP_Customer
Where C.APP_AccountManager = Environment.CurrentUser.UserDetailUuid
Select C
-- Permission: Account manager sees their customers
:Iif(
'BillingAdmin' In Set('CurrentUserRoles'),
True,
Current In Set('APP_MyManagedCustomers')
) = True
Szenario 3: Mandantentrennung
Stellen Sie sicher, dass Benutzer nur Daten ihrer eigenen Firma sehen:
-- All entities: Tenant isolation
:Iif(
'SystemAdmin' In Set('CurrentUserRoles'), -- System admin sees all tenants
True,
Current.APP_Company = Environment.CurrentUser.UserDetail.APP_Company -- Same company only
) = True