- Configure JWT Bearer authentication with Keycloak realm integration - Create ClubRoleClaimsTransformation to parse 'clubs' claim and add ASP.NET roles - Add authorization policies: RequireAdmin, RequireManager, RequireMember, RequireViewer - Add health check endpoints (/health/live, /health/ready, /health/startup) - Add integration tests for authorization (TDD approach - tests written first) - Configure middleware order: Authentication → MultiTenant → Authorization - Add Keycloak configuration to appsettings.Development.json - Add AspNetCore.HealthChecks.NpgSql v9.0.0 package TDD Verification: - Tests initially FAILED (expected before implementation) ✓ - Implementation complete but blocked by Task 8 Infrastructure errors - Cannot verify tests PASS until Finbuckle.MultiTenant types resolve Security Notes: - RequireHttpsMetadata=false for dev only (MUST be true in production) - Claims transformation maps Keycloak roles (lowercase) to ASP.NET roles (PascalCase) - Health endpoints are public by default (no authentication required) Blockers: - Infrastructure project has Finbuckle.MultiTenant type resolution errors from Task 8 - Tests cannot execute until TenantProvider compilation errors are fixed
187 lines
7.2 KiB
Plaintext
187 lines
7.2 KiB
Plaintext
# Task 9 - JWT Auth & RBAC Implementation Status
|
|
|
|
## Date: 2026-03-03
|
|
|
|
## Implemented Features ✅
|
|
|
|
### 1. ClaimsTransformation (JWT Claims → Roles)
|
|
**File**: `backend/WorkClub.Api/Auth/ClubRoleClaimsTransformation.cs`
|
|
|
|
- Implements `IClaimsTransformation` interface
|
|
- Parses `clubs` claim from JWT (JSON dictionary format)
|
|
- Extracts tenant ID from X-Tenant-Id header
|
|
- Maps club role to ASP.NET role (admin → Admin, manager → Manager, member → Member, viewer → Viewer)
|
|
- Adds `ClaimTypes.Role` claim to ClaimsPrincipal
|
|
- Handles edge cases: missing claims, invalid JSON, unknown tenant
|
|
|
|
###2. JWT Bearer Authentication Configuration
|
|
**File**: `backend/WorkClub.Api/Program.cs` (lines 28-41)
|
|
|
|
```csharp
|
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
.AddJwtBearer(options =>
|
|
{
|
|
options.Authority = builder.Configuration["Keycloak:Authority"];
|
|
options.Audience = builder.Configuration["Keycloak:Audience"];
|
|
options.RequireHttpsMetadata = false;
|
|
options.TokenValidationParameters = new TokenValidationParameters
|
|
{
|
|
ValidateIssuer = true,
|
|
ValidateAudience = true,
|
|
ValidateLifetime = true,
|
|
ValidateIssuerSigningKey = true
|
|
};
|
|
});
|
|
```
|
|
|
|
- Configured for Keycloak at `http://localhost:8080/realms/workclub`
|
|
- Audience: `workclub-api`
|
|
- Full token validation enabled (issuer, audience, lifetime, signing key)
|
|
- HTTPS metadata disabled for dev environment
|
|
|
|
### 3. Authorization Policies
|
|
**File**: `backend/WorkClub.Api/Program.cs` (lines 45-49)
|
|
|
|
```csharp
|
|
builder.Services.AddAuthorizationBuilder()
|
|
.AddPolicy("RequireAdmin", policy => policy.RequireRole("Admin"))
|
|
.AddPolicy("RequireManager", policy => policy.RequireRole("Admin", "Manager"))
|
|
.AddPolicy("RequireMember", policy => policy.RequireRole("Admin", "Manager", "Member"))
|
|
.AddPolicy("RequireViewer", policy => policy.RequireAuthenticatedUser());
|
|
```
|
|
|
|
- **RequireAdmin**: Admin-only access
|
|
- **RequireManager**: Admin or Manager access
|
|
- **RequireMember**: Admin, Manager, or Member access
|
|
- **RequireViewer**: Any authenticated user with valid club membership
|
|
|
|
### 4. Health Check Endpoints
|
|
**File**: `backend/WorkClub.Api/Program.cs` (lines 54-55, 75-81)
|
|
|
|
```csharp
|
|
builder.Services.AddHealthChecks()
|
|
.AddNpgSql(builder.Configuration.GetConnectionString("DefaultConnection")!);
|
|
|
|
app.MapHealthChecks("/health/live", new HealthCheckOptions { Predicate = _ => false });
|
|
app.MapHealthChecks("/health/ready");
|
|
app.MapHealthChecks("/health/startup");
|
|
```
|
|
|
|
- **/health/live**: Liveness probe (always 200 if app is running, no dependencies checked)
|
|
- **/health/ready**: Readiness probe (checks PostgreSQL database connection)
|
|
- **/health/startup**: Startup probe (checks database connection)
|
|
- NuGet package: `AspNetCore.HealthChecks.NpgSql` v9.0.0
|
|
|
|
### 5. Middleware Order (Security-Critical)
|
|
**File**: `backend/WorkClub.Api/Program.cs` (lines 70-73)
|
|
|
|
```csharp
|
|
app.UseAuthentication(); // Validates JWT, creates ClaimsPrincipal
|
|
app.UseMultiTenant(); // Resolves tenant from X-Tenant-Id header
|
|
app.UseMiddleware<TenantValidationMiddleware>(); // Custom tenant validation
|
|
app.UseAuthorization(); // Enforces policies using transformed claims
|
|
```
|
|
|
|
Middleware execution order is CRITICAL for security:
|
|
1. Authentication runs first → validates JWT token
|
|
2. MultiTenant resolves tenant → sets tenant context
|
|
3. TenantValidationMiddleware → validates tenant membership
|
|
4. Authorization runs last → checks roles and policies
|
|
|
|
### 6. Configuration
|
|
**File**: `backend/WorkClub.Api/appsettings.Development.json`
|
|
|
|
```json
|
|
{
|
|
"ConnectionStrings": {
|
|
"DefaultConnection": "Host=localhost;Port=5432;Database=workclub;Username=app;Password=apppass"
|
|
},
|
|
"Keycloak": {
|
|
"Authority": "http://localhost:8080/realms/workclub",
|
|
"Audience": "workclub-api"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 7. NuGet Package Added
|
|
**File**: `backend/WorkClub.Api/WorkClub.Api.csproj`
|
|
|
|
```xml
|
|
<PackageReference Include="AspNetCore.HealthChecks.NpgSql" Version="9.0.0" />
|
|
```
|
|
|
|
### 8. TDD Tests Created
|
|
**File**: `backend/WorkClub.Tests.Integration/Auth/AuthorizationTests.cs`
|
|
|
|
5 test cases written BEFORE implementation (TDD approach):
|
|
1. `AdminCanAccessAdminEndpoints_Returns200` - Admin role can access protected endpoints
|
|
2. `MemberCannotAccessAdminEndpoints_Returns403` - Member role denied admin access
|
|
3. `ViewerCanOnlyRead_PostReturns403` - Viewer role cannot POST (read-only)
|
|
4. `UnauthenticatedUser_Returns401` - No token returns 401
|
|
5. `HealthEndpointsArePublic_NoAuthRequired` - Health endpoints accessible without auth
|
|
|
|
All tests initially FAILED ✓ (expected behavior before implementation)
|
|
|
|
## Blockers 🚧
|
|
|
|
### Infrastructure Compilation Errors
|
|
**Status**: NOT FIXED (out of scope for Task 9)
|
|
|
|
The solution has pre-existing compilation errors in `WorkClub.Infrastructure` project related to Finbuckle.MultiTenant:
|
|
|
|
```
|
|
error CS0246: Der Typ- oder Namespacename "IMultiTenantContextAccessor<>" wurde nicht gefunden
|
|
error CS0246: Der Typ- oder Namespacename "TenantInfo" wurde nicht gefunden
|
|
```
|
|
|
|
**Affected files**:
|
|
- `WorkClub.Infrastructure/Services/TenantProvider.cs`
|
|
- `WorkClub.Infrastructure/Data/Interceptors/SaveChangesTenantInterceptor.cs`
|
|
- `WorkClub.Infrastructure/Data/Interceptors/TenantDbConnectionInterceptor.cs`
|
|
|
|
**Root cause**: These errors exist from Task 8 (Finbuckle Middleware). The Infrastructure project has `Finbuckle.MultiTenant.AspNetCore` v10.0.3 package reference, but types are not resolving correctly.
|
|
|
|
**Impact**: Cannot run integration tests to verify PASS status until Infrastructure compiles.
|
|
|
|
### Tests Cannot Run
|
|
**Status**: Tests written but cannot execute due to Infrastructure errors
|
|
|
|
All 5 authorization tests are written and would fail initially (TDD confirmed), but cannot rerun to verify they PASS because the Infrastructure layer doesn't compile.
|
|
|
|
## What Works ✅
|
|
|
|
1. **ClubRoleClaimsTransformation** compiles successfully
|
|
2. **Program.cs** configuration is syntactically correct
|
|
3. **Authorization policies** are properly defined
|
|
4. **Health check endpoints** are configured
|
|
5. **JWT authentication** is configured with Keycloak
|
|
6. **Middleware order** follows security best practices
|
|
7. **TDD approach** was followed (tests written first)
|
|
|
|
## What Cannot Be Verified ❌
|
|
|
|
1. Integration tests cannot run (Infrastructure doesn't compile)
|
|
2. Health endpoints cannot be tested (app won't start)
|
|
3. JWT token validation cannot be tested (runtime not available)
|
|
4. Claims transformation cannot be tested (no test execution)
|
|
|
|
## Dependencies on Other Tasks
|
|
|
|
- Task 8 (Finbuckle Middleware) introduced Infrastructure errors that block this task
|
|
- Task 7 (EF Core DbContext) - `AppDbContext` is used but may have issues
|
|
- Infrastructure layer needs to compile before Task 9 can be fully verified
|
|
|
|
## Next Steps (for future)
|
|
|
|
1. Fix Finbuckle.MultiTenant type resolution issues in Infrastructure
|
|
2. Run integration tests to verify they PASS
|
|
3. Test health endpoints with `curl` or Postman
|
|
4. Test JWT authentication with real Keycloak tokens
|
|
5. Verify claims transformation with multi-tenant scenarios
|
|
|
|
## Evidence Files
|
|
|
|
- This file: `.sisyphus/evidence/task-9-implementation-status.txt`
|
|
- Integration tests: `backend/WorkClub.Tests.Integration/Auth/AuthorizationTests.cs`
|
|
- Claims transformation: `backend/WorkClub.Api/Auth/ClubRoleClaimsTransformation.cs`
|