using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using System.Security.Claims; namespace Yavsc.Tests.Shared; /// /// Authorization policy provider used by integration tests. Replaces the /// production provider in the test host so that any policy-protected /// controller can be exercised by sending a X-Test-Role: … /// header — no login roundtrip, no cookie, no database user. /// /// Any policy that requires a role short-circuits to success when the /// matching header is present; otherwise the production policy is /// preserved. The test does not perform a real login, so we attach an /// in-memory carrying the role claim to /// the request before the assertion /// fires, so claim-based requirements (e.g. RequireRole("Admin")) /// also pass. /// public sealed class TestAuthPolicyProvider : IAuthorizationPolicyProvider { /// HTTP header read by the test bypass to learn the role. public const string HeaderName = "X-Test-Role"; /// Conventional admin role name; the production default. public const string AdminRole = "Administrator"; private readonly DefaultAuthorizationPolicyProvider _fallback; public TestAuthPolicyProvider(IOptions options) { _fallback = new DefaultAuthorizationPolicyProvider(options); } public Task GetDefaultPolicyAsync() => _fallback.GetDefaultPolicyAsync(); public Task GetFallbackPolicyAsync() => _fallback.GetFallbackPolicyAsync(); public async Task GetPolicyAsync(string policyName) { var policy = await _fallback.GetPolicyAsync(policyName); if (policy is null) return null; return new AuthorizationPolicyBuilder() .RequireAssertion(ctx => { // ASP.NET Core sets ctx.Resource to the HttpContext when // the authorization middleware invokes the policy. Use // the request headers directly to honour X-Test-Role. var http = ctx.Resource as HttpContext; if (http is null) return false; var role = http.Request.Headers[HeaderName].ToString(); if (string.IsNullOrEmpty(role)) return false; if (http.User.Identity is null || !http.User.Identity.IsAuthenticated) { var identity = new ClaimsIdentity( new[] { new Claim( "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", role), }, authenticationType: "TestAuth"); http.User = new ClaimsPrincipal(identity); } return true; }) .Build(); } }