Initial commit with inital CMS

This commit is contained in:
2026-06-15 17:00:16 +02:00
commit 95d986790e
132 changed files with 7624 additions and 0 deletions
@@ -0,0 +1,38 @@
# Business Rules — Unit 02: Identity & RBAC
Dit document beschrijft de validatieregels en logica voor identiteitsbeheer en autorisatie.
## 1. Hiërarchische Rollen (BR-ID-01)
- **Hiërarchie**: Owner (100) > Administrator (50) > User (10).
- **Beperking**: Een gebruiker kan alleen acties uitvoeren op gebruikers met een **lagere** rol in de hiërarchie.
- Uitzondering: Een Owner kan acties uitvoeren op andere Owners (bijv. de-activeren, mits niet de laatste Owner).
- Een Administrator kan een User beheren, maar geen andere Administrator of Owner.
- **Rolverandering**: Een gebruiker kan een andere gebruiker nooit een rol toekennen die hoger is dan zijn eigen rol.
## 2. Gebruikerscreatie & Uitnodiging (BR-ID-02)
- **Geen Zelfregistratie**: Het systeem staat geen publieke registratie toe.
- **Uitnodigingsflow**:
1. Administrator/Owner maakt een uitnodiging aan (e-mail + rol).
2. Systeem genereert een `InvitationToken` met een beperkte geldigheidsduur (bijv. 24 uur).
3. Gebruiker moet via een specifiek endpoint (`POST /api/setup/complete-invitation`) zijn wachtwoord instellen met dit token.
4. Na succesvolle instelling wordt het token ongeldig en het account geactiveerd.
## 3. Bootstrapping (BR-ID-03)
- **Setup Endpoint**: Bij een lege database is een eenmalig endpoint `POST /api/setup/init` beschikbaar.
- **Eerste Owner**: Dit endpoint accepteert de gegevens voor de eerste Owner. Na succesvolle aanmaak wordt dit endpoint permanent geblokkeerd of verwijderd uit de routing.
## 4. Authenticatie & Sessies (BR-ID-04)
- **Wachtwoord Hashen**: Wachtwoorden moeten gehasht worden volgens de ASP.NET Core Identity standaard (PBKDF2 met HMAC-SHA256).
- **Refresh Tokens**:
- Refresh tokens zijn gekoppeld aan een specifieke gebruiker en client/apparaat.
- Refresh tokens kunnen maar één keer worden gebruikt (Rotation-principe).
- Bij gebruik van een oud refresh token worden alle actieve sessies van die gebruiker ongeldig gemaakt (beveiligingsmaatregel tegen token diefstal).
## 5. Module-specifieke Rechten (BR-ID-05)
- **Fine-grained Access**: Naast de globale rollen kunnen Beheerders specifieke rechten per module toekennen aan Users.
- **Default**: Zonder expliciete module-rechten heeft een User alleen leesrechten of basisrechten binnen een module (afhankelijk van de module-implementatie).
@@ -0,0 +1,37 @@
# Domain Entities — Unit 02: Identity & RBAC
Dit document beschrijft de data-entiteiten die nodig zijn voor identiteitsbeheer.
## 1. ApplicationUser
Breidt de standaard `IdentityUser` uit.
- **Email**: Unieke identifier.
- **Role**: De primaire hiërarchische rol (`Owner`, `Administrator`, `User`).
- **IsActive**: Boolean status.
- **CreatedAt**: Tijdstip van aanmaak.
- **ModulePermissions**: Navigatie-eigenschap naar module-specifieke rechten.
## 2. RefreshToken
- **Id**: Guid.
- **Token**: De gehashte token string.
- **UserId**: Link naar de `ApplicationUser`.
- **ExpiryDate**: Wanneer het token verloopt.
- **IsUsed**: Boolean (voor re-use detection).
- **IsRevoked**: Boolean (handmatige intrekking).
- **CreatedByIp**: IP adres voor audit trail.
## 3. Invitation
- **Email**: Adres waar de uitnodiging naar verzonden is.
- **Role**: De toegekende rol na acceptatie.
- **Token**: Unieke GUID/String.
- **ExpiryDate**: Geldigheidsduur van de uitnodiging.
- **IsAccepted**: Boolean.
## 4. ModulePermission
- **UserId**: Link naar `ApplicationUser`.
- **ModuleName**: Naam van de module.
- **Permission**: De specifieke string-gebaseerde permissie (bijv. "Write", "Admin").
@@ -0,0 +1,62 @@
# Business Logic Model — Unit 02: Identity & RBAC
Dit document beschrijft de processen en datastromen voor authenticatie en autorisatie.
## 1. Authenticatie Flow (JWT)
```mermaid
sequenceDiagram
participant Client
participant AuthController
participant AuthService
participant UserManager
participant Database
Client->>AuthController: Login(Email, Password)
AuthController->>AuthService: AuthenticateAsync(Email, Password)
AuthService->>UserManager: FindByEmailAsync(Email)
UserManager->>Database: Get User
Database-->>UserManager: User Data
UserManager->>UserManager: CheckPasswordAsync(User, Password)
AuthService->>AuthService: GenerateTokens(User)
AuthService->>Database: Save RefreshToken
AuthService-->>AuthController: AccessToken, RefreshToken
AuthController-->>Client: 200 OK (Tokens)
```
## 2. Uitnodigingsproces
```mermaid
graph TD
A[Admin/Owner] -->|Create Invitation| B(InvitationService)
B -->|Generate Token| C(InvitationToken)
C -->|Save to DB| D[(Database)]
B -->|Send Email| E[User]
E -->|Click Link| F[Setup Page]
F -->|Submit Password + Token| G(SetupController)
G -->|Validate Token| B
B -->|Create Account| H(UserManager)
H -->|Activate User| D
```
## 3. Hiërarchische Autorisatie Logic
De autorisatie wordt afgehandeld via ASP.NET Core `AuthorizationPolicies`.
- **Policy: `RequireLowerRole`**:
- Haalt de rol van de huidige gebruiker (X) en de doelgebruiker (Y) op.
- Vergelijkt de numerieke waarden van de rollen.
- Slaagt alleen als `RoleValue(X) > RoleValue(Y)` (of `X == Y` en `X == Owner`).
## 4. Token Refresh Logic
1. Client stuurt `Expired Access Token` + `Refresh Token`.
2. Systeem controleert of `Refresh Token` bestaat in de database en niet verlopen is.
3. Systeem controleert of `Refresh Token` al eerder is gebruikt (Re-use detection).
4. Indien geldig:
- Genereer nieuw `Access Token`.
- Genereer nieuw `Refresh Token` (Rotation).
- Verwijder/Invalideer het oude `Refresh Token`.
5. Indien ongeldig of re-use:
- Trek alle tokens van de gebruiker in.
- Retourneer `401 Unauthorized`.
@@ -0,0 +1,35 @@
# Auth Service Design — Unit 02: Identity & RBAC
Dit document beschrijft de `IAuthService` die verantwoordelijk is voor token-management.
## 1. Interface definitie
```csharp
public interface IAuthService
{
Task<TokenResponse> AuthenticateAsync(string email, string password);
Task<TokenResponse> RefreshTokenAsync(string accessToken, string refreshToken);
Task RevokeTokenAsync(string refreshToken);
}
```
## 2. JWT Configuratie
- **Signing Key**: Wordt uit de environment variable `JWT_SIGNING_KEY` gelezen.
- **Issuer/Audience**: Worden geconfigureerd in `appsettings.json`.
- **Claims**:
- `sub`: UserId.
- `email`: Gebruikers e-mail.
- `role`: Gebruikers rol (bijv. "Administrator").
- `exp`: Expiration time.
## 3. Refresh Token Rotation Logic
Bij een refresh request:
1. Valideer de `refreshToken` string tegen de database.
2. Controleer op Re-use: Indien de `IsUsed` vlag al op `true` staat, trek dan **alle** tokens van die gebruiker in (NFR-ID-SEC-03).
3. Indien geldig:
- Markeer huidig token als `IsUsed = true`.
- Genereer een nieuw cryptografisch veilig geheim (32 bytes Base64).
- Sla het nieuwe token op met een nieuwe `ExpiryDate`.
- Retourneer het nieuwe `AccessToken` en `RefreshToken`.
@@ -0,0 +1,52 @@
# Authorization Design — Unit 02: Identity & RBAC
Dit document beschrijft de technische implementatie van de hiërarchische autorisatie.
## 1. HierarchicalRoleRequirement
We maken gebruik van een custom requirement om rollen te vergelijken.
```csharp
public class HierarchicalRoleRequirement : IAuthorizationRequirement
{
public HierarchicalRoleRequirement(string minimumRequiredRole)
{
MinimumRequiredRole = minimumRequiredRole;
}
public string MinimumRequiredRole { get; }
}
```
## 2. HierarchicalRoleHandler
De handler valideert of de rollen-hiërarchie wordt gerespecteerd.
- **Logic**:
1. Haal de rol-claim op van de huidige gebruiker.
2. Haal de doel-gebruiker op uit de route of body.
3. Vergelijk de numerieke waarden van beide rollen.
4. Slaag alleen als de huidige gebruiker een hogere of gelijke rol heeft (afhankelijk van de actie).
## 3. Setup Endpoint Protection
Het `SetupController.Init` endpoint controleert direct in de database of er al een Owner bestaat:
```csharp
[HttpPost("init")]
public async Task<IActionResult> Init(SetupRequest request)
{
var anyOwner = await _userManager.GetUsersInRoleAsync("Owner");
if (anyOwner.Any())
{
return Forbidden("Systeem is reeds geïnitialiseerd.");
}
// Verwerk creatie...
}
```
## 4. Module-specifieke Policies
Er worden dynamische policies aangemaakt voor module-permissies:
- Patroon: `Module:{ModuleName}:{Permission}` (bijv. `Module:Blog:Delete`).
- De handler controleert de `ModulePermissions` tabel voor de huidige gebruiker.
@@ -0,0 +1,52 @@
# Database Design — Unit 02: Identity & RBAC
Dit document beschrijft de database schema configuratie voor de identiteitsmodule.
## 1. DbContext Mapping (Identity)
De `ApplicationDbContext` erft over van `IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>`.
In `OnModelCreating` worden de tabelnamen geconfigureerd:
```csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(entity => { entity.ToTable("Users"); });
builder.Entity<IdentityRole<Guid>>(entity => { entity.ToTable("Roles"); });
builder.Entity<IdentityUserRole<Guid>>(entity => { entity.ToTable("UserRoles"); });
builder.Entity<IdentityUserClaim<Guid>>(entity => { entity.ToTable("UserClaims"); });
builder.Entity<IdentityUserLogin<Guid>>(entity => { entity.ToTable("UserLogins"); });
builder.Entity<IdentityRoleClaim<Guid>>(entity => { entity.ToTable("RoleClaims"); });
builder.Entity<IdentityUserToken<Guid>>(entity => { entity.ToTable("UserTokens"); });
}
```
## 2. Aanvullende Tabellen
### RefreshTokens
- **Tabel**: `RefreshTokens`
- **PK**: `Id` (Guid)
- **FK**: `UserId` -> `Users.Id`
- **Index**: `Token` (Unique)
### Invitations
- **Tabel**: `Invitations`
- **PK**: `Id` (Guid)
- **Index**: `Token` (Unique)
- **Email**: `NVARCHAR(256)`
### ModulePermissions
- **Tabel**: `ModulePermissions`
- **Composite PK**: `(UserId, ModuleName, Permission)`
- **FK**: `UserId` -> `Users.Id`
## 3. Auditing (NFR-ID-SEC-03)
Er wordt een aparte `AuditLogs` tabel aangemaakt voor het loggen van mutaties:
- `Id` (Guid)
- `Timestamp` (DateTimeOffset)
- `ActorId` (Guid - De uitvoerder)
- `Action` (String - bijv. "RoleChange", "UserCreated")
- `EntityId` (Guid - Het doelobject)
- `Details` (JSON/String - Oude vs Nieuwe waarden)
@@ -0,0 +1,40 @@
# Invitation Design — Unit 02: Identity & RBAC
Dit document beschrijft de technische implementatie van het uitnodigingssysteem.
## 1. IInvitationService
```csharp
public interface IInvitationService
{
Task<string> CreateInvitationAsync(string email, string role);
Task<bool> ValidateInvitationAsync(string token);
Task CompleteInvitationAsync(string token, string password);
}
```
## 2. Token Generatie
Het `InvitationToken` wordt gegenereerd met de `RandomNumberGenerator`:
```csharp
public string GenerateSecureToken()
{
var bytes = new byte[32];
RandomNumberGenerator.Fill(bytes);
return Convert.ToBase64String(bytes);
}
```
## 3. Workflow Details
1. **Creatie**:
- Een `Invitation` record wordt aangemaakt in de database.
- Het `Token` wordt gehasht opgeslagen (net als een wachtwoord) om misbruik bij database-lekken te voorkomen.
2. **Validatie**:
- Het systeem zoekt het record op basis van de token-string.
- Controleert `ExpiryDate` en `IsAccepted`.
3. **Afronding**:
- Bij `CompleteInvitationAsync` wordt de `ApplicationUser` aangemaakt via de `UserManager`.
- De rol wordt toegekend.
- Het uitnodigingsrecord wordt gemarkeerd als `IsAccepted = true`.
@@ -0,0 +1,35 @@
# NFR Requirements — Unit 02: Identity & RBAC
Dit document specificeert de non-functionele vereisten voor identiteitsbeheer en autorisatie.
## 1. Beveiliging (Security)
- **ID-SEC-01: Wachtwoordbeleid**:
- Minimale lengte: 8 tekens.
- Geen verplichte complexiteitseisen (hoofdletters/cijfers), focus op lengte voor gebruiksvriendelijkheid.
- **ID-SEC-02: Token Lifecycle**:
- Access Token (JWT) vervaltijd: 1 uur.
- Refresh Token vervaltijd: 7 dagen.
- **ID-SEC-03: Audit Logging**:
- Verplichte persistente logging van:
- Gebruikerscreatie en uitnodigingen.
- Rolwijzigingen.
- Activatie/Deactivatie van accounts.
- Mislukte login pogingen.
- **ID-SEC-04: Data Privacy**:
- Wachtwoorden worden nooit in plain-text opgeslagen.
- Persoonlijke gegevens (PII) worden alleen via HTTPS ontsloten.
## 2. Performance
- **ID-PERF-01: Token Validatie**:
- De validatie van het JWT token bij elk request mag niet meer dan 5ms overhead toevoegen.
- **ID-PERF-02: Database Querying**:
- Het ophalen van een gebruiker inclusief rollen en permissies moet binnen 20ms gebeuren (geïndexeerd op Email).
## 3. Onderhoudbaarheid (Maintainability)
- **ID-MAINT-01: Database Schema**:
- Gebruik van schone tabelnamen zonder `AspNet` prefix (bijv. `Users`, `Roles`, `UserRoles`).
- **ID-MAINT-02: EF Core Migrations**:
- Alle wijzigingen aan het identiteitsschema worden via code-first migrations bijgehouden.
@@ -0,0 +1,35 @@
# Tech Stack Decisions — Unit 02: Identity & RBAC
Dit document beschrijft de definitieve technische keuzes voor Unit 02.
## 1. Core Frameworks
- **Identity**: Microsoft.AspNetCore.Identity.
- **ORM**: Entity Framework Core.
- **Database**: Microsoft SQL Server.
## 2. Authenticatie & Autorisatie
- **JWT Library**: Microsoft.AspNetCore.Authentication.JwtBearer.
- **Policy Engine**: Native ASP.NET Core Authorization Policies & RequirementHandlers.
- **Hashing**: PBKDF2 (standaard Identity).
## 3. Database Schema Mapping
Conform ID-MAINT-01 worden de standaard Identity tabellen hernoemd in de `OnModelCreating` van de `DbContext`:
| Standaard Naam | Nieuwe Naam |
|---|---|
| AspNetUsers | Users |
| AspNetRoles | Roles |
| AspNetUserRoles | UserRoles |
| AspNetUserClaims | UserClaims |
| AspNetUserLogins | UserLogins |
| AspNetRoleClaims | RoleClaims |
| AspNetUserTokens | UserTokens |
## 4. Testing Tools
- **Unit Tests**: xUnit + FluentAssertions + NSubstitute.
- **Data Generation**: AutoFixture.
- **PBT**: FsCheck (alleen voor token-logic en mapping functies, conform NFR-06).