Files
ScadaBridge/src/ScadaLink.Security/SiteScopeAuthorizationHandler.cs
T
Joseph Doherty cafb7d2006 Phase 1 WP-2–10: Repositories, audit service, security & auth (LDAP, JWT, roles, policies, data protection)
- WP-2: SecurityRepository + CentralUiRepository with audit log queries
- WP-3: AuditService with transactional guarantee (same SaveChangesAsync)
- WP-4: Optimistic concurrency tests (deployment records vs template last-write-wins)
- WP-5: Seed data (SCADA-Admins → Admin role mapping)
- WP-6: LdapAuthService (direct bind, TLS enforcement, group query)
- WP-7: JwtTokenService (HMAC-SHA256, 15-min refresh, 30-min idle timeout)
- WP-8: RoleMapper (LDAP groups → roles with site-scoped deployment)
- WP-9: Authorization policies (Admin/Design/Deployment + site scope handler)
- WP-10: Shared Data Protection keys via EF Core
141 tests pass, zero warnings.
2026-03-16 19:32:43 -04:00

53 lines
1.7 KiB
C#

using Microsoft.AspNetCore.Authorization;
namespace ScadaLink.Security;
/// <summary>
/// Authorization requirement for site-scoped deployment operations.
/// </summary>
public class SiteScopeRequirement : IAuthorizationRequirement
{
public string TargetSiteId { get; }
public SiteScopeRequirement(string targetSiteId)
{
TargetSiteId = targetSiteId ?? throw new ArgumentNullException(nameof(targetSiteId));
}
}
/// <summary>
/// Checks that a user with the Deployment role is permitted to operate on the target site.
/// Users with Deployment role and no SiteId claims are system-wide deployers.
/// Users with SiteId claims are only permitted on those specific sites.
/// </summary>
public class SiteScopeAuthorizationHandler : AuthorizationHandler<SiteScopeRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
SiteScopeRequirement requirement)
{
// Must have Deployment role
var hasDeploymentRole = context.User.HasClaim(JwtTokenService.RoleClaimType, "Deployment");
if (!hasDeploymentRole)
{
return Task.CompletedTask; // Fail — no Deployment role
}
var siteIdClaims = context.User.FindAll(JwtTokenService.SiteIdClaimType).ToList();
if (siteIdClaims.Count == 0)
{
// No site scope restrictions — system-wide deployer
context.Succeed(requirement);
}
else if (siteIdClaims.Any(c => c.Value == requirement.TargetSiteId))
{
// User is permitted on this specific site
context.Succeed(requirement);
}
// Otherwise, silently fail (not authorized for this site)
return Task.CompletedTask;
}
}