Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Middleware for custom authorization in Vonk FHIR Server
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Vonk.Core.Context;
using Vonk.Core.Context.VonkContext;
using Vonk.Core.Support;
namespace Vonk.Authorization
{
public class VonkAuthorizationMiddleware
{
private readonly RequestDelegate _next;
public VonkAuthorizationMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var vonkContext = httpContext.Vonk();
try
{
var auth = await httpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
if (auth?.Principal?.Identity?.IsAuthenticated ?? false)
{
var claims = auth.Principal.Claims ?? Enumerable.Empty<Claim>();
if (Authorized(vonkContext, claims))
{
await _next(httpContext);
}
else
{
vonkContext.Response.HttpResult = StatusCodes.Status401Unauthorized;
vonkContext.Response.AddIssue("You are not authorized for this request", VonkIssues.UNAUTHORIZED);
}
}
}
catch
{
//handle authentication errors;
}
}
private bool Authorized(IVonkContext context, IEnumerable<Claim> claims)
{
//The claims contain roles, or roles can be derived from the claims.
//Match them with the information in the request to allow or deny the request.
//If for example the claims contain the operations you are allowed to invoke, you could do:
switch (context.Request.Interaction)
{
case VonkInteraction.instance_read:
return claims.Any(claim => claim.Value == "read");
case Core.Context.VonkInteraction.instance_update:
return claims.Any(claim => claim.Value == "update");
case Core.Context.VonkInteraction.instance_delete:
return claims.Any(claim => claim.Value == "delete");
case Core.Context.VonkInteraction.type_create:
return claims.Any(claim => claim.Value == "create");
case Core.Context.VonkInteraction.type_search:
return claims.Any(claim => claim.Value == "search");
default:
return false;
}
}
}
}
@StephanMeijer
Copy link

StephanMeijer commented Aug 22, 2022

@cknaap What configuration would be required when receiving the following Exception?

firely.server_1  | 2022-08-22 18:59:16.303 +00:00 [UserId: ] [Username: ] [Error] [ReqId: 0HMK4E1KGEKFJ:00000002] An unhandled exception has occurred while executing the request.
firely.server_1  | Vonk.Core.Common.VonkConfigurationException: HttpContext does not have an IVonkContext feature. Please configure HttpToVonkMiddleware in the pipeline.
firely.server_1  |    at Vonk.Core.Context.Http.HttpContextExtensions.Vonk(HttpContext httpContext) in /__w/1/s/src/Vonk.Core/Context/Http/HttpContextExtensions.cs:line 14
firely.server_1  |    at Project.Facade.Plugin.AuthenticationMiddleware.Invoke(HttpContext httpContext) in /Users/steve/Projects/Project/Project.Facade/Project.Facade.Plugin/AuthenticationMiddleware.cs:line 21
firely.server_1  |    at Vonk.Core.Infra.Maintenance.RequestStatisticsMiddleware.Invoke(HttpContext context, RequestStatisticsService statisticsService) in /__w/1/s/src/Vonk.Core/Infra/Maintenance/RequestStatisticsMiddleware.cs:line 29
firely.server_1  |    at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
firely.server_1  | 2022-08-22 18:59:16.711 +00:00 [UserId: ] [Username: ] [Information] [ReqId: ] Reading SearchParameters from the Administration database - done.

and/or:

firely.server_1  |    at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
firely.server_1  | 2022-08-22 18:56:42.302 +00:00 [UserId: ] [Username: ] [Error] [ReqId: 0HMK4DSVR92PG:00000002] An unhandled exception has occurred while executing the request.
firely.server_1  | Vonk.Core.Common.VonkConfigurationException: HttpContext does not have an IVonkContext feature. Please configure HttpToVonkMiddleware in the pipeline.
firely.server_1  |    at Vonk.Core.Context.Http.HttpContextExtensions.Vonk(HttpContext httpContext) in /__w/1/s/src/Vonk.Core/Context/Http/HttpContextExtensions.cs:line 14
firely.server_1  |    at Vonk.Core.Pluggability.VonkInteractionAsyncMiddleware`1.ExecuteService(HttpContext httpContext) in /__w/1/s/src/Vonk.Core/Pluggability/VonkInteractionMiddleware.cs:line 177
firely.server_1  |    at Vonk.Core.Pluggability.VonkInteractionAsyncMiddleware`1.InvokeAsync(HttpContext httpContext) in /__w/1/s/src/Vonk.Core/Pluggability/VonkInteractionMiddleware.cs:line 159
firely.server_1  |    at Vonk.Core.Infra.Maintenance.RequestStatisticsMiddleware.Invoke(HttpContext context, RequestStatisticsService statisticsService) in /__w/1/s/src/Vonk.Core/Infra/Maintenance/RequestStatisticsMiddleware.cs:line 35
firely.server_1  |    at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment