In this blog post I describe all my experiments to support NuGet feed authentication.
Introduction
My goal was to make NuGet.exe usable in Continuous Integration (i.e. here) scenarios in case one uses NuGet feed with authentication. In fact, I decided to make NuGet.exe client use persisted credentials instead of asking user for them.
Why do I need that? That was easy. We receive many questions in feedback on how to use authenticated NuGet feeds in builds or on Visual Studio. For example: TW-20764. I also have several similar requests on twitter
People start using their own NuGet feeds. In a big company it's normal to have some NuGet packages to be hidden from everyone. That is reasonable to involve authentication to the feeds. And that is reasonable to use NuGet.exe inside continuous integration builds to fetch dependencies and/or to publish packages. NuGet.exe has to use packages source with authentication work. This means one should provide credentials to NuGet to make it work in scripts without user interaction.
Current state description
NuGet team realized they need to provide authentication support. As far as I know NuGet claims to support feed credentials starting from NuGet 1.5. That is nice to know the feature is implemented inside NuGet core!
I read about some complains in the twitter that NuGet does not persist entered passwords in Visual Studio. It turns out one need to re-enter passwords for every new Visual Studio instance.
Code research
Remember, my goal was to support continuous integration scenarios. The idea was to make NuGet avoid asking a passwords.
What I did. First I fetched sources of NuGet from nuget.codeplex.com, switched to branch 2.0 (1ab57c30a3aee16c85ef72cf1aeb9511cf3eace4).
The first file I checked was src\CommandLine\Program.cs. There I found how credentials provider is set-up in Initialize method:
Here I noticed there is no way to provide my own credentials provider from plugin. See/vote for related issue.
Still, there is a chance to provide settings that would make SettingsCredentialProvider load settings from configuration.
Digging NuGet.Config
Next step was to check how NuGet.exe loads configuration. Of course I knew there is shared NuGet.Config file that stores all machine-wide settings. This does not work for me because there could be several running NuGet instances and I could not let one instance access feeds from another.
In the same file (src\CommandLine\Program.cs) I found how Settings are loaded:
And take src/Core/Configuration/Settings.cs:
So, it looked like a chance for me to provide a non-global config file. Still, to make it work I should:
- create a NuGet.Config file in the working directory
- ensure the file is parseable by NuGet
This looks to tricky. It is not possible to make NuGet use custom NuGet.Config file. I created an issue. I wish I could specify a path to NuGet.Config file I want to use with an instance of NuGet.exe.
Storing Credentials
Ok. Now I know where config is. Next was to implement a plugin for NuGet.exe to store feed credentials into it. That was not so complicated. The sources of the plugin are found on GitHub.
The first version of code looked like:
This was easy. In plugin I simply create or update the feed entry adding credentials. That was it. It looked to me that was all I needed to do!
NuGet Problems
It turned out, NuGet credentials provider does not work for /$metadata path. That make NuGet to re-query for credentials. I created an issue for that too. It looked like current implementation of SettingsCredentialProvider does not compare urls in the right way, thus requiring one to re-enter credentials.
The workaround for it was easy. I made my plugin for NuGet to register two NuGet feeds. For given feed http://host/feed I register enabled feed http://host/feed and than I register disabled feed http://host/feed/$metadata. Finally, that made both NuGet.exe and NuGet in Visual Studio use provided credentials.
Post Mortem
That looked I found the way to make NuGet Authentication work inside continuous integration builds. I decided to make it a try
I failed.
It turns out SettingsCredentialProvider does not take care to provide authentication for package stream urls. So NuGet.exe requested a password to download a package. I expected NuGet.exe authentication mechanism would re-use feed credentials for it too.
Unfortunately, $/metadata workaround idea failed here. It had to provide an authentication for full package download URL. It is impossible to provide explicit credentials for every package stream in the feed.
I create the issue for NuGet to handle it. This issue looks related to issue 2379.
Summary
Currently I failed to make NuGet authentication work smoothly in continuous integration scenario. I with I could implement it at some moment in future.
I collected related issues in TW-20764. The list of NuGet issues for now is:
Feel free to vote for those issues!
I like the idea of NuGet. I'd like to say thank you for all who involved into NuGet development process. You are doing a great tool that solve problems for people!
I hope we could make the described scenario work. I wish I could use command line or create a plugin for NuGet to make feed authentication work.
comments powered by Disqus