8

I am using multiple intranet APIs to try to build out some applications that have some services that are shared by all of the applications. A lot of these services can be called directly from the GUI using Javascript requests, however a couple of the services need to be called by the other server applications.

All of the front ends and APIs are using Windows Authentication. Right now I've got it set to authorize any Windows authenticated user. Anonymous authentication is disabled.

I'm using HttpClient to connect to the needed service from within the web code. Here's an example:

HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["OtherServiceUrl"]);

client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

SomeResponseObject responseObject;
HttpResponseMessage response = client.GetAsync("SomeController").Result;
if (response.IsSuccessStatusCode)
{
    responseObject = response.Content.ReadAsAsync<SomeResponseObject>().Result;
}
else
{
    throw new ApplicationException("API request not successful");
}

The good news is that this works just fine when I'm running the services locally. The bad news is that when I deploy to IIS, the call to the web service fails with a Unauthorized response.

After a lot of fiddling around, I realized the only time that I get an Unauthorized response is when the domain of the target API is the same as the domain of the calling application. It worked on my local box because IIS express assigns a new port to each application. The matching domain situation occurred in IIS because I created both the calling application and the API as applications under the same site in IIS, so the two applications look like directories in the same domain. It's almost like HttpClient doesn't bother to send over the authentication from the calling web application if it notices that the domains match.

I created a new site on the same server but bound to a different port and put the API there instead and tried again. Sure enough, that resolves the problem, the request from the API passes through just fine.

I can put in a bunch of sub domains to handle all of these different services, or just rely on using different ports in order to make the domains for these services unique, but it seems odd to me that this limitation is in place. Does anyone know if there's a property I can set on the handler or client or something else I can do to allow applications running on the same IIS site to talk to each other via HttpClient when Windows Authentication is used?

Thanks!

Per Sachin's suggestion, I also tried adding this to the webconfig of the application that makes the API request via HttpClient:

<system.net>
  <defaultProxy useDefaultCredentials="true" />
</system.net>

Still no luck.

  • This may help, try adding config entry: http://stackoverflow.com/questions/299940/how-should-i-set-the-default-proxy-to-use-default-credentials – Sachin K Aug 23 '16 at 16:40
  • Thanks Sachin. I tried adding this to the web.config for the web application that is making the request to the API: ` ` Unfortunately I'm still getting the same error. – GuessAgainMatt Aug 23 '16 at 21:41
  • I'm having the same exact issue. Same exact. Except when I put the calling API on a different port I'm still getting the Unauthorized issue. I wish there was a solution for this besides editing the registry. – Daniel Jackson Oct 31 '18 at 20:56

1 Answers1

6

Take a look at this: https://support.microsoft.com/en-us/kb/926642

In my case it was an identical scenario on Windows Server 2012, but the solution in the KB still applies. The loopback check will prevent credentials from being sent through httpClient when they're on the same host, which causes the 401. For me the only resolution was Method 2 - setting DisableLoopbackCheck in the registry. I understand that this is a security "feature" but it's certainly an impediment to using modern service-oriented architecture in a classic Windows environment.

brian_gtr
  • 96
  • 6
  • 1
    Thank you Brian! The first method worked for me. In case the link goes dead, the solution involves adding a registry entry to allow loopback requests. The preferred method is to add a multistring value called BackConnectionHostNames to the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0 subkey, with each DNS entry you want to refer to on its own line. If that doesn't work, you can disable the loopback check entirely by adding a DWORD with name DisableLoopbackCheck and value 1 to the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa subkey. – GuessAgainMatt Sep 16 '16 at 14:45