bd6c0b4d3d
Add missing <returns>/<param>/<summary>/<typeparam> tags and clean up misused inheritdoc across 481 files so the documented API surface is complete. Documentation-only (zero code lines changed). The 131 remaining findings are inheritdoc-style warnings deliberately left to preserve hand-written implementation rationale (plan-decision notes, race-condition explanations).
117 lines
4.4 KiB
C#
117 lines
4.4 KiB
C#
using System.Security.Claims;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.Auth.AspNetCore;
|
|
using ZB.MOM.WW.OtOpcUa.Security.Audit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Security.Tests.Audit;
|
|
|
|
/// <summary>
|
|
/// Unit tests for <see cref="HttpAuditActorAccessor"/>.
|
|
/// <para>
|
|
/// Covers the three cases:
|
|
/// <list type="bullet">
|
|
/// <item>Authenticated principal with a <see cref="ZbClaimTypes.Username"/> claim →
|
|
/// returns the username claim value.</item>
|
|
/// <item>Authenticated principal with only a <see cref="ZbClaimTypes.Name"/> / no
|
|
/// username claim → falls back to the Name claim.</item>
|
|
/// <item>No HTTP context (null) or unauthenticated principal → returns
|
|
/// <see langword="null"/>.</item>
|
|
/// </list>
|
|
/// </para>
|
|
/// </summary>
|
|
public sealed class HttpAuditActorAccessorTests
|
|
{
|
|
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
private static IHttpContextAccessor ContextWith(ClaimsPrincipal principal)
|
|
{
|
|
var context = new DefaultHttpContext { User = principal };
|
|
return new HttpContextAccessorStub(context);
|
|
}
|
|
|
|
private static IHttpContextAccessor NoContext() =>
|
|
new HttpContextAccessorStub(null);
|
|
|
|
private static ClaimsPrincipal AuthenticatedWith(params Claim[] claims)
|
|
{
|
|
var identity = new ClaimsIdentity(
|
|
claims,
|
|
authenticationType: "TestScheme", // non-null authenticationType → IsAuthenticated = true
|
|
nameType: ZbClaimTypes.Name,
|
|
roleType: ZbClaimTypes.Role);
|
|
return new ClaimsPrincipal(identity);
|
|
}
|
|
|
|
private static ClaimsPrincipal Unauthenticated() =>
|
|
new(new ClaimsIdentity()); // no authenticationType → IsAuthenticated = false
|
|
|
|
// ── tests ─────────────────────────────────────────────────────────────────────
|
|
|
|
/// <summary>
|
|
/// An authenticated principal that carries <see cref="ZbClaimTypes.Username"/>
|
|
/// returns exactly that claim value — it is the canonical actor string.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Returns_username_claim_for_authenticated_principal()
|
|
{
|
|
var principal = AuthenticatedWith(
|
|
new Claim(ZbClaimTypes.Username, "alice"),
|
|
new Claim(ZbClaimTypes.Name, "alice-name"),
|
|
new Claim(ZbClaimTypes.DisplayName, "Alice User"));
|
|
|
|
var sut = new HttpAuditActorAccessor(ContextWith(principal));
|
|
|
|
sut.CurrentActor.ShouldBe("alice");
|
|
}
|
|
|
|
/// <summary>
|
|
/// When the principal has no <see cref="ZbClaimTypes.Username"/> claim but does have
|
|
/// a <see cref="ZbClaimTypes.Name"/> claim, the Name claim value is returned as the
|
|
/// fallback actor.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Falls_back_to_Name_claim_when_Username_claim_is_absent()
|
|
{
|
|
var principal = AuthenticatedWith(
|
|
new Claim(ZbClaimTypes.Name, "bob"));
|
|
|
|
var sut = new HttpAuditActorAccessor(ContextWith(principal));
|
|
|
|
sut.CurrentActor.ShouldBe("bob");
|
|
}
|
|
|
|
/// <summary>
|
|
/// An unauthenticated principal (Identity.IsAuthenticated == false) returns null —
|
|
/// the caller's fallback (typically <see cref="AuditActor.SystemFallback"/>) is used.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Returns_null_for_unauthenticated_principal()
|
|
{
|
|
var sut = new HttpAuditActorAccessor(ContextWith(Unauthenticated()));
|
|
|
|
sut.CurrentActor.ShouldBeNull();
|
|
}
|
|
|
|
/// <summary>
|
|
/// When there is no current <c>HttpContext</c> (e.g. background task, actor mailbox
|
|
/// worker), returns null.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Returns_null_when_no_HttpContext()
|
|
{
|
|
var sut = new HttpAuditActorAccessor(NoContext());
|
|
|
|
sut.CurrentActor.ShouldBeNull();
|
|
}
|
|
|
|
// ── stub ──────────────────────────────────────────────────────────────────────
|
|
|
|
private sealed class HttpContextAccessorStub(HttpContext? context) : IHttpContextAccessor
|
|
{
|
|
/// <summary>Gets or sets the HTTP context for the stub.</summary>
|
|
public HttpContext? HttpContext { get; set; } = context;
|
|
}
|
|
}
|