LibGit2Sharp:如何使用自定义 HTTP 身份验证中的个人访问令牌将本地存储库提交推送到 Azure DevOps 远程存储库 header?
LibGit2Sharp: How to push a local repo commit to Azure DevOps remote repo using a Personal Access Token inside a custom HTTP authentication header?
我正在尝试使用 LibGit2Sharp 以编程方式将我在本地存储库上所做的提交推送到远程副本,该副本托管在私有 Azure DevOps 服务器上。
根据 Azure documentation,启用 HTTPS OAuth 的个人访问令牌需要在自定义身份验证 header 中与请求一起发送,如 'Basic' 和 Base64 编码令牌:
var personalaccesstoken = "PATFROMWEB";
using (HttpClient client = new HttpClient()) {
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes($":{personalaccesstoken}")));
using (HttpResponseMessage response = client.GetAsync(
"https://dev.azure.com/{organization}/{project}/_apis/build/builds?api-version=5.0").Result) {
response.EnsureSuccessStatusCode();
}
}
LibGit2Sharp.CloneOptions
class has a FetchOptions
field which in turn has a CustomHeaders
array that can be used to inject the authentication header during the clone operation, like the following (as mentioned in this issue):
CloneOptions cloneOptions = new() {
CredentialsProvider = (url, usernameFromUrl, types) => new UsernamePasswordCredentials {
Username = $"{USERNAME}",
Password = $"{ACCESSTOKEN}"
},
FetchOptions = new FetchOptions {
CustomHeaders = new[] {
$"Authorization: Basic {encodedToken}"
}
}
};
Repository.Clone(AzureUrl, LocalDirectory, cloneOptions);
并且克隆过程成功(我测试了它以及 checked the source code :))
但是,LibGit2Sharp.PushOptions
没有任何此类机制来注入身份验证 header。我限于以下代码:
PushOptions pushOptions = new()
{
CredentialsProvider = (url, usernameFromUrl, types) => new UsernamePasswordCredentials
{
Username = $"{USERNAME}",
Password = $"{PASSWORD}"
}
};
这使我的推送操作失败并显示以下消息:
Too many redirects or authentication replays
我检查了 Repository.Network.Push()
on Github 的源代码。
public virtual void Push(Remote remote, IEnumerable<string> pushRefSpecs, PushOptions pushOptions)
{
Ensure.ArgumentNotNull(remote, "remote");
Ensure.ArgumentNotNull(pushRefSpecs, "pushRefSpecs");
// Return early if there is nothing to push.
if (!pushRefSpecs.Any())
{
return;
}
if (pushOptions == null)
{
pushOptions = new PushOptions();
}
// Load the remote.
using (RemoteHandle remoteHandle = Proxy.git_remote_lookup(repository.Handle, remote.Name, true))
{
var callbacks = new RemoteCallbacks(pushOptions);
GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks();
Proxy.git_remote_push(remoteHandle,
pushRefSpecs,
new GitPushOptions()
{
PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism,
RemoteCallbacks = gitCallbacks,
ProxyOptions = new GitProxyOptions { Version = 1 },
});
}
}
正如我们在上面看到的,Push()
方法内部的 Proxy.git_remote_push
方法调用正在传递一个新的 GitPushOptions
object,这确实 seems to have a CustomHeaders
field implemented. 但是它没有暴露给消费者应用程序,而是直接在库代码中实例化!
我绝对有必要使用 LibGit2Sharp API,并且我们的 end-to-end 测试需要在 Azure DevOps 存储库上完成,所以这个问题阻碍了我的进一步发展。
我的问题是:
- 是否可以使用其他方式对来自 LibGit2Sharp 的 Azure 推送操作进行身份验证?我们能否利用
PushOptions.CredentialsProvider
处理程序,使其与 Azure 坚持的 auth-n 方法兼容?
- 我们可以通过在执行 Push 命令之前在
FetchOptions
object 中注入 header 来调用 Commands.Fetch
来缓存凭据吗?我试过了,但失败并出现同样的错误。
- 为了解决这个问题,是否需要对库进行修改以使其与 Azure Repos 兼容?如果是,那么如果有人可以给我关于如何绑定到本机代码的指示,那么我可以加强并做出贡献:)
我会回答我自己的问题,因为我们已经解决了这个问题。
解决这个问题很简单;我只需要从 PushOptions
对象中删除 CredentialsProvider
委托,即:
var pushOptions = new PushOptions();
而不是,
PushOptions pushOptions = new()
{
CredentialsProvider = (url, usernameFromUrl, types) => new UsernamePasswordCredentials
{
Username = $"{USERNAME}",
Password = $"{PASSWORD}"
}
};
¯\(ツ)/¯
我不知道它为什么有效,但确实有效。 (也许 Azure 的一些人可以向我们澄清一下。)
我正在尝试使用 LibGit2Sharp 以编程方式将我在本地存储库上所做的提交推送到远程副本,该副本托管在私有 Azure DevOps 服务器上。
根据 Azure documentation,启用 HTTPS OAuth 的个人访问令牌需要在自定义身份验证 header 中与请求一起发送,如 'Basic' 和 Base64 编码令牌:
var personalaccesstoken = "PATFROMWEB";
using (HttpClient client = new HttpClient()) {
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes($":{personalaccesstoken}")));
using (HttpResponseMessage response = client.GetAsync(
"https://dev.azure.com/{organization}/{project}/_apis/build/builds?api-version=5.0").Result) {
response.EnsureSuccessStatusCode();
}
}
LibGit2Sharp.CloneOptions
class has a FetchOptions
field which in turn has a CustomHeaders
array that can be used to inject the authentication header during the clone operation, like the following (as mentioned in this issue):
CloneOptions cloneOptions = new() {
CredentialsProvider = (url, usernameFromUrl, types) => new UsernamePasswordCredentials {
Username = $"{USERNAME}",
Password = $"{ACCESSTOKEN}"
},
FetchOptions = new FetchOptions {
CustomHeaders = new[] {
$"Authorization: Basic {encodedToken}"
}
}
};
Repository.Clone(AzureUrl, LocalDirectory, cloneOptions);
并且克隆过程成功(我测试了它以及 checked the source code :))
但是,LibGit2Sharp.PushOptions
没有任何此类机制来注入身份验证 header。我限于以下代码:
PushOptions pushOptions = new()
{
CredentialsProvider = (url, usernameFromUrl, types) => new UsernamePasswordCredentials
{
Username = $"{USERNAME}",
Password = $"{PASSWORD}"
}
};
这使我的推送操作失败并显示以下消息:
Too many redirects or authentication replays
我检查了 Repository.Network.Push()
on Github 的源代码。
public virtual void Push(Remote remote, IEnumerable<string> pushRefSpecs, PushOptions pushOptions)
{
Ensure.ArgumentNotNull(remote, "remote");
Ensure.ArgumentNotNull(pushRefSpecs, "pushRefSpecs");
// Return early if there is nothing to push.
if (!pushRefSpecs.Any())
{
return;
}
if (pushOptions == null)
{
pushOptions = new PushOptions();
}
// Load the remote.
using (RemoteHandle remoteHandle = Proxy.git_remote_lookup(repository.Handle, remote.Name, true))
{
var callbacks = new RemoteCallbacks(pushOptions);
GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks();
Proxy.git_remote_push(remoteHandle,
pushRefSpecs,
new GitPushOptions()
{
PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism,
RemoteCallbacks = gitCallbacks,
ProxyOptions = new GitProxyOptions { Version = 1 },
});
}
}
正如我们在上面看到的,Push()
方法内部的 Proxy.git_remote_push
方法调用正在传递一个新的 GitPushOptions
object,这确实 seems to have a CustomHeaders
field implemented. 但是它没有暴露给消费者应用程序,而是直接在库代码中实例化!
我绝对有必要使用 LibGit2Sharp API,并且我们的 end-to-end 测试需要在 Azure DevOps 存储库上完成,所以这个问题阻碍了我的进一步发展。
我的问题是:
- 是否可以使用其他方式对来自 LibGit2Sharp 的 Azure 推送操作进行身份验证?我们能否利用
PushOptions.CredentialsProvider
处理程序,使其与 Azure 坚持的 auth-n 方法兼容? - 我们可以通过在执行 Push 命令之前在
FetchOptions
object 中注入 header 来调用Commands.Fetch
来缓存凭据吗?我试过了,但失败并出现同样的错误。 - 为了解决这个问题,是否需要对库进行修改以使其与 Azure Repos 兼容?如果是,那么如果有人可以给我关于如何绑定到本机代码的指示,那么我可以加强并做出贡献:)
我会回答我自己的问题,因为我们已经解决了这个问题。
解决这个问题很简单;我只需要从 PushOptions
对象中删除 CredentialsProvider
委托,即:
var pushOptions = new PushOptions();
而不是,
PushOptions pushOptions = new()
{
CredentialsProvider = (url, usernameFromUrl, types) => new UsernamePasswordCredentials
{
Username = $"{USERNAME}",
Password = $"{PASSWORD}"
}
};
¯\(ツ)/¯
我不知道它为什么有效,但确实有效。 (也许 Azure 的一些人可以向我们澄清一下。)