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