Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use NTLM Authentication in Web Request in .NET Core

Tags:

c#

.net-core

ntlm

Update Turns out all I needed to do was upgrade to .NET Core 2.1! Thanks for the solutions everyone!


I have a .NET Core 2.0 Console App and need to make a web request to an API which uses Windows Authentication (NTLM specifically). It's an internal API in my company and I'm having a hard time trying to connect to it successfully, keep getting 401s.

My research

I checked out on SO:

  • NTLM authentication HttpClient in Core - raised last year, no proper answer given saying that the issue would be resolved in a later .NET Core update.
  • Sending HTTP Headers with HTTP Web Request for NTLM Authentication - this was in 2009 and doesn't appear to be relevant for .NET Core.
  • How to get HttpClient to pass credentials along with the request? - this was in 2012, thought it'd be the one but still get 401 when using it.

I then found this issue which was raised in the .NET Core github and it says it has been resolved. I tried following a code example there but still did not work.

My code

Here is what I have so far, I changed the Uri as it's hosted on the company network, but I hope this will be sufficient to run locally.

public class NTLMProxy
{
    private readonly HttpClient _httpClient;

    public NTLMProxy()
    {
        _httpClient = CreateHttpClientWithNTLM();
    }

    public Task<HttpResponseMessage> GetUsers()
    {
        var httpRequest = new HttpRequestMessage(HttpMethod.Get, _httpClient.BaseAddress);

        return _httpClient.SendAsync(httpRequest);
    }

    public HttpClient CreateHttpClientWithNTLM()
    {
        var uri = new Uri("http://ntlmservice.com/services/api/foo");
        var credentialsCache = new CredentialCache { { uri, "NTLM", CredentialCache.DefaultNetworkCredentials } };
        var handler = new HttpClientHandler { Credentials = credentialsCache };
        var httpClient = new HttpClient(handler) { BaseAddress = uri };
        httpClient.DefaultRequestHeaders.ConnectionClose = false;
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        ServicePointManager.FindServicePoint(uri).ConnectionLeaseTimeout = 120 * 1000;  // Close connection after two minutes

        return httpClient;
    }
}

If you have any ideas / suggestions, please let me know.

like image 628
Troy Poulter Avatar asked Dec 10 '18 05:12

Troy Poulter


1 Answers

For .NET Core 2.1 I have this implementation working, using a HttpClientFactory

In ConfigureServices(IServiceCollection services) in the class Startup I have this named HttpClient registration:

        services.AddHttpClient("myName").ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler
        {
            Credentials = new CredentialCache { 
                {
                    new Uri("url"), "NTLM", new NetworkCredential("username", "password", "domain")
                }
            }
        });

At the location where you need the HttpClient just resolve it like this:

var client  = _httpClientFactory.CreateClient("myName"); 

Don't forget to inject the factory in the constructor.

public class MyClass{
    private readonly IHttpClientFactory _httpClientFactory;

    public MyClass(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }
}

Good luck!

like image 122
321X Avatar answered Oct 11 '22 15:10

321X