2

I have an almost working implementation of OAuth2 in asp.net 5 (RC1). My solution is based upon the code given by Mark Hughes in Token Based Authentication in ASP.NET 5 (vNext), which is brilliant.

My problem is that my setup is using CORS requests and almost every request is preceded by an OPTIONS request. Even though I only apply the Authorize attribute to the GetAll controller action/method, as shown below, the preceding OPTIONS request is authorized as well.

[Route("api/[controller]")]
public class TextController : Controller
{
    [HttpGet]
    [Authorize("Bearer", Roles = "admin")]
    public IEnumerable<string> GetAll()
    {
        return _repository.GetAll;
    }

    ...
}

The authorization service setup in startup.cs looks like this:

services.AddAuthorization(auth =>
        {
            auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
                .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)
                .RequireAuthenticatedUser().Build());
        });

Is ther any way I can change the behavior of the authorization middleware to skip authorization of OPTIONS requests?

Note:

I have tried creating my own authorization attribute, but for some reason IsAuthenticated always evaluates to false, as if the authorization has not happened yet when reaching this code:

public class BearerAuthorizationAttribute : Attribute, IAuthorizationFilter
{
    private readonly string Role;
    public BearerAuthorizationAttribute(string Role = null)
    {
        this.Role = Role;
    }
    [Authorize("Bearer")]
    public void OnAuthorization(Microsoft.AspNet.Mvc.Filters.AuthorizationContext context)
    {
        string meth = context.HttpContext.Request.Method;
        if (meth != "OPTIONS")
        {

            if (!context.HttpContext.User.Identity.IsAuthenticated)
            {
                context.Result = new ContentResult() { Content = "Unauthorized", StatusCode = 401 };
                return;
            }
            if (Role != null && !context.HttpContext.User.IsInRole(Role))
            {
                context.Result = new ContentResult() { Content = "Unauthorized, role level insufficient", StatusCode = 401 };
                return;
            }
        }

    }
}
Community
  • 1
  • 1
Sjolund
  • 519
  • 5
  • 10

1 Answers1

2

I finally figured out how to fix my problem. In my Startup.cs I was using services.AddCors, like so:

// Create CORS policies
services.AddCors(options =>
{
    // Define one or more CORS policies
    options.AddPolicy("AllowSpecificOrigin",
        builder =>
        {
            builder.WithOrigins(Configuration.Get<string[]>("AppSettings:AllowedOrigins")) // TODO: revisit and check if this can be more strict and still allow preflight OPTION requests
                        .AllowAnyMethod() 
                        .AllowAnyHeader();
        }
    );
});
// Apply CORS policy globally
services.Configure<MvcOptions>(options =>
{
    options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
});

It turns out that this only worked partially.

The solution for me was to do app.UseCors in stead, i.e., delete the code above and doing this:

app.UseCors(builder =>
{
    builder.WithOrigins(Configuration.Get<string[]>("AppSettings:AllowedOrigins")) // TODO: revisit and check if this can be more strict and still allow preflight OPTION requests
        .AllowAnyMethod()
        .AllowAnyHeader();
});

When using app.UseCors I get fully working CORS handling, which bounces the OPTIONS reqests before they are being authorized.

The solution is inspired by CORS is not working in web api with OWIN authentication.

Community
  • 1
  • 1
Sjolund
  • 519
  • 5
  • 10