将 SSH 身份验证与 libgit2 结合使用 [英] Using SSH authentification with libgit2

查看:49
本文介绍了将 SSH 身份验证与 libgit2 结合使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 SSH 密钥对带有 libgit2 的 git 服务器进行身份验证.到目前为止,这适用于像 ssh://myuser@host.domain:1234/dirs/repo.git 这样的 URL,其中我的应用程序接受 URL 作为参数.

I am trying to authenticate against a git server with libgit2 using SSH keys. So far, this is working for URLs like ssh://myuser@host.domain:1234/dirs/repo.git, where my application accepts the URL as an argument.

但是,如果我从 URL(即 ssh://host.domain:1234/dirs/repo.git)中删除用户名,连接将失败,即使我设置了用户名以编程方式(见下文).

However, if I remove the username from the URL (i.e. ssh://host.domain:1234/dirs/repo.git) the connection fails, even if I set the user name programmatically (see below).

考虑以下 MCVE,用于检查某个存储库是否可访问的程序(除必要外不进行错误检查):

Consider the following MCVE for a program that checks whether a certain repository is reachable (no error checks except for the necessary):

#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 编译,假设包含和库路径设置正确.

This can be compiled with gcc -Wall -pedantic -std=c99 -o myapp main.c -lssh2 -lgit2, assuming the include and library paths are set properly.

现在考虑不同 URL 的输出:

Now consider the output for different 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

我不明白为什么会收到此错误,因为我将完全相同的信息传递给库(为什么它首先是不受支持的凭据类型"?).

I do not understand why I receive this error, since I pass the exact same information to the library (why is it "unsupported credentials type" in the first place?).

更糟糕的是,我通常在我的 ~/.ssh/config 中使用 Host 条目,而不是将 host.domain:1234> 我可以简单地使用 myhost(例如 git clone ssh://myhost/dirs/repo.git 工作得很好).对于我的应用程序,这是输出:

Even worse, I usually use Host entries in my ~/.ssh/config, such that instead of putting host.domain:1234 I can simply use myhost (e.g. git clone ssh://myhost/dirs/repo.git works just fine). For my application, this is the output:

$ ./myapp ssh://myhost/dirs/repo.git
Error 12: failed to resolve address for myhost: Name or service not known

看起来 libgit2 没有配置 libssh2 来读取 ssh-config.这是一个相关的,但可能是一个不同的问题.我仍然觉得这两个问题是一体的.

It looks like libgit2 does not configure libssh2 to read in the ssh-config. That's a related, yet probably a different problem. Still I feel these two problems belong together.

总结我的问题:

  1. 如何以编程方式(与在 URL 中相比)将用户名传递给 git 凭据?
  2. 如何在尝试连接之前告诉 libgit2 从我的 ssh-config 中检索信息?
  1. How do I pass the username to the git credentials programmatically (vs. in the URL)?
  2. How do I tell libgit2 to retrieve information from my ssh-config before attempting to connect?

推荐答案

这确实是两个不相关的问题.

These really are two separate unrelated questions.

  1. 您应该检查回调中的 allowed_types 参数,并且只返回包含 GIT_CREDTYPE_SSH_KEYgit_cred_ssh_key_new 凭据.后端可能正在请求 GIT_CREDTYPE_USERNAME 类型的凭据,因为 URL 没有.在这种情况下,您应该返回由 git_cred_username_new 创建的凭证.您的回调将被调用两次,一次是为了获取用户名,第二次是为了创建 ssh 凭据.

  1. You should be checking the allowed_types parameter in your callback and only return a git_cred_ssh_key_new credential if it contains GIT_CREDTYPE_SSH_KEY. The backend is probably requesting a credential of type GIT_CREDTYPE_USERNAME because the URL doesn't have one. In that case you should be returning a credential created by git_cred_username_new. Your callback will be called twice, once to get the username, and a second time to create the ssh credential.

libgit2 不支持从位于 ~/.ssh/config 的 OpenSSH 配置文件中读取配置设置,因为 libssh2 不支持它.如果你想从那里读取设置,你必须自己做.

Reading config settings from your OpenSSH config file at ~/.ssh/config isn't supported by libgit2 because it isn't support by libssh2. If you want to read settings from there, you have to do it yourself.

这篇关于将 SSH 身份验证与 libgit2 结合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆