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();
}
}