2

My question today is:
How to configure HttpClient so that it can authenticate the call without bothering the user on MacOS?
(.NET Core 2.2 console app running as Launch Agent on MacOS, calling a Web API on IIS with NTLM and Kerberos enabled, over our company's internal network)

Long story:
I have a .NET Core app that uses the following method to call a web api:

var handler = new HttpClientHandler() 
{ 
   UseDefaultCredentials = true 
};

var client = new HttpClient(handler)
{
   BaseAddress = new Uri("https://MyWebAPI.MyCompanyName.com/")
};

string result = client.GetAsync("MyEndpointSubURL")
    .Result.Content.ReadAsStringAsync().Result;

When I run this on my Windows machine, the app easily connects and gets the result.
However, when I run this on a Mac, I get an exception:

Interop+NetSecurityNative+GssApiException - GSSAPI operation failed with error
The provided name was not a mechanism name. (unknown mech-code 0 for mech unknown).
at Microsoft.Win32.SafeHandles.SafeGssNameHandle.CreatePrincipal(String name)

Any ideas what I need to change to make it work?

We desperately want to avoid bothering the user with prompts (it's meant to be a background syncing service).

Recall, it's a .NET Core 2.2 console app running as Launch Agent on MacOS. The Web API it's calling is an Asp.NET Web API hosted with IIS with NTLM and Kerberos enabled and I only need to get past IIS (web API does not use any authentication/authorization mechanisms by itself). The API is exposed only over our company's internal network, so the user is already logged in to the network.

4 Answers 4

2

Try running kinit <username>@<DOMAIN> from the terminal and then running your program again. You may need to configure your krb5.conf file to properly point to the domain controller.

We have "default credentials" working in our system on Mac w/ .NET Core 2.1+ using the same code you show there. Configuring Kerberos through kinit and the conf file is the biggest challenge.

Based on what I can tell, .NET doesn't use the cache produced from running kinit, but this is what configures the principal to be used. .NET's interaction with Kerberos is poorly documented. See https://github.com/dotnet/corefx/issues/30203#issuecomment-395592407

Sign up to request clarification or add additional context in comments.

1 Comment

Hey, thanks for the answer. I guess your confirmation that it works for you on Macs is a very helpful one, as we are by now pretty certain that our server/network configurations are to blame. We have a highly risk-averse firm and it seems a few too many precautions were taken when hardening our infrastructure ^^'
1

I had a very hard time getting this to work on macOS with .NET Core 2.2.

I followed the online documentation about setting up your krb5.conf, running kinit and klist to make sure I had a valid kerberos ticket.

After all that, kerberos was working with Azure Data Studio, so I knew my setup was okay, but I could not get HttpClient with UseDefaultCredentials = true working. It always failed with the same error:

System.ComponentModel.Win32Exception: GSSAPI operation failed with error -  An unsupported mechanism was requested (unknown mech-code 0 for mech unknown).

It did however work on a coworker's machine.

After a lot of digging, we discovered my coworker had .NET Core 2.2.7 installed while I only had 2.2.1. Upgrading my workstation to .NET Core 2.2.8 resolved my issue. Also rolling back our app to use 2.1.13 worked as well.

I hope this helps someone else in the future.

Comments

0

Try this: With basic auth example.

            var url = "https://MyWebAPI.MyCompanyName.com/";
            using (var httpClient = new HttpClient())
            {
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "Base64Credetials");

                using (var response = await httpClient.GetAsync(url))
                    if (response.IsSuccessStatusCode)
                    {
                        var strResponse = await response.Content.ReadAsStringAsync();
                        MyObject result = JsonConvert.DeserializeObject<MyObject>(strResponse);
                        if (result != null)
                        {
                            //Your code here
                        }
                    }
            }

1 Comment

Hey, thanks for the answer. Just to be sure... by "Base64Credetials" you mean literally this phrase, or is it "username:password" encoded in base64? If it's the latter then it won't work for me, unless you suggest some other means of retrieving the user's password. As said before, I don't want to ask the user for password. I want him to be authenticated based on what he entered in the Mac's login screen, just like it happens when I run my code on a windows machine.
0

I don't think MacOS has a concept of "default authentication" in the same way Windows does. Kerberos and NTLM are both Windows concepts. I suspect on MacOS you will have to use a different authentication scheme (Basic or Bearer) and then retrieve the credentials from somewhere such as the Keychain. IIRC an app can be granted silent read access to the key chain.

2 Comments

Thanks for the idea! If you find a moment, I'd appreciate a snippet of the solution or some links :)
I don't have a Mac unfortunately but this is something I found that uses Xamarin.Security I think.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.