fix security

This commit is contained in:
voltsrage
2026-06-21 19:53:19 +08:00
parent a37fad0e57
commit 7170b6efad
14 changed files with 422 additions and 27 deletions
@@ -14,6 +14,7 @@ public static class ClinicalPermissions
public const string OrdersWrite = "orders:write";
public const string MedicationsWrite = "medications:write";
public const string FhirIngest = "fhir:ingest";
public const string FhirRead = "fhir:read";
public const string AuditRead = "audit:read";
public const string UsersAdmin = "users:admin";
}
@@ -48,6 +48,7 @@ public static class ClinicalRolePermissionMap
ClinicalPermissions.OrdersWrite,
ClinicalPermissions.MedicationsWrite,
ClinicalPermissions.FhirIngest,
ClinicalPermissions.FhirRead,
ClinicalPermissions.AuditRead,
ClinicalPermissions.UsersAdmin,
},
@@ -58,6 +59,7 @@ public static class ClinicalRolePermissionMap
ClinicalPermissions.ObservationsIngest,
ClinicalPermissions.MedicationsWrite,
ClinicalPermissions.FhirIngest,
ClinicalPermissions.FhirRead,
},
};
@@ -1,19 +1,57 @@
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();
}
}