Mediatr: Integrate MediatR Authorization Behavior with ASP.NET Core Recource Based Authorization

Created on 30 Aug 2018  路  4Comments  路  Source: jbogard/MediatR

I am using MediatR on an ASP.NET Core 2.1 application and I have the following example:

public class GetPostsRequest : IRequest<Envelope<GetPostsResponse>> { }

public class GetPostsResponse { }

I am trying to define two MediatR behaviors:

  1. A ValidationBehavior to validate the Requests;

  2. A AuthorizationBehavior to authorize or not the Request and to "Shape" the Response, for example, to remove items for the Response that the user has not permission to access.

    Is it possible to integrate such an AuthorizationBehavior with ASP.NET Core Authorization Service and AuthorizationHandler?

    I am asking this because it seems ASP.NET Core AuthorizationHandlers expects Requirements:
    https://docs.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?view=aspnetcore-2.1&tabs=aspnetcore2x#write-a-resource-based-handler

    Not only the resource ...

Most helpful comment

I know this thread is closed, but I strongly disagree with @bartosz6 's comment about single responsibility. In fact, if you don't move your authorization logic closer to the messages, it can lead to unauthorized access to a resource. Consider this example: You have some data service with BasicQuery and AdvancedQuery requests. Part of BasicResult must be obfuscated based on some policy. The developer decides that since part of AdvancedResult is the same (and must equal to) BasicResult, it's best to just send a BasicQuery and use the data from the response. Unless we do message-level authorization in this scenario, any change to the policies for BasicQuery must also be made to any endpoint that explicitly or implicitly invokes it, otherwise the same policies will not be applied.
In my opinion the best approach here is to put the Authorization attributes on the request types and add a pipeline behavior (in the host) that performs authorization.

All 4 comments

I don鈥檛 think you would really want to, why tie the frameworks together? You could leverage authorisation in your pipeline, but authentication?

Don鈥檛 get me wrong you could fire requests off from auth handlers, but if you鈥檙e saying tight integration... I probably wouldn鈥檛 try

I don鈥檛 think you would really want to, why tie the frameworks together? You could leverage authorisation in your pipeline, but authentication?

Maybe I am missing something but I was describing the integration of Authorization.

Consider the following Controller's Action of an API I am working on:

    [HttpGet("projects")]
    public async Task<IActionResult> GetProjects(GetProjectsRequest request) {

      // Step 1
      // Request's Authorization
      AuthorizationResult authorization = await _authorizer.AuthorizeAsync(User, request, Policies.AuthenticatedAndMember);

      if (!authorization.Succeeded)
        return Unauthorized();

      // Step 2
      // Request's Validation
      List<Error> errors = await _validator.ValidateAsync(request);

      if (errors.Any())
        return BadRequest(errors);

      // Step 3
      // Send Request and get Response
      GetProjectsResponse response = await _mediator.Send(request);

      // Step 4
      // Reshape response in case the User is not Authorized to view some data.
      // For example, for a list of projects, only an administrator can see all project properties.
      // If the user is not administrator I set some properties to not be serielized.
      GetProjectsResponse response = await _authorizer.AuthorizeAsync(User, response, Policies.AuthenticatedAndMember);

      // Step 5
      // Return response
      return Ok(response);

    }

I few questions I have on each Step:

  1. On Step 1: _authorizer.AuthorizeAsync(User, request, Policies.AuthenticatedAndMember)
    So the Policies (or Requirements) can vary according to the Request.
    This makes a little bit difficult to integrate with the mediator pipeline as a behavior, not?

  2. On Step 4: Should this be integrated into the Handler?
    Do you use other options to shape the response according to user permissions?

This was my idea to integrate everything with Mediator Pipeline but it does not seem very easy.

I would not move authorization inside mediator. Execution order of behaviors cannot be guaranteed. MVC attributes seems to be the simplest way. Anyway it is possible, but you would have to include User and Policies in your request to mediator.

According to step 4 - this is violation of single responsibility principle as well as security issue. It is better to create separated endpoint for administrators.

I know this thread is closed, but I strongly disagree with @bartosz6 's comment about single responsibility. In fact, if you don't move your authorization logic closer to the messages, it can lead to unauthorized access to a resource. Consider this example: You have some data service with BasicQuery and AdvancedQuery requests. Part of BasicResult must be obfuscated based on some policy. The developer decides that since part of AdvancedResult is the same (and must equal to) BasicResult, it's best to just send a BasicQuery and use the data from the response. Unless we do message-level authorization in this scenario, any change to the policies for BasicQuery must also be made to any endpoint that explicitly or implicitly invokes it, otherwise the same policies will not be applied.
In my opinion the best approach here is to put the Authorization attributes on the request types and add a pipeline behavior (in the host) that performs authorization.

Was this page helpful?
0 / 5 - 0 ratings