在 libgit2 中使用 SSH 身份验证
Using SSH authentification with libgit2
我正在尝试使用 SSH 密钥通过 libgit2
对 git 服务器进行身份验证。
到目前为止,这适用于像 ssh://myuser@host.domain:1234/dirs/repo.git
这样的 URL,我的应用程序接受 URL 作为参数。
但是,如果我从 URL(即 ssh://host.domain:1234/dirs/repo.git
)中删除用户名,连接将失败,即使我以编程方式设置用户名(见下文)。
考虑以下 MCVE 程序,该程序检查某个存储库是否可访问(除必要情况外不进行错误检查):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <git2.h>
#include <git2/sys/repository.h>
int my_cred_cb(git_cred **out, const char *url,
const char *username_from_url, unsigned int allowed_types, void *payload)
{
uid_t uid = geteuid(); // Get effective user ID
struct passwd* pw = getpwuid(uid); // Get password file entry
char privkeypath[strlen(pw->pw_dir) + 13];
strcpy(privkeypath, pw->pw_dir);
strcat(privkeypath, "/.ssh/id_rsa"); // "~user/.ssh/id_rsa"
char publkeypath[strlen(privkeypath) + 5];
strcpy(publkeypath, privkeypath);
strcat(publkeypath, ".pub"); // "~user/.ssh/id_rsa.pub"
const char* username = (username_from_url != NULL ? username_from_url : pw->pw_name);
printf("Using username: %s, priv key %s and publ key %s\n", username, privkeypath, publkeypath);
return git_cred_ssh_key_new(out, username, publkeypath, privkeypath, ""); // No passphrase for keys
}
int main(int argc, char** argv)
{
git_remote* remote = NULL;
git_repository* repo = NULL;
git_remote_callbacks cbs;
const git_error* err;
if (argc != 2) return EXIT_FAILURE;
git_libgit2_init();
git_repository_new(&repo);
git_remote_create_anonymous(&remote, repo, argv[1]);
git_remote_init_callbacks(&cbs, GIT_REMOTE_CALLBACKS_VERSION);
cbs.credentials = my_cred_cb;
if (git_remote_connect(remote, GIT_DIRECTION_FETCH, &cbs, NULL, NULL)) {
err = giterr_last();
printf ("Error %d: %s\n", err->klass, err->message);
return EXIT_FAILURE;
}
git_libgit2_shutdown();
printf("git repo exists and is reachable.\n");
}
这可以用 gcc -Wall -pedantic -std=c99 -o myapp main.c -lssh2 -lgit2
编译,假设包含和库路径设置正确。
现在考虑不同 URLs 的输出:
$ ./myapp ssh://myuser@host.domain:1234/dirs/repo.git
Using username: myuser, priv key /home/myuser/.ssh/id_rsa and publ key /home/myuser/.ssh/id_rsa.pub
git repo exists and is reachable.
现在失败的案例:
$ ./myapp ssh://host.domain:1234/dirs/repo.git # Note the missing user name
Using username: myuser, priv key /home/myuser/.ssh/id_rsa and publ key /home/myuser/.ssh/id_rsa.pub
Error 23: callback returned unsupported credentials type
我不明白为什么会收到此错误,因为我将完全相同的信息传递给了图书馆(为什么首先是 "unsupported credentials type"?)。
更糟糕的是,我通常在 ~/.ssh/config
中使用 Host
条目,这样我就可以简单地使用 myhost
而不是 host.domain:1234
(例如 git clone ssh://myhost/dirs/repo.git
工作得很好)。对于我的应用程序,这是输出:
$ ./myapp ssh://myhost/dirs/repo.git
Error 12: failed to resolve address for myhost: Name or service not known
看起来 libgit2
没有配置 libssh2
读取 ssh-config。这是一个相关的,但可能是一个不同的问题。我还是觉得这两个问题是一个问题。
总结我的问题:
- 如何以编程方式将用户名传递给 git 凭据(相对于 URL)?
- 如何告诉
libgit2
在尝试连接之前从我的 ssh-config 检索信息?
这确实是两个独立的不相关问题。
您应该检查回调中的 allowed_types
参数,并且只有 return 包含 GIT_CREDTYPE_SSH_KEY
的 git_cred_ssh_key_new
凭据。后端可能正在请求 GIT_CREDTYPE_USERNAME
类型的凭据,因为 URL 没有。在这种情况下,您应该 returning 由 git_cred_username_new
创建的凭据。您的回调将被调用两次,一次是为了获取用户名,第二次是为了创建 ssh 凭证。
从位于 ~/.ssh/config 的 OpenSSH 配置文件中读取配置设置不受 libgit2 支持,因为它不受 libssh2 支持。如果你想从那里读取设置,你必须自己做。
我正在尝试使用 SSH 密钥通过 libgit2
对 git 服务器进行身份验证。
到目前为止,这适用于像 ssh://myuser@host.domain:1234/dirs/repo.git
这样的 URL,我的应用程序接受 URL 作为参数。
但是,如果我从 URL(即 ssh://host.domain:1234/dirs/repo.git
)中删除用户名,连接将失败,即使我以编程方式设置用户名(见下文)。
考虑以下 MCVE 程序,该程序检查某个存储库是否可访问(除必要情况外不进行错误检查):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <git2.h>
#include <git2/sys/repository.h>
int my_cred_cb(git_cred **out, const char *url,
const char *username_from_url, unsigned int allowed_types, void *payload)
{
uid_t uid = geteuid(); // Get effective user ID
struct passwd* pw = getpwuid(uid); // Get password file entry
char privkeypath[strlen(pw->pw_dir) + 13];
strcpy(privkeypath, pw->pw_dir);
strcat(privkeypath, "/.ssh/id_rsa"); // "~user/.ssh/id_rsa"
char publkeypath[strlen(privkeypath) + 5];
strcpy(publkeypath, privkeypath);
strcat(publkeypath, ".pub"); // "~user/.ssh/id_rsa.pub"
const char* username = (username_from_url != NULL ? username_from_url : pw->pw_name);
printf("Using username: %s, priv key %s and publ key %s\n", username, privkeypath, publkeypath);
return git_cred_ssh_key_new(out, username, publkeypath, privkeypath, ""); // No passphrase for keys
}
int main(int argc, char** argv)
{
git_remote* remote = NULL;
git_repository* repo = NULL;
git_remote_callbacks cbs;
const git_error* err;
if (argc != 2) return EXIT_FAILURE;
git_libgit2_init();
git_repository_new(&repo);
git_remote_create_anonymous(&remote, repo, argv[1]);
git_remote_init_callbacks(&cbs, GIT_REMOTE_CALLBACKS_VERSION);
cbs.credentials = my_cred_cb;
if (git_remote_connect(remote, GIT_DIRECTION_FETCH, &cbs, NULL, NULL)) {
err = giterr_last();
printf ("Error %d: %s\n", err->klass, err->message);
return EXIT_FAILURE;
}
git_libgit2_shutdown();
printf("git repo exists and is reachable.\n");
}
这可以用 gcc -Wall -pedantic -std=c99 -o myapp main.c -lssh2 -lgit2
编译,假设包含和库路径设置正确。
现在考虑不同 URLs 的输出:
$ ./myapp ssh://myuser@host.domain:1234/dirs/repo.git
Using username: myuser, priv key /home/myuser/.ssh/id_rsa and publ key /home/myuser/.ssh/id_rsa.pub
git repo exists and is reachable.
现在失败的案例:
$ ./myapp ssh://host.domain:1234/dirs/repo.git # Note the missing user name
Using username: myuser, priv key /home/myuser/.ssh/id_rsa and publ key /home/myuser/.ssh/id_rsa.pub
Error 23: callback returned unsupported credentials type
我不明白为什么会收到此错误,因为我将完全相同的信息传递给了图书馆(为什么首先是 "unsupported credentials type"?)。
更糟糕的是,我通常在 ~/.ssh/config
中使用 Host
条目,这样我就可以简单地使用 myhost
而不是 host.domain:1234
(例如 git clone ssh://myhost/dirs/repo.git
工作得很好)。对于我的应用程序,这是输出:
$ ./myapp ssh://myhost/dirs/repo.git
Error 12: failed to resolve address for myhost: Name or service not known
看起来 libgit2
没有配置 libssh2
读取 ssh-config。这是一个相关的,但可能是一个不同的问题。我还是觉得这两个问题是一个问题。
总结我的问题:
- 如何以编程方式将用户名传递给 git 凭据(相对于 URL)?
- 如何告诉
libgit2
在尝试连接之前从我的 ssh-config 检索信息?
这确实是两个独立的不相关问题。
您应该检查回调中的
allowed_types
参数,并且只有 return 包含GIT_CREDTYPE_SSH_KEY
的git_cred_ssh_key_new
凭据。后端可能正在请求GIT_CREDTYPE_USERNAME
类型的凭据,因为 URL 没有。在这种情况下,您应该 returning 由git_cred_username_new
创建的凭据。您的回调将被调用两次,一次是为了获取用户名,第二次是为了创建 ssh 凭证。从位于 ~/.ssh/config 的 OpenSSH 配置文件中读取配置设置不受 libgit2 支持,因为它不受 libssh2 支持。如果你想从那里读取设置,你必须自己做。