shoc-backend/SeaHaven.Services/Helpers/WorkOrderMediaAuthorization.cs
Arthur Bassi 6b18327d6b fix(work-orders): authorize GET media and forward cancellation
Enforce claims-derived read scope on media list and thread CancellationToken through detail data reads so HTTP cancel stops EF work.
2026-08-04 14:14:37 -03:00

95 lines
3 KiB
C#

using System.Security.Claims;
using Data.SeaHavenIndustries;
using SeaHaven.Services.Exceptions;
namespace SeaHaven.Services.Helpers
{
/// <summary>
/// Claims-derived authorization for work-order media read/mutations.
/// True multi-tenant CustomerId/TenantId is not modeled on WorkOrder/JWT;
/// scope is role + Assigned (<see cref="WorkOrder.AssignTo"/>) for Technician.
/// </summary>
public static class WorkOrderMediaAuthorization
{
private static readonly string[] StaffRoles =
{
"Admin",
"Manager",
"Dispatcher",
"Supervisor"
};
public static void EnsureCanRead(ClaimsPrincipal user, string? actorId)
{
EnsureAuthenticated(user, actorId, "You are not allowed to view work order media.");
if (IsStaff(user) || user.IsInRole("User"))
return;
throw Forbidden("You are not allowed to view work order media.");
}
public static void EnsureCanMutate(ClaimsPrincipal user, string? actorId)
{
EnsureAuthenticated(user, actorId);
if (IsStaff(user) || user.IsInRole("User"))
return;
throw Forbidden();
}
public static void EnsureCanDelete(ClaimsPrincipal user, string? actorId)
{
EnsureAuthenticated(user, actorId);
// Technician (User) may upload/categorize assigned media but not delete.
if (IsStaff(user))
return;
throw Forbidden();
}
/// <summary>
/// Staff: any in-scope (non-deleted/non-template) work order.
/// Technician: only work orders assigned to the caller. Out-of-scope → NotFound (no disclosure).
/// </summary>
public static void EnsureWorkOrderInCallerScope(
ClaimsPrincipal user,
string actorId,
WorkOrder workOrder)
{
if (IsStaff(user))
return;
if (user.IsInRole("User")
&& string.Equals(workOrder.AssignTo, actorId, StringComparison.Ordinal))
{
return;
}
throw new WorkOrderBoardValidationException("NotFound", "Work order not found.");
}
private static void EnsureAuthenticated(
ClaimsPrincipal user,
string? actorId,
string? forbiddenMessage = null)
{
if (user is null
|| !(user.Identity?.IsAuthenticated ?? false)
|| string.IsNullOrWhiteSpace(actorId))
{
throw Forbidden(forbiddenMessage);
}
}
private static bool IsStaff(ClaimsPrincipal user)
=> StaffRoles.Any(user.IsInRole);
private static WorkOrderBoardValidationException Forbidden(string? message = null)
=> new(
"Forbidden",
message ?? "You are not allowed to mutate work order media.");
}
}