Search code examples
.netdotnet-httpclientntlm

HTTPClient with NTLM authentication not working in dotnet web application


I have a web server I'm working on using dotnet 7, and I need to hit an external API which uses NTLM authentication.

This is a snippet from my program.cs

private static WebApplicationBuilder CreateWebApplication(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);
    builder.services.AddHttpClient<IMyService, MyService>()
        .ConfigurePrimaryHttpMessageHandler(_ => CreateHandler("myuser", "mypass"));
    builder.services.AddControllers();
}

private static HttpClientHandler CreateHandler(string username, string password) 
{
    return new HttpClientHandler {
        PreAuthenticate = true,
        UseProxy = false,
        UseDefaultCredentials = false,
        Credentials = new CredentialsCache 
        {
            {
                new Uri("http://myendpoint", "Negotiate", new NetworkCredential(username, password))
            }
        }
    }
}

This is a snippet from my service

public class MyService
{
    private HttpClient _client;
    public MyService(HttpClient client) 
    {
        _client = client;
    }

    public async Task Run() 
    {
        HttpRequestMessage req = GenerateHttpReq();
        HttpResponseMessage res = await _client.SendAsync(req);
        if (!response.IsSuccessStatusCode) {
            throw new Exception($"Failed to send request. Status code: {response.StatusCode}");
        }
        // ... some more processing
    }
}

When I run my app, the Run() method in the service gets called, but an exception is thrown Failed to send request. Status code: Unauthorized.

In order to make sure I'm not doing anything wrong with the http client creation, I've written a small app that does work

var handler = new HttpClientHandler {
        PreAuthenticate = true,
        UseProxy = false,
        UseDefaultCredentials = false,
        Credentials = new CredentialsCache 
        {
            {
                new Uri("http://myendpoint"), "Negotiate", new NetworkCredential(username, password)
            }
        }

var client = new HttpClient(handler);
var res = await client.PostAsync("http://myendpoint",new StringContent(""));

The above request is authenticated with the server successfully.

I should note, I am running my project on and Ubuntu 22 machine. When running the little test application on my Ubuntu machine it fails, but when running it on a windows machine it does work. We deploy our project to a Linux based container so I need it to work on Linux.


Solution

  • Posting an answer just in case someone runs into the same issue as me.

    The solution to my problem was to use .NET 8.0 and add the following to my .csproj file

    <ItemGroup>
      <RuntimeHostConfiguration Include="System.Net.Security.UseManagedNtlm" Value="true"/>
    </ItemGroup>
    

    I will note that I am running my project on the official dotnet docker image using dotnet/sdk:8.0-jammy for building the project and dotnet/aspnet:8.0-jammy for deploying