57 lines
2.0 KiB
C#
57 lines
2.0 KiB
C#
using System.Security.Claims;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
|
|
{
|
|
private readonly ILogger<PermissionAuthorizationHandler> _logger;
|
|
private readonly IHttpContextAccessor _http;
|
|
private readonly ClinicalMetrics _metrics;
|
|
|
|
public PermissionAuthorizationHandler(
|
|
ILogger<PermissionAuthorizationHandler> logger,
|
|
IHttpContextAccessor http,
|
|
ClinicalMetrics metrics)
|
|
{
|
|
_logger = logger;
|
|
_http = http;
|
|
_metrics = metrics;
|
|
}
|
|
|
|
protected override Task HandleRequirementAsync(
|
|
AuthorizationHandlerContext context,
|
|
PermissionRequirement requirement)
|
|
{
|
|
var roleClaim = context.User.FindFirst("clinical_role")?.Value;
|
|
if (roleClaim is null)
|
|
{
|
|
LogAuthorizationFailure(context.User, "none", requirement.Permission);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
var role = ClinicalRoleExtensions.FromDbString(roleClaim);
|
|
if (ClinicalRolePermissionMap.HasPermission(role, requirement.Permission))
|
|
{
|
|
context.Succeed(requirement);
|
|
}
|
|
else
|
|
{
|
|
LogAuthorizationFailure(context.User, roleClaim, requirement.Permission);
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private void LogAuthorizationFailure(ClaimsPrincipal user, string role, string permission)
|
|
{
|
|
var username = user.FindFirst(ClaimTypes.Name)?.Value ?? "unknown";
|
|
var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? "unknown";
|
|
var endpoint = _http.HttpContext?.GetEndpoint()?.DisplayName ?? "unknown";
|
|
|
|
_logger.LogWarning(
|
|
"Authorization denied: user={User} (id={UserId}), role={Role}, " +
|
|
"requiredPermission={Permission}, endpoint={Endpoint}",
|
|
username, userId, role, permission, endpoint);
|
|
|
|
_metrics.AuthorizationFailuresTotal.WithLabels(permission, role).Inc();
|
|
}
|
|
} |