0

Having two asp.net core APIs where API A has basic auth and API B has windows auth. API A is calling API B but since API B has windows auth enabled, API A needs to have HttpClient with NTLM auth.

API A (simplified):

var ccahe = new CredentialCache
{
    {
        httpRequestMessage.RequestUri, "NTLM",
        new NetworkCredential("a.antr01", "pw", "ICEPOR")
    }
};
var httpClientHandler = new HttpClientHandler()
{
    PreAuthenticate = true,
    Credentials = ccahe,
    UseDefaultCredentials = true,
    AllowAutoRedirect =  true
};

using (HttpClient httpClient = new HttpClient(httpClientHandler))
{
    return await httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead);
}

as you see in the snippet above, I have a HttpClient with user a.antr01 but with the debugger in API B in the claims transformation code I see the my user which is logged in Windows and running the IDEs under that account:

enter image description here

how to send the request from API A which would support NTLM to API B and API B would have a correct credentials on its side?

EDIT: if there would be a way how to support both basic and NTLM auth in API B - API A would not be needed anymore - maybe somebody has an idea how to achieve that?

so basic auth flow would be decode base64 -> auth against AD -> get authorization claims -> continue to controller

and NTLM auth would be (already authenticated) -> get authorization claims -> continue to controller

pandemic
  • 1,135
  • 1
  • 22
  • 39
  • 1
    Those aren't NTLM credentials. Windows Authentication never passes credentials. You can't impersonate a Windows user by specifying the username and password like that either. You'd have to use impersonation but in that case you'd be abusing Windows authentication. The whole point is that you DON'T NEED credentials. The OS already knows who the current user is. You should give permissions to that user, not hard-code a username/password – Panagiotis Kanavos Apr 01 '21 at 14:32
  • What auth providers have you got setup on API B? –  Apr 01 '21 at 14:39
  • @CallumMorrisson `services.AddAuthentication(IISDefaults.AuthenticationScheme);` – pandemic Apr 01 '21 at 14:43
  • Alright, and when you make the same call from API A without providing the credentials, it still shows as being authenticated with `ICEPOR\atran1` ? –  Apr 01 '21 at 14:48
  • having `Credentials = ccahe` commented out in the `HttpClientHandler` constructor, still `ICEPOR\atran1` is being shown in API B – pandemic Apr 01 '21 at 14:52
  • @pandemic In your code you're explicitly asking to **discard the explicit credentials** by setting `UseDefaultCredentials = true` *after* setting the credentials. That's what the property says it does - `Use the Default Credentials` instead of those passed in `Credentials`. The code did what you told it to do. A service may allow multiple authentication methods but a *request* can only use one. Even if you used eg JWT to provide multiple claims that would still be *one* authentication method – Panagiotis Kanavos Apr 02 '21 at 06:38
  • @PanagiotisKanavos still doesn't work after commenting out `UseDefaultCredentials = true` - its not even reaching API B ClaimsTransformer code, getting 401 instantly from API B – pandemic Apr 02 '21 at 07:59
  • [all you need is check this link](https://stackoverflow.com/questions/12212116/how-to-get-httpclient-to-pass-credentials-along-with-the-request/12675503#12675503) – Amir Hossein Moradi Jan 31 '22 at 14:29

2 Answers2

1

I can give you solution for your EDIT. Only way I could achieve windows and basic auth at the same time in WebAPI was using a specific location for the basic authentication: Web.config

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


  <location path="api/mypath">
    <system.webServer>
      <security>
        <authentication>
          <basicAuthentication defaultLogonDomain="mydomain" enabled="true" realm="myrealm" />
        </authentication>
      </security>
    </system.webServer>
  </location>

</configuration>

So all request to the /api/mypath/mycontroller will require basic authentication. All other request /api/someotherpath/someothercontroller will use the windows authentication.

You can re-match your controller with [System.Web.Http.Route("api/mypath/mycontroller")]

In the IIS server so should enable both Windows and Basic authentication. Afterward the web.config will kick in (you might have to configure the IIS config file as well to enable both authentications types).

If you don't insist on having NTLM and basic on the same endpoint -> this might be your solution.

Besides this I use almost the exact same code to connect to the API with NTLM:

var credentialsCache = new CredentialCache
{{builder.Uri, "NTLM", new NetworkCredential(
    "user",
    "password",
    "domain"
)}};
var handler = new HttpClientHandler { Credentials = credentialsCache };
var client = new HttpClient(handler);
await client.PostAsync(url, data).ConfigureAwait(false);
antanta
  • 618
  • 8
  • 16
0

Just for sanity, can you spin up a console application with just

var httpRequestMessage = ...; // whatever it's expecting

var httpClientHandler = new HttpClientHandler()
{
    PreAuthenticate = true,
    Credentials = new NetworkCredential("a.antr01", "pw", "ICEPOR"), // real password instead of "pw"
    AllowAutoRedirect =  true
};

using (HttpClient httpClient = new HttpClient(httpClientHandler))
{
    return await httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead);
}

and see what happens in API B?

  • with console app, I am able to get a correct user in API B! – pandemic Apr 02 '21 at 10:05
  • Alright, so the issue is either your credentials cache, or `UseDefaultCredentials = true`. Good luck! –  Apr 02 '21 at 10:11
  • 1
    @pandemic it would be useful for others in the future if you come back and answer your own question here when you figure out which of the two caused your issue. –  Apr 02 '21 at 10:20
  • yeah wiring up the basic auth decode func to impersonate a NTLM call to API B and if everything goes as planned, I will post a question! – pandemic Apr 02 '21 at 10:52