Spec: Implemented
This is a fork of #6410 to track related work for separate prioritization.
Users restore NuGet packages using a variety of codepaths and clients: Visual Studio NuGet Package Manager, NuGet.exe, dotnet(.exe), and msbuild /restore and /t:restore. We want to make it seamless to use authenticated feeds (e.g. from VSTS Package Management, MyGet, or Artifactory) in all of those codepaths, without the NuGet team or authenticated feed providers having to write duplicate auth code.
In addition, we want to bundle an authentication plugin with msbuild (when installed with VS or via the Build Tools SKU) and dotnet (when installed via the installer) so that VSTS auth works seamlessly on first run of e.g. dotnet restore
, similar to how the Git Credential Manager automatically authenticates VSTS, GitHub, and Bitbucket users after a standard Git for Windows installation.
As part of this work, we should investigate whether to move from the old VSTS NuGet Credential Provider, which is Windows-only, to standardize on the Git Credential Manager, which is cross-plat. And, we want to consider using @dtivel's plugin model (developed for large package support), so there's a single NuGet plugin model.
/cc @anangaur @emgarten @xavierdecoster
Just an FYI: this already works cross-platform with JetBrains Rider's last preview version - www.jetbrains.com/rider/eap and with the existing plugin model, so wondering what work is left to do here other than hooking up a different executable to prompt for credentials?
That鈥檚 good to know. Just curious: are you using a cross plat (.NET Core) credential provider or different versions for different platforms?
This workitem is to make the current (VSTS) credential provider work for all the platforms with VS, dotnet.exe and msbuild.exe. In addition, we would also be exploring ways to make the plugin model with NuGet better.
We plan to publish the spec soon.
FYI here's the announcement post we did: https://blog.jetbrains.com/dotnet/2018/03/06/credential-providers-private-nuget-feeds-rider-2018-1-eap/
We've plugged into the existing mechanism and are using a cross-platform JVM-based browser window + OAuth flow. Simple interface similar to what NuGet currently has:
public interface NuGetCredentialProvider {
public abstract fun getProviderResponse(
project: com.intellij.openapi.project.Project,
uri: java.net.URI,
isRetry: kotlin.Boolean): NuGetCredentialProviderResponse?
}
(PS: in building 33 today in case you want to learn more)
/cc: @nkolev92 @jeffkl
2 big questions on the new spec:
1) Will the old mechanism continue to work?
2) Will there be a way to plug in a provider that does not require a separate process? Imagine I am building something using the SDK, and I want to add a credential provider plugin as part of my application. Can that credential provider be part of my application (e.g. same assembly just plugging an interface), or do I have to go the IPC route?
Ok, then 2 becomes interesting :-)
@maartenba
There are currently no plans for a plugin to be started in process.
We considered it but decided to go the standalone process route for a couple of reasons:
If you're using the client SDKs directly you have the ability to override the CredentialService itself.
Ok so it is possible to override that one?
@maartenba
Yes, it's normally setup by the application, not at the API level.
Relevant code.
@nkolev92, do you have a working example of plugin with protocol v2 support? I've tried to use https://github.com/NuGet/NuGet.Client/tree/release-4.8.0-preview3/test/TestExtensions/TestablePlugin without success. Despite protocol claims using stdout/stdin for communication this plugin tries to connect to some process specified in -portnumber
argument.
@dtretyakov here's my prototype that shows how to implement a credential provider: https://github.com/jeffkl/NuGetCredentialProvider
We're working on an open source credential provider that everyone can contribute to. Ideally it would work for local devs connecting to VSTS and hosted builds like AppVeyor and VSTS out-of-the-box. That way we don't need a different provider for each scenario.
@jeffkl
In the end we moved away from the one OSS plugin for all providers.
@dtretyakov
As Jeff suggested, his plugin is a good reference.
You can also consider take a look at the plugin I used for testing (doesn't do any actual auth).
Please note that that the protocol is still being worked on and there could still be changes.
@nkolev92, @jeffkl thanks for details. I've made it working for my use case.
Do you know in which target .NET CLI and MSBuild versions will be available NuGet plugins protocol v2?
@dtretyakov
2.1.400 of the SDK, and 15.8 version of MSBuild.
@nkolev92, after adding logging in our credentials plugin I've faced deadlock problems when I'm using Connection.SendAsync
method which was in your example:
https://github.com/nkolev92/NuGet.Tools/blob/master/NuGet.CredentialProvider/CredentialProvider.Console/PluginLoggingHandler.cs#L15
During the experiment I've added ConfigureAwait(false)
in all await calls in the NuGet.Protocol library:
https://github.com/dtretyakov/NuGet.Client/commit/e2a50bd017852d30f8b4e771da8cc86f2144e93e
Then by using Connection.SendRequestAndReceiveResponseAsync
it was possible to normally log messages in the code fragment like that:
https://github.com/JetBrains/teamcity-nuget-support/blob/master/nuget-extensions/nuget-plugin/PluginController.cs#L21-L27
Did you faced such problems in other credential plugins? Why practically all await ...
calls in the NuGet.Protocol
library are used without ConfigureAwait(false)
?
Without configureawait
restore fails with "was cancelled" messages like that:
[14:51:36][restore] Starting: C:\TeamCity\buildAgent\tools\NuGet.CommandLine.4.8.0-rtm.5369\tools\NuGet.exe restore C:\TeamCity\buildAgent\work\71412ac3a5525267\NuGetFeedTest.sln -NoCache -Verbosity detailed -Source http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json -Source https://www.nuget.org/api/v2/
[14:51:36][restore] NuGet Version: 4.8.0.5369
[14:51:36][restore] MSBuild auto-detection: using msbuild version '15.6.82.30579' from 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\bin'. Use option -MSBuildVersion to force nuget to use a specific version of MSBuild.
...
[14:51:37][restore] Restoring NuGet package NuGetFeedTest.0.0.314-beta.1.
[14:51:37][restore] GET http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/flatcontainer/nugetfeedtest/0.0.314-beta.1/nugetfeedtest.0.0.314-beta.1.nupkg
[14:51:37][restore] Using C:\TeamCity\buildAgent\plugins\nuget-agent/bin/credential-plugin/net46/CredentialProvider.TeamCity.exe as a credential provider plugin.
[14:51:38][restore] GET https://www.nuget.org/api/v2/Packages(Id='NuGetFeedTest',Version='0.0.314-beta.1')
[14:51:38][restore] NotFound https://www.nuget.org/api/v2/Packages(Id='NuGetFeedTest',Version='0.0.314-beta.1') 161ms
[14:51:38][restore] GET https://www.nuget.org/api/v2/FindPackagesById()?id='NuGetFeedTest'&semVerLevel=2.0.0
[14:51:38][restore] OK https://www.nuget.org/api/v2/FindPackagesById()?id='NuGetFeedTest'&semVerLevel=2.0.0 137ms
[14:51:42][restore] WARNING: Unable to find version '0.0.314-beta.1' of package 'NuGetFeedTest'.
[14:51:42][restore] https://www.nuget.org/api/v2/: Package 'NuGetFeedTest.0.0.314-beta.1' is not found on source 'https://www.nuget.org/api/v2/'.
[14:51:42][restore] http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json: Getting package 'NuGetFeedTest.0.0.314-beta.1' from source 'http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json' was cancelled.
[14:51:42][restore]
[14:51:43][restore] WARNING: Unable to find version '0.0.314-beta.1' of package 'NuGetFeedTest'.
[14:51:43][restore] https://www.nuget.org/api/v2/: Package 'NuGetFeedTest.0.0.314-beta.1' is not found on source 'https://www.nuget.org/api/v2/'.
[14:51:43][restore] http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json: Getting package 'NuGetFeedTest.0.0.314-beta.1' from source 'http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json' was cancelled.
[14:51:43][restore]
[14:51:43][restore] Errors in packages.config projects
[14:51:43][restore]
[14:51:43][restore] Unable to find version '0.0.314-beta.1' of package 'NuGetFeedTest'.
[14:51:43][restore] https://www.nuget.org/api/v2/: Package 'NuGetFeedTest.0.0.314-beta.1' is not found on source 'https://www.nuget.org/api/v2/'.
[14:51:43][restore] NuGet Config files used:
[14:51:43][restore] C:\Users\Dmitry.Tretyakov\AppData\Roaming\NuGet\NuGet.Config
[14:51:43][restore] C:\Program Files (x86)\NuGet\Config\Microsoft.VisualStudio.Offline.config
[14:51:43][restore] http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json: Getting package 'NuGetFeedTest.0.0.314-beta.1' from source 'http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json' was cancelled.
[14:51:43][restore]
[14:51:43][restore] Feeds used:
[14:51:43][restore] http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json
[14:51:43][restore] https://www.nuget.org/api/v2/
[14:51:43][restore] Process exited with code 1
I'm not sure about the wrong scenario here, but can give some thoughts on ConfigureAwait(false)
whether it makes sense for this current case, is up to you to decide.
In my discussion with CPS/ extensibility team, ConfigureAwait(false)
should not be used with JTF
aware code since this option will always return on threadpool thread and will never return to the original SynchronizationContext
. So only when you want to use Task.Wait
where it will deadlock if run from UI thread and any of the continuation needs it. so ConfigureAwait(false)
will make sure to not block UI thread.
@dtretyakov
You are right the correct approach is to use SendRequestAndReceiveResponseAsync for logging.
I think Aashish, provided enough context about the ConfigureAwait usages.
I assume the deadlock is on the plugin side?
@nkolev92, yes plugin, has dependency on NuGet.Protocol
library and experience deadlocks after sending log message via SendRequestAndReceiveResponseAsync
method.
@jainaashish, from my point of view it's fine to have in the NuGet.Protocol
library code ConfigureAwait(false)
calls, since it's intended to use in the other apps like NuGet.CommandLine or 3rd party plugins. If you need to preserve original context In NuGet.CommandLine or NuGet plugin for VS you could await your method calls without using ConfigureAwait
. See recommendation for library authors by Stephen Toub:
As a library implementer, it鈥檚 a best practice to always use ConfigureAwait(false) on all of your awaits, unless you have a specific reason not to; this is good not only to help avoid these kinds of deadlock problems, but also for performance, as it avoids unnecessary marshaling costs.
Maybe @dtivel as a general contributor of NuGet.Protocol
library could provide some cons of using ConfigureAwait(false)
there?
But anyway currently I don't have any working solution to use logging in the NuGet plugin. If somebody could help to make it working without modification of NuGet code I will be happy to hear about it. In the other case we have to create our own implementation of "NuGet.Protocol" library to make all use cases working.
@AArnott also recently added a topic on this ConfigureAwait(false)
in his Cookbook for Visual Studio
You might wana take a look here
Since this library isn't app independent (also being consumed inside VS), I don't think ConfigureAwait(false)
will be the right thing to do here unless I'm reading it wrong.
About your issue, then I see you wrapped Connection.SendRequestAndReceiveResponseAsync
inside Task.Run()
which should have solved your deadlock situation because then there is no SynchronizationContext
... Did you just try that change?
@jainaashish, as I said Task.Run()
with a Connection.SendRequestAndReceiveResponseAsync
call without changes in NuGet.Protocol
library does not prevent deadlock. Only after adding ConfigureAwait(false)
I was able to make logging working and that is the problem.
If the library applies to several apps, not all of which follow JTF threading rules, .ConfigureAwait(false)
is probably the right way to go. But if it's to solve deadlocks, you may want to find where the threading rules are not being observed anyway to reduce risk that the deadlocks may reappear later/elsewhere.
@nkolev92, @jainaashish is is true that If NuGet.Protocol
library is intended to use by NuGet plugins authors or should we write our own implementations of the NuGet Protocol?
Yes it's intended to be used by NuGet plugins authors...
As Andrew suggested we can proceed with adding ConfigureAwait(false)
for Plugin library and discussed with @dtivel as well.
@nkolev92, another error was received while running NuGet restore on mono:
Starting: /usr/bin/mono-sgen /home/jetbrains/Downloads/buildAgent/tools/NuGet.CommandLine.4.8.0-rtm.5369/tools/NuGet.exe restore /home/jetbrains/Downloads/buildAgent/work/71412ac3a5525267/NuGetFeedTest.sln -NoCache -Verbosity detailed -Source http://localhost:8080/httpAuth/app/nuget/feed/NuGetFeedTest/default/v3/index.json -Source http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json -Source https://www.nuget.org/api/v2/
[17:33:30][restore] in directory: /home/jetbrains/Downloads/buildAgent/work/71412ac3a5525267
[17:33:31][restore] NuGet Version: 4.8.0.5369
[17:33:31][restore] MSBuild auto-detection: using msbuild version '15.0' from '/usr/lib/mono/msbuild/15.0/bin'. Use option -MSBuildVersion to force nuget to use a specific version of MSBuild.
[17:33:32][restore] MSBuild P2P timeout [ms]: 120000
[17:33:32][restore] /usr/bin/msbuild "/home/jetbrains/Downloads/buildAgent/temp/buildTmp/NuGetScratch/70my6m9f.lkk.nugetinputs.targets" /t:GenerateRestoreGraphFile /nologo /nr:false /v:q /p:NuGetRestoreTargets="/home/jetbrains/Downloads/buildAgent/temp/buildTmp/NuGetScratch/ouvua8kp.ika.nugetrestore.targets" /p:RestoreUseCustomAfterTargets="True" /p:RestoreTaskAssemblyFile="/home/jetbrains/Downloads/buildAgent/tools/NuGet.CommandLine.4.8.0-rtm.5369/tools/NuGet.exe" /p:RestoreSources=\"http://localhost:8080/httpAuth/app/nuget/feed/NuGetFeedTest/default/v3/index.json\;http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json\;https://www.nuget.org/api/v2/\;\" /p:RestoreSolutionDirectory="/home/jetbrains/Downloads/buildAgent/work/71412ac3a5525267/" /p:SolutionDir="/home/jetbrains/Downloads/buildAgent/work/71412ac3a5525267/" /p:SolutionName="NuGetFeedTest" /p:RestoreBuildInParallel="False" /p:RestoreUseSkipNonexistentTargets="False"
[17:33:34][restore]
[17:33:34][restore] Restoring NuGet package NuGetFeedTest.0.0.326-beta.1.
[17:33:35][restore] Using /home/jetbrains/Downloads/buildAgent/plugins/nuget-agent/bin/credential-plugin/net46/CredentialProvider.TeamCity.exe as a credential provider plugin.
[17:33:35][restore] GET https://www.nuget.org/api/v2/Packages(Id='NuGetFeedTest',Version='0.0.326-beta.1')
[17:33:36][restore] NotFound https://www.nuget.org/api/v2/Packages(Id='NuGetFeedTest',Version='0.0.326-beta.1') 698ms
[17:33:36][restore] GET https://www.nuget.org/api/v2/FindPackagesById()?id='NuGetFeedTest'&semVerLevel=2.0.0
[17:33:37][restore] OK https://www.nuget.org/api/v2/FindPackagesById()?id='NuGetFeedTest'&semVerLevel=2.0.0 711ms
[17:33:37][restore] WARNING: Unable to find version '0.0.326-beta.1' of package 'NuGetFeedTest'.
[17:33:37][restore] http://localhost:8080/httpAuth/app/nuget/feed/NuGetFeedTest/default/v3/index.json: Unable to load the service index for source http://localhost:8080/httpAuth/app/nuget/feed/NuGetFeedTest/default/v3/index.json.
[17:33:37][restore] 401 ()
[17:33:37][restore] http://localhost:8080/httpAuth/app/nuget/feed/_Root/default/v3/index.json: wintrust.dll
[17:33:37][restore] https://www.nuget.org/api/v2/: Package 'NuGetFeedTest.0.0.326-beta.1' is not found on source 'https://www.nuget.org/api/v2/'.
OS: Ubuntu 16.04
Mono: 5.12.0.301
Under Verbosity logging NuGet.exe writes only "wintrust.dll" as a error message. Under which mono and os versions did you verified work of the commit https://github.com/NuGet/NuGet.Client/commit/318ddad6da227ef8357160dfe6f0727798371891?
@nkolev92, it looks on mono could be used the AuthenticodeDeformatter for signature verification.
@dtretyakov
Mono on linux currently does not work (and it won't work in 4.8).
Thanks for the pointer. I'll look into it.
@nkolev92, so as I understand in the mentioned change you've tried to disable plugins usage under any mono runtime? Or they work fine on mono in macos? If not maybe you could write meaningful message that plugin would not work under mono istead of this runtime exception?
Do you have a feature freeze time in NuGet 4.8?
@nkolev92 , @jainaashish another thought about change https://github.com/NuGet/NuGet.Client/commit/318ddad6da227ef8357160dfe6f0727798371891#diff-e24eb77aabfdbad8c040b73608ca477b: it could be a breaking from the Plugins v1 perspective. They could start failing in NuGet 4.8+ on Mono runtime.
@nkolev92, another significant problem is that NuGet authentication plugin is not used in dotnet nuget push
/ dotnet nuget delete
commands:
[11:58:35][nuget push] Starting: "C:\Program Files\dotnet\dotnet.exe" nuget push C:\TeamCity\buildAgent\work\71412ac3a5525267\NuGetFeedNetCore\NuGetFeedNetCoreLib\bin\Debug\NuGetFeedNetCoreLib.0.0.16.nupkg --api-key ******* --source http://localhost:8080/httpAuth/app/nuget/feed/NuGetFeedTest/default/v3/index.json
[11:58:35][nuget push] in directory: C:\TeamCity\buildAgent\work\71412ac3a5525267
[11:58:36][nuget push] error: Unable to load the service index for source http://localhost:8080/httpAuth/app/nuget/feed/NuGetFeedTest/default/v3/index.json.
[11:58:36][nuget push] error: Response status code does not indicate success: 401 ().
.NET CLI: 2.1.401-preview-009229
With NuGet 4.8.0 it works fine. Do you plan to address in the scope of .NET CLI 2.1.4xx?
@dtretyakov
4.8/2.1.400/15.8 are locked and they are shipping very soon.
There will be no more changes there.
Regarding the mono change, it's not breaking the V1 plugins since the V1 plugins used the fallback signature verifier (always failed validation), which means it's not any worse than before.
The behavior is inconsistent across different installations and versions of mono (versions and OSs), so that'll be addressed in the next release. We'll call out the mono behavior in 4.8 in our release notes/docs.
@nkolev92 is it possible to use credential providers with MSBuild /t:Restore
for MSBuild 15.8?
No, Credential Provider support is rolling out as part of the 15.9 previews.
Per @nkolev92 below, this should be possible with 15.8.
Small correction.
15.8 assemblies and it's equivalent ship vehicles do have support for the credential providers.
As part of the 15.9 previews, we have VSTS support within Visual Studio.
//cc @rrelyea
List of current problems:
NuGet.Protocol
library causes deadlocks while sending log messagesdotnet nuget push
does not use credentials plugin. Fixed in https://github.com/NuGet/NuGet.Client/pull/2395dotnet nuget delete
does not use credentials plugin. Fixed in https://github.com/NuGet/NuGet.Client/pull/2414@nkolev92, @jainaashish, please let me know when these problems will be resolved.
I'm planning on closing this issue, to properly reflect that it has shipped in this 4.8 milestone.
@nkolev92 - can you please create/move remaining issues to 4.9 and 5.0 as appropriate.
@rrelyea so whats the fix? How can I install dependencies from authenticated feeds?
@phillip-haydon we've just released the Azure Artifacts Credential Provider. If you haven't updated to the required version of dotnet/nuget/msbuild (see readme), you can also use the old mechanism of a plain-text PAT: https://docs.microsoft.com/en-us/azure/devops/artifacts/nuget/dotnet-exe?view=vsts
@alexmullans This may be a silly question, but does this work for non-Azure feeds? The linked repo description implies its Azure-specific.
@bennettfactor the Azure Artifacts Credential Provider is specific to Azure Artifacts feeds. However, the plug-in mechanism that the Credential Provider uses to plug into NuGet/dotnet/MSBuild is generic. Another feed provider (e.g. MyGet) could write their own credential provider plug-in.
@alexmullans @nkolev92 With just the netcore
plugin, it looks like no credential providers are picked up, and instead an exception is thrown? Does the netcore
provider support interactive login (or at least device flow)?
Repro:
MultiThreadedCredentialsRepro.zip (need to make sure no netfx
plugin is installed)
NuGet.Protocol.Core.Types.FatalProtocolException
HResult=0x80131500
Message=Failed to retrieve metadata from source 'https://xxxxxxxxxxxx.pkgs.visualstudio.com/_packaging/17c08682-207e-46f3-8265-4d7fd84104bb/nuget/v3/query2/?q=&skip=0&take=10&prerelease=true&semVerLevel=2.0.0'.
Source=NuGet.Protocol
StackTrace:
at NuGet.Protocol.RawSearchResourceV3.<SearchPage>d__3.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at NuGet.Protocol.RawSearchResourceV3.<Search>d__4.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at NuGet.Protocol.PackageSearchResourceV3.<SearchAsync>d__3.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at MultiThreadedCredentialsRepro.Program.<Main>d__0.MoveNext() in C:\Users\maart\Desktop\MultiThreadedCredentialsRepro\MultiThreadedCredentialsRepro\Program.cs:line 66
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at MultiThreadedCredentialsRepro.Program.<Main>(String[] args)
It looks like discovery is hardcoded to netfx
and .exe
providers when using the NuGet SDK tools? Is there planned support to also have it load .NET Core plugins? (which would make it cross platform)
@maartenba
It already is supported, it works with dotnet.exe.
For discovery,
https://github.com/NuGet/NuGet.Client/blob/720f0669d33d4c9874344745629efab12116599b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginDiscoveryUtility.cs#L88
and https://github.com/NuGet/NuGet.Client/blob/720f0669d33d4c9874344745629efab12116599b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginDiscoverer.cs
For launching:
https://github.com/NuGet/NuGet.Client/blob/720f0669d33d4c9874344745629efab12116599b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginFactory.cs#L159-L168
Quickly skimming at your repro, you might be seeing https://github.com/NuGet/Home/issues/7438.
Thanks, that helps!
Our scenario is that we have desktop .NET targeted, running under Mono on Linux. So for discovery and launching, behaviour is based on the NuGet.Protocol target used? So full .NET can not launch a .NET Core provider? And vice-versa?
(This also means nuget.exe
under Mono currently does not support the netcore
plugins?)
[Edit] further investigation shows plugins are loaded based on the target framework NuGet.Protocol is compiled against. That's perhaps not ideal, but by plugging in some custom implementations for the IPluginResolver, this seems to work now.
Most helpful comment
Just an FYI: this already works cross-platform with JetBrains Rider's last preview version - www.jetbrains.com/rider/eap and with the existing plugin model, so wondering what work is left to do here other than hooking up a different executable to prompt for credentials?