microsoft-identity-web icon indicating copy to clipboard operation
microsoft-identity-web copied to clipboard

[Bug] RequiredScope doesn't work when securing controllers by setting AuthorizationOptions.FallbackPolicy

Open lucmoco opened this issue 2 years ago • 2 comments

Which version of Microsoft Identity Web are you using? Microsoft Identity Web 1.22.1

Where is the issue?

  • Web app
    • [ ] Sign-in users
    • [ ] Sign-in users and call web APIs
  • Web API
    • [ ] Protected web APIs (validating tokens)
    • [x] Protected web APIs (validating scopes)
    • [ ] Protected web APIs call downstream web APIs
  • Token cache serialization
    • [ ] In-memory caches
    • [ ] Session caches
    • [ ] Distributed caches
  • Other (please describe)

Is this a new or an existing app? This is a new app or an experiment.

Repro

I'm trying to protect an API controller method (here in the standard WeatherForecastController sample controller) with the RequiredScopeAttribute, so that only calls having the Weather.Read scope succeed.

[RequiredScope("Weather.Read")]
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = Random.Shared.Next(-20, 55),
        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    })
    .ToArray();
}

I have configured JWT Bearer authentication as follows in Program.cs:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration);

builder.Services.AddAuthorization(options => options.FallbackPolicy = options.DefaultPolicy);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Note that with the statement

builder.Services.AddAuthorization(options => options.FallbackPolicy = options.DefaultPolicy);

Authentication should be required for all controllers.

I have also configured an AAD application for the API, exposing two scopes, Weather.Read and Data.Read.

Expected behavior When calling the endpoint with scope Data.Read but without Weather.Read, the call should be unauthorized.

Actual behavior When calling the endpoint with scope Data.Read but without Weather.Read, the call succeeds. The security check used to work however with previous versions of the library. I've done the test with the following versions:

  • 1.16.1 => OK (unauthorized)
  • 1.17.0 => OK (unauthorized)
  • 1.18.0 => scope not checked (200 response)
  • 1.19.0 => scope not checked (200 response)
  • 1.20.0 => scope not checked (200 response)
  • 1.22.1 => scope not checked (200 response)

Note that if I require authorization by other means than setting the FallbackPolicy, the scope check works, even in 1.22.1, for example:

  • Specifying app.MapControllers().RequireAuthorization(); in Program.cs.
  • Adding an [Authorize] attribute for the whole controller.

If I add a manual check in the controller method, the check also detects that the required scope Weather.Read is missing:

HttpContext.VerifyUserHasAnyAcceptedScope("Weather.Read");

Possible solution

Additional context / logs / screenshots / link to code

lucmoco avatar Jan 27 '22 14:01 lucmoco

@DavidFowl Can you assist with this? This is related to the changes we did for moving from Filters to Policies. Appreciate any advice on how to resolve this.

jennyf19 avatar Jan 27 '22 18:01 jennyf19

This is still not solved in Microsoft.Identitty.Web 2.12.4. This is a security problem and should be fixed urgently ! @davidfowl, @jennyf19, any input ?

lucmoco avatar Oct 06 '23 14:10 lucmoco