DotNet CLI , private NuGet feeds and Linux...

Today I hit an issue whilst trying to run dotnet run for some of our benchmarkdotnet tests which I like to run all new hardware I try out. My pair of Raspberry PI 4's arrived and I wanted to compare the performance of our Fingerprint capture code. I've hit the issue before and last time I figured it out I swore I'd blog and write it up as I knew I would forget!

My benchmark project is a straight forward BenchmarkDotNet project however it consumers NuGet packages from both nuget.org as well as our private NuGet repository which requires authentication. For all of our windows machines this works without an issue for machines on the domain they authenticate seemlessly however when using Linux devices this is a different issue :(

Instead on Linux devices we always get:
/home/pi/dotnet/sdk/2.2.300/NuGet.targets(121,5): error :   GSSAPI operation failed with error - An invalid status code was supplied (SPNEGO cannot find mechanisms to negotiate).
This essentially means it was unable to find a way to negotiate from kerberos to ntlm authentication with the server, as discussed in this issue on GitHub. It's worth reading the issue as it looks like this is fixed for .Net Core 3.0 which is expected to be released in September 2019.

Until .Net Core 3.0 is here I need a workaround, I know you can provide credentials for a NuGet provider via a nuget.config file in your repository, this might be the answer. Within the nuget.config you can add your package source and then within a packageSourceCredentials  element provide the auth details.

For example:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <packageSources>
  <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  <add key="private-nuget" value="https://private-tfs.example.com/Team/_packaging/Company/nuget/v3/index.json" />
 </packageSources>
 <activePackageSource>
  <add key="All" value="(Aggregate source)" />
 </activePackageSource>
 <packageSourceCredentials>
  <private-nuget>
   <add key="Username" value="NugetReader" />
   <add key="ClearTextPassword" value="i'm a secret!" />
  </private-nuget>
 </packageSourceCredentials>
</configuration>

Note that the key you provide for the package source you then use as the element name within the packageSourceCredentials Element. I used <add key="private-nuget" /> so my element name was then <private-nuget>

When on Windows and using nuget.exe you can provide the username and password for the package source as command line arguments and the password will be stored in the nuget.config in an encrypted form. However currently on Linux this isn't supported. Instead you have to use ClearTextPassword, bare this in mind and ensure you use a unique username and password for your package source user account which only has limited access to your repository.

The above config however although worked fine on our Windows machines I still ran into a new error on Linux.
/home/pi/dotnet/sdk/2.2.300/NuGet.targets(121,5): error :   GSSAPI operation failed with error - An invalid status code was supplied (Configuration file does not specify default realm).

Essentially now this still boils down to the negotiation but this time whether this username is for the server or the domain etc. This is where I couldn't remember what I had done last time to make this work. I knew it was something to do with changing the authentication type to basic. After some searching I eventually found how you do this. As part of your packageSourceCredentials you specify the valid authentication methods, in this case I only want basic.

 <packageSourceCredentials>
  <private-nuget>
   <add key="Username" value="NugetReader" />
   <add key="ClearTextPassword" value="i'm a secret!" />
   <add key="ValidAuthenticationTypes" value="basic" />
  </private-nuget>
 </packageSourceCredentials>

With this all set everything restored and built fine! Hurrah!

Now this works but is there a better way to do this? Essentially yes! You can use the Azure Artifacts Credential Provider this works not only for Azure DevOps but also locally hosted TFS. Simply follow the instructions provided in the readme and then do you dotnet restore but ensure you provide the --interactive argument. You will then be asked for your credentials which are then used to generate a session token. The readme also contains how you can use this for build servers etc. However, it does appear that this provider does seem to have issues dependant on your version of .Net Core however I'm hoping they are resolved soon.

If you do run into any issues as mentioned on that issues list you can at least use the nuget.config approach until it is fixed.

Hope this helps.

Comments

Popular posts from this blog

Lessons Learnt: Migrating From Net Framework to Net Core - Net Standard Libraries and Multi-Targeting

Running a TFS Build Agent on your Raspberry PI / ARM based device