【问题标题】:Get Nuget credentials stored somewhere by Visual Studio in a VSIX project获取 Visual Studio 在 VSIX 项目中某处存储的 Nuget 凭据
【发布时间】:2018-11-08 09:53:55
【问题描述】:

我正在开发一个需要管理给定项目的 Nuget 包的 Visual Studio 扩展(VSIX 项目)。

我已经将IVsPackageInstaller 服务用作documented here,但这是有限的,我需要更多功能(例如获取给定软件包的最新版本号)。

我搜索但没有找到任何关于如何以编程方式与 Visual Studio 包管理器交互的信息,因此我决定直接使用 Nuget API。

我使用 WebRequest 类向 Nuget API 发送 HTTP 请求(因为我们不能在 VSIX 项目中使用 HttpClient)但我遇到了一个问题:请求将发送到一个私有 Nuget 提要需要认证! (托管在 Azure DevOps 上)

我使用Fiddler 检查发送到我们的 Azure DevOps 服务器的 HTTP 请求。我看到一个发往 https://app.vssps.visualstudio.com/_apis/Token/SessionTokens 的 POST 请求带有一个令牌作为响应,但这不是我正在寻找的令牌。

传递给 Nuget API 的令牌是一个 Basic 令牌,我不知道它来自哪里。我在捕获的 HTTP 响应中的任何地方都找不到这个令牌。

我还可以看到对我们的 Azure DevOps 服务器的一些响应包含一些像这样的标头(我更改了 GUID)

WWW-Authenticate: Bearer authorization_uri=https://login.windows.net/ce372fcc-5e17-490b-ad99-47565dac8a84

我可以在 %userprofile%\AppData\Local\.IdentityService\AccountStore.json 文件中找到这个 GUID,这里肯定有一些事情发生。同一个文件夹中的SessionTokens.json 文件看起来也很有趣,但它是加密的......

我还尝试在注册表中挖掘以查看是否可以在 Simon's comment 中指定的路径中找到有趣的信息,但似乎 VS2017 不再将令牌存储在那里。

我还加载了privateregistry.bin 文件(又名Visual Studio Settings Store)并到处搜索,但找不到任何东西。

因此,我不想尝试对 Visual Studio 进行逆向工程,而是想直接访问其凭据提供程序。我尝试访问多个服务和类

var componentModel = await ServiceProvider.GetGlobalServiceAsync(typeof(SComponentModel)) as IComponentModel;
var credentialProvider = componentModel.GetService<IVsCredentialProvider>();
var credentialServiceProvider = componentModel.GetService<ICredentialServiceProvider>();
var defaultCredentialServiceProvider = new DefaultVSCredentialServiceProvider();

但它们都不起作用(返回 null 或异常)。

我在 Github 上的 NuGet.PackageManagement.VisualStudio 项目中徘徊,但找不到我的答案。

还有很多 Nuget 包,例如 NuGet.PackageManagement.VisualStudioMicrosoft.VisualStudio.Services.Release.ClientMicrosoft.VisualStudio.Services.ExtensionManagement.WebApiMicrosoft.VisualStudio.Services.InteractiveClient /p>

那么如何访问 Visual Studio 使用的 Nuget 凭据呢?

我采用任何可以让我访问所有读取 Nuget 功能的解决方案,例如以编程方式使用 Visual Studio 包管理,或解密此 SessionTokens.json 文件或访问 Visual Studio 凭据提供程序。

hacky 越少,答案就越好。

此时您可能已经猜到了,我不想将usernamepassword 存储在自己的某个地方。我需要创建一个用户友好的 VS 扩展,这就是为什么我要检索和使用用户已经保存在 Visual Studio 中的凭据。

如果你能解决这个问题,非常感谢。

【问题讨论】:

  • 为什么不用nuget客户端API? github.com/NuGet/NuGet.Client 这就是 Visual Studio 使用的。
  • 哇,非常感谢,老实说,我有点惊讶,唯一的文档是 2016 年的非官方博客文章。这解决了我的 Nuget 问题,但我很固执,我想了解当我我面临一个问题。开发人员可以使用服务提供商正式访问 VS 存储的凭据吗?如果是,我们该怎么办?谢谢你的回答
  • 现在开源的所有东西都有一些缺点。什么是官方的现在是一个灰色地带,并且文档已经大大减少。作为开发人员,我们现在只能靠自己了……许多 VS 包现在都在使用 MEF,所以我认为您可以向 MEF 询问在 NuGet.PackageManagement.VisualStudio 中定义的 ICredentialServiceProvider 接口。如果你想更深入,只需分析它是如何实现的。 Visual Studio 代码库很大,祝你好运:-)
  • 就是这样,我试过componentModel.GetService&lt;ICredentialServiceProvider&gt;(),但它没有给我任何实际的凭据提供程序。是的,它很大,我迷失在所有的代码中,这就是为什么我希望你能得到神奇的答案。但是谢谢,您通过指向NuGet.Client 帮助了我很多。有了所有这些代码,我完全不知道应该使用什么。
  • 你应该提供一个小的复制样本

标签: c# visual-studio nuget visual-studio-extensions vsix


【解决方案1】:

NuGet 客户端 SDK

非常感谢Simon who pointed me in the direction of NuGet.Client

only documentation from Microsoft 正在链接 2016 blog post from Dave Glick,但他们也给出了很好的说明:

这些博文是在 NuGet 客户端 SDK 包的 3.4.3 版本发布后不久编写的。较新版本的软件包可能与博文中的信息不兼容。

好吧,那我想我们会处理 Dave 的博客...

你应该安装两个包:NuGet.ClientNuget.Protocol

下面是获取软件包最新版本的示例代码:

using NuGet.Configuration;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace MyProject
{
    public class NugetHelper
    {
        public async Task<string> GetLatestVersionNumberFromNugetFeedAsync(NugetPackage package)
        {
            try
            {
                Logger logger = new Logger(); //Just a class implementing the Nuget.Common.ILogger interface
                List<Lazy<INuGetResourceProvider>> providers = new List<Lazy<INuGetResourceProvider>>();
                providers.AddRange(Repository.Provider.GetCoreV3());  // Add v3 API support
                PackageSource packageSource = new PackageSource(package.Source.ToString());
                SourceRepository sourceRepository = new SourceRepository(packageSource, providers);
                PackageMetadataResource packageMetadataResource = await sourceRepository.GetResourceAsync<PackageMetadataResource>();
                var searchMetadata = await packageMetadataResource.GetMetadataAsync(package.Name, false, false, new SourceCacheContext(), logger, new CancellationToken());
                var versionNumber = searchMetadata.FirstOrDefault().Identity.Version.OriginalVersion;
                return versionNumber;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    }

    public class NugetPackage
    {
        public string Name { get; set; }
        public string Version { get; set; }
        public string MinimumVersion { get; set; }
        public Uri Source { get; set; }
    }
}

物理令牌存储场所

我尝试逆向工程,Visual Studio 将 HTTP 请求中使用的令牌存储到 Nuget API 的位置。

我将注册表的所有不同配置单元导出到文本文件,包括 Visual Studio 设置存储 (privateregistry.bin)。 然后在 Visual Studio 中添加了一个全新的 Nuget 提要,按预期得到了登录弹出窗口,所以我登录了。 最后,我再次将所有配置单元导出为文本文件,并将它们与身份验证前的文件进行比较。

我在 VS 设置商店中没有发现任何有趣的东西。

唯一有趣的变化是

[HKEY_CURRENT_USER\Software\Microsoft\VSCommon\ConnectedUser\IdeUserV2] @="0746fb8e-4bc2-4ee5-b804-0084af725deb" "AccountsRoaming_LastAccountsSettingVersion"=dword:0000025b

[HKEY_CURRENT_USER\Software\Microsoft\VsHub\ServiceModules\Settings\PerHubName\vshub\ConnectedUser\IdeUserV2\Cache] "LastProfileVersion"=dword:10b8260a

[HKEY_USERS\S-1-5-21-1787888774-1556370510-3519259403-1001\Software\Microsoft\VSCommon\Keychain] "TokenStorageNameSpace"="VisualStudio"

[HKEY_USERS\S-1-5-21-1787888774-1556370510-3519259403-1001\Software\Microsoft\VsHub\ServiceModules\Settings\PerHubName\vshub\ConnectedUser\IdeUserV2\Cache] "LastProfileVersion"=dword:10b8260a

也许在某个地方,这些加密的 SessionTokens.jsonIdentityServiceAdalCache.cache 文件存在密钥,但以十六进制存储数据会使事情变得更加困难。

我必须放弃这个,我几乎没有机会对身份验证系统进行逆向工程。

Visual Studio 凭据提供程序

NuGet Client SDK 解决了我的问题,但实际上并没有回答这个 SO 问题。

如我所说,我试着打电话

var componentModel = await ServiceProvider.GetGlobalServiceAsync(typeof(SComponentModel)) as IComponentModel;
componentModel.GetService<ICredentialServiceProvider>()

但这不起作用,所以如果有人知道如何访问 Visual Studio 凭据提供程序,我会很高兴知道答案。

【讨论】:

  • 太好了,感谢您在这里分享您的解决方案,您可以Accept it as an Answer。这可能对阅读此主题的其他社区成员有益,我们可以关闭此主题,谢谢。
  • 它解决了我的问题,但实际上并没有完全回答我的问题。我开始创建一个示例项目suggested by Simon,但我现在没有太多时间。我还在调查 VS 对注册表所做的更改。完成所有这些后,我会将其标记为已接受。目前我对我的回答状态并不完全满意。
  • 那太好了,谢谢你的贡献:)。
猜你喜欢
  • 2023-03-13
  • 2023-04-01
  • 2022-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多