401 response for CORS request in IIS with Windows Auth enabled

自作多情 提交于 2019-11-26 02:34:00

问题


I\'m trying to enable CORS support in my WebAPI project, and if I enable Anonymous Authentication then everything works fine, but with Windows Auth + disabled anonymous authentication, the OPTIONS request sent always returns a 401 unauthorized response. The site requesting it is on the DOMAIN so should be able to make the call, is there any way to get around the issue without disabling Windows Authentication?


回答1:


You can allow only OPTIONS verb for anonymous users.

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

According W3C specifications, browser excludes user credentials from CORS preflight: https://dvcs.w3.org/hg/cors/raw-file/tip/Overview.html#preflight-request




回答2:


Several years later, but through the answer from @dariusriggins and @lex-li I have managed to add the following code to my Global.asax:

    public void Application_BeginRequest(object sender, EventArgs e)
    {
        string httpOrigin = Request.Params["HTTP_ORIGIN"];
        if (httpOrigin == null) httpOrigin = "*";
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", httpOrigin);
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Token");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.HttpMethod == "OPTIONS")
        {
            HttpContext.Current.Response.StatusCode = 200;
            var httpApplication = sender as HttpApplication;
            httpApplication.CompleteRequest();
        }
    }

the httpOrigin is actually looked up in a list of allowed hosts but that just complicated things. This means that all other requests are validated but options just returns.

Thanks for this question, I would have been lost without it!




回答3:


From MS:

If you disable anonymous authentication, it’s by design that IIS would return a 401 to any request. If they have enabled Windows auth, the 401 response in that case would have a WWW-Authenticate header to allow the client to start an authentication handshake. The question then becomes whether the client that the customer is using can do Windows authentication or not.

Finally, it seems like there might be an underlying question about whether it’s possible or not to configure a URL such that anonymous access is allowed for one verb (OPTIONS, in this case), but require Windows authentication for other verbs. IIS does not support this through simple configuration. It might be possible to get this behavior by enabling both Anonymous and Windows authentication, setting ACLs on the content that deny access to the anonymous user, and then configuring the handler mapping for the URL in question so that it does not verify the existence of the file associated with the URL. But it would take some playing with it to confirm this.




回答4:


The easiest way to fix this is to create a rewrite rule with the condition request_method = ^OPTIONS$. Then set the action to be a custom response, set that to 200 OK. Then all options requests will respond with 200 instead of 401. This will fix the CORS issue.

Of course you still need to make sure you have the correct cross origin request headers.

This will stop options requests (which dont have any credentials) responding with 401 when integrated auth is enabled.




回答5:


The accepted answer is correct however I was troubleshooting a rest api with a "node with iisnode and npm cors module" setup for a while and was not comfortable with just enabling anonymous authentication for all users. Since its a node application the system.web tag does not do much. I ended up with the following addition to the web.config:

<system.webServer>
<security>
  <requestFiltering>
    <hiddenSegments>
      <add segment="node_modules" />
    </hiddenSegments>
  </requestFiltering>
  <authorization>
    <add accessType="Allow" verbs="OPTIONS" users="?" />
    <add accessType="Deny" verbs="GET, PUT, POST, DELETE" users="?" />
  </authorization>
</security>
</system.webServer>



回答6:


I've run into same issue today due to bug in IE 10 and 11, I'm using ServiceStack instead of WebApi, but the approach can work for you as well.

  1. Enabled Windows Integrated and Anonymous Authentication on IIS Web Site.
  2. Have a series of filters on the ServiceStack Pipeline,
    • For handling Cors and OPTIONS request, On Options request, I add necessary headers and end the request,
    • Filter for checking includng HttpRequest is Authenticated?,
    • etc filter,

After passing through all the filters, it executes the service.

CorsFeature.cs

AuthenticateFilter

In my AppHost,

appHost.Plugins.Add(new CorsFeature());

appHost.RequestFilters.Add(AuthenticateFilter.Authenticate);

I have modified the CorsFeature to handle OptionsRequest's in addition to adding headers, Authenticate Filter to check for requests authenticated!




回答7:


Related Question: IIS hijacks CORS Preflight OPTIONS request

Merging info from answers found in multiple places. If you need to enable CORS on a ASP.net page method with Windows Authentication on the intranet, this is what seems to work. Without the changes to web.config, this doesn't work.

You need to add this to Global.asax

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        string httpOrigin = HttpContext.Current.Request.Params["HTTP_ORIGIN"] ?? HttpContext.Current.Request.Params["ORIGIN"] ?? "*";
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", httpOrigin);
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Token");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            HttpContext.Current.Response.StatusCode = 200;
            var httpApplication = sender as HttpApplication;
            httpApplication.CompleteRequest();
        }
    }

And this to web.config

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



回答8:


I'm using Web API and OWIN and I tried every suggested solution but the only thing that worked was the following

//use it in your startup class
app.Use((context, next) =>
{
    if (context.Request.Headers.Any(k => k.Key.Contains("Origin")) && context.Request.Method == "OPTIONS")
    {
        context.Response.StatusCode = 200;
        context.Response.Headers.Add("Access-Control-Allow-Origin", new string[1] { "ALLOWED_ORIGIN" });
        context.Response.Headers.Add("Access-Control-Allow-Headers", new string[4] { "Origin", "X-Requested-With", "Content-Type", "Accept" });
        context.Response.Headers.Add("Access-Control-Allow-Methods", new string[5] { "GET", "POST", "PUT", "DELETE", "OPTIONS" });
        context.Response.Headers.Add("Access-Control-Allow-Credentials", new string[1] { "true" });

        return context.Response.WriteAsync("");
    }

    return next.Invoke();
});

//this is important! Without it, it didn't work (probably because the middleware was too late)
app.UseStageMarker(PipelineStage.Authenticate);

you need to insert this code somewhere in one of your OWIN startup classes. It's important to call app.UseStageMarker(PipelineStage.Authenticate) because otherwise the preflight check failed. Further infos for UseStageMarker -> https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-middleware-in-the-iis-integrated-pipeline

It's also important that you need to explicitly define the allowed headers. It will fail if you use * as a placeholder.

Maybe it helps somebody.




回答9:


I understand this is an old question with several possible solutions (as well as more questions), but in case anyone else comes across this, IIS CORS 1.0 is available as of Nov '17:

https://blogs.iis.net/iisteam/introducing-iis-cors-1-0

https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference

You can download it through IIS Windows Platform Installer (WPI). This should resolve many of your CORS authentication issues. Enjoy!




回答10:


Extending the answer provided by @dariusriggins. Check this post: Microsoft | Developer: Putting it all together – CORS tutorial

For IIS Configurations:

Authorization rule

Authorization stage (or Authorization event), we need to make sure we only allow the anonymous requests from CORS preflight and require all other incoming requests have authentication credentials supplied. We can achieve this through Authorization Rules. A default authorization rule granting all users access to the site is already in place and supplied by default by IIS. We will start by modifying this rule to only allow anonymous users, if they send requests that are using the OPTIONS http verb. Below is the target configuration in IIS for this authorization rule:

Edit Authorization rule




回答11:


What worked for me (when working with AngularJS or JQuery) is to add withCredentials:true to each request on client:

$http.get("http://localhost:88/api/tests", {withCredentials :true})

And enabling CORS on server, this was done with Microsoft.Owin.Cors from nuget and adding it in Startup like below:

public void Configuration(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();

        ConfigureOAuth(app);

        WebApiConfig.Register(config);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        app.UseWebApi(config);

    }

References:

  • CORS on server (see step 11): http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
  • CORS on client: http://brockallen.com/2012/12/15/cors-and-windows-authentication/



回答12:


Enabling SupportCredentials on EnableCorsAttribute in WebApiConfig.cs did the trick for me:

public static void Register(HttpConfiguration config)
{        
    //enable cors request just from localhost:15136 
    var cors = new EnableCorsAttribute("http://localhost:15136", "*", "*");
    cors.SupportsCredentials = true;
    config.EnableCors(cors);

    //other stuff
}

https://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

Make sure you send credentials when calling from javascript ({withCredentials :true})



来源:https://stackoverflow.com/questions/10723088/401-response-for-cors-request-in-iis-with-windows-auth-enabled

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!