2

This question is essentially the same as the one here, but, for asp.net core while using the asp.net core cookie middleware.

Is accessing query string/request body data possible on validation, and if it is, would you encourage the idea? It seems that according to this that it is very much possible, however, are the same rules in play from big boy asp.net (such as you are only to read the request data once in a given requests lifetime)?

Example: I'm creating an app where people have one account, but, are members of different teams. They can perform many different actions in the app, and, they can perform that action while in the "context" of one team or another that they are a member of. So, I have a teamId integer being passed in requests made to the server. I'd like to pull claims off the ClaimsPrincipal verifying that they really are a member of that team in the authorization portion of the pipeline.

Community
  • 1
  • 1
steamrolla
  • 1,968
  • 1
  • 23
  • 36

1 Answers1

7

As you said it is possible to access request's data on OnValidatePrincipal event. So, you can write something like this:

OnValidatePrincipal = async (context) =>
{
      if (context.Request.Path.Value.StartsWith("/teams/")) 
      {
          var teamId = // get team id from Path;

          if (user is not team member)
          {
              context.Response.StatusCode = 403;
          }
      }
} 

However, i think your requirement is related Authorization rather than Authentication. I would use Policy-Based Authorization to handle the requirement. Example policy should be like this:

Requirement and Handler:

public class TeamMemberHandler: AuthorizationHandler<TeamMemberRequirement>
{
    private readonly IActionContextAccessor _accessor; // for getting teamId from RouteData
    public TeamMemberHandler(IActionContextAccessor accessor)
    {
        _accessor = accessor;
    }
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TeamMemberRequirement requirement)
    {
        var teamId = // get teamId with using _accessor
        if (user is not member of team(by teamId))
        {
            context.Fail();
        }
        return Task.FromResult(0);
    }
}
public class TeamMemberRequirement : IAuthorizationRequirement
{
}

Configure Services:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
    services.AddAuthorization(options =>
    {
        options.AddPolicy("TeamMember",
                          policy => policy.Requirements.Add(new TeamMemberRequirement()));
    });

    services.AddSingleton<IAuthorizationHandler, TeamMemberHandler>();
}

Finally use it on top of controller(or if you want, you can add filter globally)

Authorize[(Policy = "TeamMember")]
public class TeamHomeController : Controller
{
    // Authorize[(Policy = "AnotherPolicy")]
    public IActionResult Index(){}
}
adem caglin
  • 17,749
  • 8
  • 44
  • 67
  • Awesome answer, thanks! But, to take it even a step further: is parameterizing policies possible? Let's say a user should have a claim saying that they have access to read some data when they send a GET `/some/endpoint?teamId=3`. They then try to update that data with a PUT against that same controller. This would require a claim saying that they can update this data. So, is parameterizing policies with those claim types possible? Or, would a new policy be needed for each? – steamrolla Jul 15 '16 at 12:12
  • Yes, you need a new policy for update and you should use it on top of update action method. – adem caglin Jul 15 '16 at 12:27
  • Bah! That will be a ton of different policies at the end of the day with the same code but different data. Maybe an enhancement from the asp.net core team in the future? – steamrolla Jul 15 '16 at 12:31
  • see http://stackoverflow.com/questions/36445780/how-to-implement-permission-based-access-control-with-asp-net-core – adem caglin Jul 15 '16 at 12:33