Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebAPI CORS with Windows Authentication - allow Anonymous OPTIONS request

Tags:

I have a WebAPI 2 REST service running with Windows Authentication. It is hosted separately from the website, so I've enabled CORS using the ASP.NET CORS NuGet package. My client site is using AngularJS.

So far, here's what I've been through:

  1. I didn't have withCredentials set, so the CORS requests were returning a 401. Resolved by adding withCredentials to my $httpProvider config.
  2. Next, I had set my EnableCorsAttribute with a wildcard origin, which isn't allowed when using credentials. Resolved by setting the explicit list of origins.
  3. This enabled my GET requests to succeed, but my POST issued a preflight request, and I hadn't created any controller actions to support the OPTIONS verb. To resolve this, I've implemented a MessageHandler as a global OPTIONS handler. It simply returns 200 for any OPTIONS request. I know this isn't perfect, but works for now, in Fiddler.

Where I'm stuck - my Angular preflight calls aren't including the credentials. According to this answer, this is by design, as OPTIONS requests are designed to be anonymous. However, the Windows Authentication is stopping the request with a 401.

I've tried putting the [AllowAnonymous] attribute on my MessageHandler. On my dev computer, it works - OPTIONS verbs do not require authentication, but other verbs do. When I build and deploy to the test server, though, I am continuing to get a 401 on my OPTIONS request.

Is it possible to apply [AllowAnonymous] on my MessageHandler when using Windows Authentication? If so, any guidance on how to do so? Or is this the wrong rabbit hole, and I should be looking at a different approach?

UPDATE: I was able to get it to work by setting both Windows Authentication and Anonymous Authentication on the site in IIS. This caused everything to allow anonymous, so I've added a global filter of Authorize, while retaining the AllowAnonymous on my MessageHandler.

However, this feels like a hack...I've always understood that only one authentication method should be used (no mixed). If anyone has a better approach, I'd appreciate hearing about it.

like image 400
Dave Simione Avatar asked Dec 11 '14 02:12

Dave Simione


People also ask

Can we use Windows authentication in Web API?

a) To create a web api project in windows authentication mode, follow below steps: After choosing ASP.Net Web Application, select Web API template and from the right side click Change Authentication button and select Windows Authentication.

How do I enable CORS in startup CS?

Install the CORS middleware. Add the CORS middleware to the pipeline in the ConfigureServices method. Enable CORS in the Configure method. Enable CORS in the controllers, the action methods, or globally.


2 Answers

I used self-hosting with HttpListener and following solution worked for me:

  1. I allow anonymous OPTIONS requests
  2. Enable CORS with SupportsCredentials set true
var cors = new EnableCorsAttribute("*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
var listener = appBuilder.Properties["System.Net.HttpListener"] as HttpListener;
if (listener != null)
{
    listener.AuthenticationSchemeSelectorDelegate = (request) => {
    if (String.Compare(request.HttpMethod, "OPTIONS", true) == 0)
    {
        return AuthenticationSchemes.Anonymous;
    }
    else
    {
        return AuthenticationSchemes.IntegratedWindowsAuthentication;
    }};
}
like image 84
Igor Tkachenko Avatar answered Oct 14 '22 08:10

Igor Tkachenko


I have struggled for a while to make CORS requests work within the following constraints (very similar to those of the OP's):

  • Windows Authentication for all users
  • No Anonymous authentication allowed
  • Works with IE11 which, in some cases, does not send CORS preflight requests (or at least do not reach global.asax BeginRequest as OPTIONS request)

My final configuration is the following:

web.config - allow unauthenticated (anonymous) preflight requests (OPTIONS)

<system.web>
    <authentication mode="Windows" />
    <authorization>
        <allow verbs="OPTIONS" users="*"/>
        <deny users="?" />
    </authorization>
</system.web>

global.asax.cs - properly reply with headers that allow caller from another domain to receive data

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (Context.Request.HttpMethod == "OPTIONS")
    {
        if (Context.Request.Headers["Origin"] != null)
            Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);

        Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, MaxDataServiceVersion");
        Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");

        Response.End();
    }
}

CORS enabling

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // all requests are enabled in this example. SupportsCredentials must be here to allow authenticated requests          
        var corsAttr = new EnableCorsAttribute("*", "*", "*") { SupportsCredentials = true };
        config.EnableCors(corsAttr);
    }
}

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
}
like image 22
Alexei - check Codidact Avatar answered Oct 14 '22 08:10

Alexei - check Codidact