aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

FallbackPolicy takes precedence over AuthorizeFilters added using Conventions

Open moanrose opened this issue 3 years ago • 7 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

Security policies applied using the MvcOptions.Conventions does not apply if a FallbackPolicy is specified

I want to add a security policy for a controller using MvcOptions.Conventions, if no FallbackPolicy is specified the security policies are evaluated as expected. However if a FallbackPolicy is specified, only that applies.

Expected Behavior

I would expect the AuthorizeFilters added using Conventions to take precedence over the FallbackPolicy

Steps To Reproduce

The following code should be sufficient to reproduce the problem

using Microsoft.AspNetCore.Authentication.Negotiate;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Authorization;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
    options.Conventions.Add(new AllowAnonymousConvention());
});
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("allowAnonymous", new AuthorizationPolicyBuilder()
        .RequireAssertion(_ => true)
        .Build());
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAssertion(_ => false)
        .Build();
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

[ApiController]
[Route("[controller]")]
public class HelloWorldController : ControllerBase
{
    [HttpGet]
    public string Get()
    {
        return "Hello world";
    }
}

public class AllowAnonymousConvention : IControllerModelConvention
{
    public void Apply(ControllerModel controller)
    {
        if (controller.ControllerType.Equals(typeof(HelloWorldController)))
        {
            controller.Filters.Add(new AuthorizeFilter(new IAuthorizeData[]
            {
                new AuthorizeAttribute("allowAnonymous")
            }));
        }
    }
}

Exceptions (if any)

No response

.NET Version

6.0.101

Anything else?

No response

moanrose avatar Feb 02 '22 10:02 moanrose

@HaoK i believe this is expected right? You shouldn't mix policies and filters

blowdart avatar Feb 02 '22 17:02 blowdart

It's weirder - the AuthZ middleware will evaluate the fallback policy since it does not see the filter, and MVC will then execute the filter. Applying the attribute directly to the controller would be the easiest way to do this. You might also be able to add the AttributeAttribute to SelectorModel.EndpointMetadata but I haven't really tried it out to see if it works.

pranavkm avatar Feb 02 '22 23:02 pranavkm

Yeah this isn't really something we designed for, its more like a gap

HaoK avatar Feb 03 '22 00:02 HaoK

Yes, using the SelectorModel.EndpointMetadata does the trick

public class AllowAnonymousConvention : IActionModelConvention
{
    public void Apply(ActionModel action)
    {
        if (action.Controller.ControllerType.Equals(typeof(HelloWorldController)))
        {
            foreach (var s in action.Selectors)
            {
                s.EndpointMetadata.Add(new AuthorizeAttribute("allowAnonymous"));
            }
        }
    }
}

I would however argue that this behaviour is counter intuitive

moanrose avatar Feb 03 '22 07:02 moanrose

Triage: Fallback policies take precedence over auth filters and should not be used together. Worth documenting.

Tratcher avatar Feb 04 '22 21:02 Tratcher

Thanks for contacting us.

We're moving this issue to the .NET 7 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

ghost avatar Feb 04 '22 21:02 ghost

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

ghost avatar Oct 11 '22 19:10 ghost

Fixed via updated docs

wtgodbe avatar Oct 17 '22 17:10 wtgodbe