proper implementation of "windows" authentication in web api?

user9393635 picture user9393635 · Mar 29, 2018 · Viewed 16.9k times · Source

I've created a Web Api 2 app which will only be used on the corporate network. I've read about Windows authentication in Web API so it seems to be possible. But I need to figure out the proper implementation for this. I've included the following xml in my Web.config:

<system.web>
  <authentication mode="Windows" />   
</system.web>

I seem to remember some type of event hook in old school webforms app. Something like BeginRequest() where a security check could be made before rendering a page. I included the following line of code as the first line in one of my controller methods but the returned value appears to just be an empty object without any meaningful info:

var identity = HttpContext.Current.User.Identity as WindowsIdentity;

Does Web API 2 support Windows authentication? Am I missing a step? Should Windows authentication work if I submit a general request from Postman for testing? I also tried this code but got a similar empty object:

var x = RequestContext.Principal;

I vaguely recall an IIS setting like "Enable Integrated Security." Can you please specify the exact setting? And would I be able to accomplish this if I'm running the app on IIS Express?

UPDATE

I followed the steps for IIS Express mentioned in one of the answers below but the code samples that I provided in my original post still didn't get a populated user object. I also updated applicationhost.config file to turn off anonymous authentication:

<anonymousAuthentication enabled="false" userName="" />

After I made that updated I resubmitted my test request via Postman but I get the following error:

    <h3>HTTP Error 401.2 - Unauthorized</h3>
    <h4>You are not authorized to view this page due to invalid authentication headers.</h4>
</div>
<div class="content-container">
    <fieldset>
        <h4>Most likely causes:</h4>
        <ul>
            <li>No authentication protocol (including anonymous) is selected in IIS.</li>
            <li>Only integrated authentication is enabled, and a client browser was used that does not support integrated authentication.</li>
            <li>Integrated authentication is enabled and the request was sent through a proxy that changed the authentication headers before they reach the Web server.</li>
            <li>The Web server is not configured for anonymous access and a required authorization header was not received.</li>
            <li>The "configuration/system.webServer/authorization" configuration section may be explicitly denying the user access.</li>
        </ul>
    </fieldset>
</div>
<div class="content-container">
    <fieldset>
        <h4>Things you can try:</h4>
        <ul>
            <li>Verify the authentication setting for the resource and then try requesting the resource using that authentication method.</li>
            <li>Verify that the client browser supports Integrated authentication.</li>
            <li>Verify that the request is not going through a proxy when Integrated authentication is used.</li>
            <li>Verify that the user is not explicitly denied access in the "configuration/system.webServer/authorization" configuration section.</li>
            <li>Check the failed request tracing logs for additional information about this error. For more information, click 
                <a href="http://go.microsoft.com/fwlink/?LinkID=66439">here</a>.
            </li>
        </ul>
    </fieldset>
</div>

Do I need to configure my Postman request with some type of special header in order for this to work?

Answer

Adrita Sharma picture Adrita Sharma · Mar 27, 2019

In addition to the previous answers, we also need to Pass credentials in cross-origin requests.

Server Side (Web API):

Set the SupportsCredentials property to true on the [EnableCors] attribute:

[EnableCors(origins: "http://exampleclient.com", headers: "*", 
methods: "*", SupportsCredentials = true)]

Client Side (UI):

Set XMLHttpRequest.withCredentials to true.

jQuery:

$.ajax({
  type: 'get',
  url: 'http://www.example.com/api/auth',
  xhrFields: {
    withCredentials: true
  }

Angular:

this.http.get('http://www.example.com/api/auth', { withCredentials: true }).subscribe((resp: any) => {
  console.log(resp)
}

XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/api/auth');
xhr.withCredentials = true;