Search code examples
c#iisasp.net-web-apiwindows-authenticationangular

Browser OPTIONS request method and windows authorization


I'm trying to POST data from my Angular 2 service to ASP.NET 5 API that uses windows authentication and is hosted on IIS. After some modification to angular, requests are created with:

var request = new XMLHttpRequest();
request.withCredentials = true;

That's solved my problem with authorizing GET requests, now for a first GET request, server returns 401 response with headers:

WWW-Authenticate:Negotiate
WWW-Authenticate:NTLM

And after that angular client sends an another request, but this time with a Authorization header that contains NTLM token and it works.

For POST request I added "Content-Type: application/json" to request's header, so browser sends a first request like this:

OPTIONS /api/reservation/ HTTP/1.1
Host: localhost:82
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: http://localhost:81
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Referer: http://localhost:81/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4

And server responds with:

HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/8.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Wed, 13 Jan 2016 11:54:56 GMT
Content-Length: 6394

But this time, instead of another request with authorization, like in GET request, there's an error:

XMLHttpRequest cannot load http://localhost:82/api/reservation/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:81' is therefore not allowed access. The response had HTTP status code 401.

For CORS I use this configuration in ASP.NET 5:

services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin().AllowAnyMethod().WithHeaders("accept", "authorization", "content-type", "origin", "x-custom-header").AllowCredentials()));

Can I somehow disable windows authentication for OPTIONS requests in IIS? Or maybe there's some way to force browser to follow up with authorization?


Solution

  • Ok, I found a way to make it work on IIS Express or IIS 8.5, with ASP.NET 5.

    We need to modify wwwroot/web.config like this:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.webServer>
        <handlers>
          <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
        </handlers>
        <httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" startupTimeLimit="3600" forwardWindowsAuthToken="true"></httpPlatform>
        <httpProtocol>
          <customHeaders>
            <add name="Access-Control-Request-Headers" value="Content-Type,Authorization" />
            <add name="Access-Control-Allow-Headers" value="Content-Type,Authorization" />
            <add name="Access-Control-Allow-Origin" value="http://localhost:5814" />
            <add name="Access-Control-Allow-Credentials" value="true" />
          </customHeaders>
        </httpProtocol>
        <security>
          <authorization>
            <!--<remove users="*" roles="" verbs="" />  Uncomment for IIS-->
            <add accessType="Allow" users="*" verbs="GET,POST,PUT" />
            <add accessType="Allow" users="?" verbs="OPTIONS" />
            <add accessType="Deny" users="?" verbs="GET,POST,PUT" />
          </authorization>
        </security>
      </system.webServer>
      <system.web>
        <authorization>
          <allow users="*" verbs="GET,POST,PUT" />
          <allow users="?" verbs="OPTIONS" />
        </authorization>
      </system.web>
    </configuration>
    

    In launchSettings.json set:

    "iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:4402/",
      "sslPort": 0
    }
    

    And in Startup.cs:

    services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyMethod().WithHeaders("accept", "authorization", "content-type", "origin", "x-custom-header").AllowCredentials()));
    

    Some of these settings might be not neccesary.

    For IIS we need to install Windows Authentication and URL Authorization.