using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ZB.MOM.WW.MxGateway.Server;
using ZB.MOM.WW.MxGateway.Server.Dashboard;
namespace ZB.MOM.WW.MxGateway.Tests.Gateway;
///
/// Verifies the shared Secrets UI is wired into the dashboard: the
/// AddSecretsAuthorization policies are registered so the mounted
/// /admin/secrets Blazor page ([Authorize(Policy = "secrets:manage")]) and its
/// reveal action resolve, AND that the dashboard's real Administrator principal shape actually
/// satisfies them (the claim-type-compatibility risk class that bit HistorianGateway). The
/// browser reveal/redirect behaviour is verified separately on the box.
///
public sealed class DashboardSecretsMountTests
{
private const string ManagePolicy = "secrets:manage";
private const string RevealPolicy = "secrets:reveal";
///
/// Verifies that Build registers the shared Secrets authorization policies
/// (secrets:manage + secrets:reveal) added additively via
/// Configure<AuthorizationOptions>(o => o.AddSecretsAuthorization()).
///
/// A task that represents the asynchronous operation.
[Fact]
public async Task Build_RegistersSecretsAuthorizationPolicies()
{
await using WebApplication app = GatewayApplication.Build([]);
IAuthorizationPolicyProvider policyProvider =
app.Services.GetRequiredService();
AuthorizationPolicy? managePolicy = await policyProvider.GetPolicyAsync(ManagePolicy);
AuthorizationPolicy? revealPolicy = await policyProvider.GetPolicyAsync(RevealPolicy);
Assert.NotNull(managePolicy);
Assert.NotNull(revealPolicy);
}
///
/// Verifies that the dashboard's Administrator principal — constructed exactly the way
/// mints it
/// (role claim on ZbClaimTypes.Role, carrying Administrator, authenticated) —
/// satisfies BOTH secrets policies. This locks claim-type compatibility: if roles were ever
/// issued on a divergent claim type, RequireRole("Administrator") would no longer match
/// and this test would fail.
///
/// A task that represents the asynchronous operation.
[Fact]
public async Task AdministratorPrincipal_SatisfiesSecretsPolicies()
{
await using WebApplication app = GatewayApplication.Build([]);
IAuthorizationService authorization =
app.Services.GetRequiredService();
ClaimsPrincipal administrator = DashboardAutoLoginAuthenticationHandler.CreatePrincipal("multi-role");
AuthorizationResult manage = await authorization.AuthorizeAsync(administrator, resource: null, ManagePolicy);
AuthorizationResult reveal = await authorization.AuthorizeAsync(administrator, resource: null, RevealPolicy);
Assert.True(manage.Succeeded);
Assert.True(reveal.Succeeded);
}
///
/// Verifies that an anonymous, role-less principal is DENIED both secrets policies, proving the
/// policies actually gate on the Administrator role rather than admitting everyone.
///
/// A task that represents the asynchronous operation.
[Fact]
public async Task AnonymousPrincipal_IsDeniedSecretsPolicies()
{
await using WebApplication app = GatewayApplication.Build([]);
IAuthorizationService authorization =
app.Services.GetRequiredService();
ClaimsPrincipal anonymous = new(new ClaimsIdentity());
AuthorizationResult manage = await authorization.AuthorizeAsync(anonymous, resource: null, ManagePolicy);
AuthorizationResult reveal = await authorization.AuthorizeAsync(anonymous, resource: null, RevealPolicy);
Assert.False(manage.Succeeded);
Assert.False(reveal.Succeeded);
}
}