2

I'm trying to implement an application that uses the same Token Based Authentication mechanism demonstrated in this really awesome example by Taiseer Joudeh.

In my application I kept encountering Cors problems. In some configurations I would get a 500 error on the Preflight (OPTIONS) request for the POST to get the token or I could get the token but then get a 404 error on the preflight request for the GET request to the actual API call with the Bearer token.

One difference was that Taiseer's code was setup to host in IISExpress (or Azure) and mine is hosted on Local IIS (running on Windows 7 at the moment).

On a hunch I tried hosting his API under Local IIS and I found the exact same problem. (500 error on the preflight request for the token and it looks like the actual API will work properly)

From what I've been reading it seems like this may be some conflict between the modules and handlers in IIS and the Cors implementation in WebApi but Taiseer's implementation works when hosted in Azure so perhaps it is a difference in the version of IIS (I'm currently running under Windows 7).

How can I sort out what is causing the problem?

RonnBlack
  • 3,998
  • 6
  • 26
  • 28
  • 2
    You have to be more specific about the error you are getting. Investigate which exception is causing the 500 server error (try to debug remotely if needed), or if none find what is the IIS internal error inside the logs. We have not enough information to help you at the moment. – Federico Dipuma Apr 20 '16 at 12:13

3 Answers3

3

The root of the problem

The Token action is not hosted in a controller but is instead built in somewhere in the lower level plumbing. The only access to the mechanism is through the override method GrantResourceOwnerCredentials() in the class that extends OAuthAuthorizationServerProvider. (In our case is ApplicationOAuthProvider.cs).

GrantResourceOwnerCredentials() does have the context available but it is not called as part of the PreFlight request so you have no way to insert the appropriate PreFlight response headers for CORS.

The solution

We eventually settled on the following solution. I'm not a big fan of it because it forces these headers into every response but at least it works.

The solution was to override Application_PreSendRequestHeaders() method in Global.asax to insert the appropriate headers.

Global.asax.cs

    void Application_PreSendRequestHeaders(Object sender, EventArgs e)
    {
        var origin = Request.Headers.Get("Origin");
        var validOrigins = ConfigurationManager.AppSettings["allowedCorsOrigins"].Split(',');
        if(validOrigins.Any(o => o == origin))
        {
            Response.Headers.Set("Access-Control-Allow-Origin", origin);
            Response.Headers.Set("Access-Control-Allow-Credentials", "true");
            Response.Headers.Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, withcredentials, Prefer");
            Response.Headers.Set("Access-Control-Expose-Headers", "Claims, *");
            Response.Headers.Set("Access-Control-Max-Age", "600");
            Response.Headers.Set("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
        }
    }

This requires the following web.config entries:

web.config

<configuration>
  <appSettings>
    <add key="allowedCorsOrigins" value="http://www.allowedsite1.net,http://localhost:22687" />
    <add key="allowedCorsMethods" value="get, post, put, delete, options, batch" />
    <add key="allowedCorsHeaders" value="*" />
  </appSettings>
...
</configuration>

The reason for the loop to search for the valid origins is that you can't respond with a list of allowed origins...

This solved most of the problems with one exception (If I recall correctly was problems with PUT and DELETE verbs). This required removing the "ExtensionlessUrlHandler-Integrated-4.0" and re-adding it with a path and verb in the handlers section of the web.config.

web.config (2nd change)

<system.webServer>
    <handlers>
        <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
        <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="" />
    </handlers>
    ....
</system.webServer>

Useful links related CORS

RonnBlack
  • 3,998
  • 6
  • 26
  • 28
  • 1
    You should accept your answer to close the question. In the meantime, Microsoft later shipped IIS CORS module for such, https://learn.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference – Lex Li Sep 03 '18 at 14:26
2

It is not the IdentityServer you are using but it could be the same problem. Regarding to the IdentityServer´s Github page you have to activate RAMMFAR (runAllManagedModulesForAllRequests) for your application when running under the IIS.

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
  </modules>
</system.webServer>
Hypnobrew
  • 1,120
  • 9
  • 23
1

I had this same issue, I did everythin as suggested by Mr. Tom hall. But still chrome reported no Access-control-allow-origin header is present.. after inspecting with fidler i realized that my request goes through a proxy server and my proxy server is handling the preflight options request..

So in "internet options" i removed the proxy server and found out that everything is working...!!!

Pradeep
  • 581
  • 3
  • 11
  • 19