From 04641319ce79709740a307a1b5a2a437c46b7090 Mon Sep 17 00:00:00 2001 From: WorkClub Automation Date: Wed, 18 Mar 2026 15:11:42 +0100 Subject: [PATCH] feat: Add global administrator role support with integration tests for admin-only club endpoints. --- .../Auth/ClubRoleClaimsTransformation.cs | 8 +++ backend/WorkClub.Api/Program.cs | 2 +- .../Clubs/AdminClubEndpointsTests.cs | 57 +++++++++++++++++++ .../CustomWebApplicationFactory.cs | 2 + .../Infrastructure/TestAuthHandler.cs | 8 ++- docker-compose.yml | 2 + 6 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 backend/WorkClub.Tests.Integration/Clubs/AdminClubEndpointsTests.cs diff --git a/backend/WorkClub.Api/Auth/ClubRoleClaimsTransformation.cs b/backend/WorkClub.Api/Auth/ClubRoleClaimsTransformation.cs index 15516cd..ca88bcd 100644 --- a/backend/WorkClub.Api/Auth/ClubRoleClaimsTransformation.cs +++ b/backend/WorkClub.Api/Auth/ClubRoleClaimsTransformation.cs @@ -54,6 +54,14 @@ public class ClubRoleClaimsTransformation : IClaimsTransformation return Task.FromResult(principal); } + // --- NEW: Skip DB role lookup if user is a global admin --- + var realmAccess = principal.FindFirst("realm_access")?.Value; + if (!string.IsNullOrEmpty(realmAccess) && realmAccess.Contains("\"admin\"", StringComparison.OrdinalIgnoreCase)) + { + return Task.FromResult(principal); + } + // --------------------------------------------------------- + // Look up the user's role in the database for the requested tenant _httpContextAccessor.HttpContext!.Items["TenantId"] = tenantId; var memberRole = GetMemberRole(userIdClaim, tenantId); diff --git a/backend/WorkClub.Api/Program.cs b/backend/WorkClub.Api/Program.cs index d5838ac..9e85016 100644 --- a/backend/WorkClub.Api/Program.cs +++ b/backend/WorkClub.Api/Program.cs @@ -90,8 +90,8 @@ if (app.Environment.IsDevelopment()) app.UseHttpsRedirection(); app.UseAuthentication(); -app.UseMiddleware(); app.UseAuthorization(); +app.UseMiddleware(); app.UseMiddleware(); app.MapHealthChecks("/health/live", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions diff --git a/backend/WorkClub.Tests.Integration/Clubs/AdminClubEndpointsTests.cs b/backend/WorkClub.Tests.Integration/Clubs/AdminClubEndpointsTests.cs new file mode 100644 index 0000000..7bc9cd6 --- /dev/null +++ b/backend/WorkClub.Tests.Integration/Clubs/AdminClubEndpointsTests.cs @@ -0,0 +1,57 @@ +using System.Net; +using System.Net.Http.Json; +using System.Security.Claims; +using System.Text.Json; +using WorkClub.Domain.Enums; +using WorkClub.Application.Clubs.DTOs; +using WorkClub.Tests.Integration.Infrastructure; +using Xunit; + +namespace WorkClub.Tests.Integration.Clubs; + +public class AdminClubEndpointsTests : IntegrationTestBase +{ + public AdminClubEndpointsTests(CustomWebApplicationFactory factory) : base(factory) + { + } + + [Fact] + public async Task CreateClub_WithAdminRole_ReturnsCreated() + { + AuthenticateAsAdmin(); + + var request = new CreateClubRequest("New Admin Club", SportType.Tennis, "Desc"); + var response = await Client.PostAsJsonAsync("/api/admin/clubs", request); + + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + } + + [Fact] + public async Task CreateClub_WithoutAdminRole_ReturnsForbidden() + { + AuthenticateAsNonAdmin(); + + var request = new CreateClubRequest("New Club", SportType.Tennis, "Desc"); + var response = await Client.PostAsJsonAsync("/api/admin/clubs", request); + + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + private void AuthenticateAsAdmin() + { + Client.DefaultRequestHeaders.Remove("X-Test-Email"); + Client.DefaultRequestHeaders.Add("X-Test-Email", "admin@workclub.com"); + + Client.DefaultRequestHeaders.Remove("X-Test-Realm-Access"); + Client.DefaultRequestHeaders.Add("X-Test-Realm-Access", "{\"roles\":[\"admin\"]}"); + } + + private void AuthenticateAsNonAdmin() + { + Client.DefaultRequestHeaders.Remove("X-Test-Email"); + Client.DefaultRequestHeaders.Add("X-Test-Email", "user@workclub.com"); + + Client.DefaultRequestHeaders.Remove("X-Test-Realm-Access"); + Client.DefaultRequestHeaders.Add("X-Test-Realm-Access", "{\"roles\":[\"user\"]}"); + } +} diff --git a/backend/WorkClub.Tests.Integration/Infrastructure/CustomWebApplicationFactory.cs b/backend/WorkClub.Tests.Integration/Infrastructure/CustomWebApplicationFactory.cs index ecfe149..d64be22 100644 --- a/backend/WorkClub.Tests.Integration/Infrastructure/CustomWebApplicationFactory.cs +++ b/backend/WorkClub.Tests.Integration/Infrastructure/CustomWebApplicationFactory.cs @@ -67,6 +67,8 @@ public class CustomWebApplicationFactory : WebApplicationFactory