fix security
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user