1

I have this well known 401 Unauthorized error. My scenario is that website A needs to call HTTP request (GET) to website B. Both websites runs on the same IIS server under different application pools (accounts). When I call HTTP request within the browser on my computer (that is connected to the windows domain) the HTTP request works and website B returns JSON data. But when that call is done by website A it seems that the information about the service account of website A is not added into the HTTP request and website B denies that request with 401. That leads to two questions

  1. Why the IIS server does not recognize (authenticate/authorize) the website A account?
  2. How can I add manually the account info into the HTTP request (using HTTP Client) so that I don't need to know username and password of the service account?

Currently my code looks like

namespace Infrastructure
{
    public class FooService
    {
        private readonly HttpClient _httpClient;

        public FooService(HttpClient httpClient)
        {
            _httpClient = httpClient;
            _httpClient.BaseAddress = new Uri("https://domain/");

            // Adding basic header does not work.
            // var byteArray = Encoding.ASCII.GetBytes("user:passowrd");
            // _httpClient.DefaultRequestHeaders.Authorization = 
            //    new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
        }

        public async Task<FooServiceData> GetDataAsync() =>
            await _httpClient.GetFromJsonAsync<FooServiceData>(
                "foo/data");
    }

    public class FooServiceData
    {
        public string Url { get; set; }
        public string Token { get; set; }
    }
}

and the call that throws 401 is executed in controller action

var credentials = _fooService.GetDataAsync().Result;

Update:

When I connect to the website B via browser it does work. When I run ASP.NET MVC website project (on my development machine in Visual Studio) that sends HTTP request, it also does not work (401). The IIS setting (launchSetting.json) contains following

"iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": false,
    "iisExpress": {
      "applicationUrl": "http://localhost:26978",
      "sslPort": 44339
    }
  }

I thought that the Visual Studio is running under my account (and also the IIS service it runs in the background) but it seems that there are some changes in the Auth that prevent the website B to Auth me, any idea?

Update 2:

We tried to setup following property in the properties of the Website B service account but it didn't help.

enter image description here

Muflix
  • 6,192
  • 17
  • 77
  • 153
  • 1
    What's the actual authentication method you configured for both web apps? For Windows authentication based apps, escalate to your domain administrators so that they can guide you on Kerberos SSO setup. – Lex Li Aug 10 '22 at 15:13
  • Yes, Windows authentication should be used. Domain administrator told me that he will try to tweak the Kerberos somehow. I guess the Kerberos setup has to be done on the receiver side (website B) rather than the caller side (website A), right? – Muflix Aug 10 '22 at 17:45
  • 1
    You could refer to [Kerberos Authentication Overview](https://learn.microsoft.com/en-us/windows-server/security/kerberos/kerberos-authentication-overview) to get more information on it. You could let us know if you have questions. – Deepak-MSFT Aug 11 '22 at 09:06
  • @Deepak-MSFT thank you for the link. We tried to setup the property "Trust this user for delegation to any service (Kerberos Only)" to ON in the properties and delegation tab of the website account, but it does not help. Any Idea? The IIS site normally is able to authenticate the user account. – Muflix Aug 11 '22 at 09:39

1 Answers1

0

I solved the issue with the following code on the caller side. Previously I registered the FooService as follows

services.AddHttpClient<FooService>();

but for Windows Authentication the credentials has to be specified

services.AddHttpClient<FooService>()
    .ConfigurePrimaryHttpMessageHandler(x => new HttpClientHandler()
    {
         Credentials = CredentialCache.DefaultNetworkCredentials
    });
Muflix
  • 6,192
  • 17
  • 77
  • 153