mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-11 02:10:03 +00:00
Merge pull request #3157 from mgorny/ssh_memory_auth
Support getting SSH keys from memory, pt. 2
This commit is contained in:
commit
2c8550f040
@ -270,6 +270,11 @@ IF (LIBSSH2_FOUND)
|
||||
LINK_DIRECTORIES(${LIBSSH2_LIBRARY_DIRS})
|
||||
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} libssh2")
|
||||
SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES})
|
||||
|
||||
CHECK_LIBRARY_EXISTS(${LIBSSH2_LIBRARIES} libssh2_userauth_publickey_frommemory "" HAVE_LIBSSH2_MEMORY_CREDENTIALS)
|
||||
IF (HAVE_LIBSSH2_MEMORY_CREDENTIALS)
|
||||
ADD_DEFINITIONS(-DGIT_SSH_MEMORY_CREDENTIALS)
|
||||
ENDIF()
|
||||
ELSE()
|
||||
MESSAGE(STATUS "LIBSSH2 not found. Set CMAKE_PREFIX_PATH if it is installed outside of the default search path.")
|
||||
ENDIF()
|
||||
|
@ -108,6 +108,13 @@ typedef enum {
|
||||
* it will ask via this credential type.
|
||||
*/
|
||||
GIT_CREDTYPE_USERNAME = (1u << 5),
|
||||
|
||||
/**
|
||||
* Credentials read from memory.
|
||||
*
|
||||
* Only available for libssh2+OpenSSL for now.
|
||||
*/
|
||||
GIT_CREDTYPE_SSH_MEMORY = (1u << 6),
|
||||
} git_credtype_t;
|
||||
|
||||
/* The base structure for all credential types */
|
||||
@ -290,6 +297,23 @@ GIT_EXTERN(int) git_cred_default_new(git_cred **out);
|
||||
*/
|
||||
GIT_EXTERN(int) git_cred_username_new(git_cred **cred, const char *username);
|
||||
|
||||
/**
|
||||
* Create a new ssh key credential object reading the keys from memory.
|
||||
*
|
||||
* @param out The newly created credential object.
|
||||
* @param username username to use to authenticate.
|
||||
* @param publickey The public key of the credential.
|
||||
* @param privatekey The private key of the credential.
|
||||
* @param passphrase The passphrase of the credential.
|
||||
* @return 0 for success or an error code for failure
|
||||
*/
|
||||
GIT_EXTERN(int) git_cred_ssh_key_memory_new(
|
||||
git_cred **out,
|
||||
const char *username,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase);
|
||||
|
||||
/**
|
||||
* Signature of a function which acquires a credential object.
|
||||
*
|
||||
|
@ -9,6 +9,14 @@
|
||||
#include "smart.h"
|
||||
#include "git2/cred_helpers.h"
|
||||
|
||||
static int git_cred_ssh_key_type_new(
|
||||
git_cred **cred,
|
||||
const char *username,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase,
|
||||
git_credtype_t credtype);
|
||||
|
||||
int git_cred_has_username(git_cred *cred)
|
||||
{
|
||||
if (cred->credtype == GIT_CREDTYPE_DEFAULT)
|
||||
@ -31,6 +39,7 @@ const char *git_cred__username(git_cred *cred)
|
||||
return c->username;
|
||||
}
|
||||
case GIT_CREDTYPE_SSH_KEY:
|
||||
case GIT_CREDTYPE_SSH_MEMORY:
|
||||
{
|
||||
git_cred_ssh_key *c = (git_cred_ssh_key *) cred;
|
||||
return c->username;
|
||||
@ -174,6 +183,45 @@ int git_cred_ssh_key_new(
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
return git_cred_ssh_key_type_new(
|
||||
cred,
|
||||
username,
|
||||
publickey,
|
||||
privatekey,
|
||||
passphrase,
|
||||
GIT_CREDTYPE_SSH_KEY);
|
||||
}
|
||||
|
||||
int git_cred_ssh_key_memory_new(
|
||||
git_cred **cred,
|
||||
const char *username,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
#ifdef GIT_SSH_MEMORY_CREDENTIALS
|
||||
return git_cred_ssh_key_type_new(
|
||||
cred,
|
||||
username,
|
||||
publickey,
|
||||
privatekey,
|
||||
passphrase,
|
||||
GIT_CREDTYPE_SSH_MEMORY);
|
||||
#else
|
||||
giterr_set(GITERR_INVALID,
|
||||
"This version of libgit2 was not built with ssh memory credentials.");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int git_cred_ssh_key_type_new(
|
||||
git_cred **cred,
|
||||
const char *username,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase,
|
||||
git_credtype_t credtype)
|
||||
{
|
||||
git_cred_ssh_key *c;
|
||||
|
||||
@ -182,7 +230,7 @@ int git_cred_ssh_key_new(
|
||||
c = git__calloc(1, sizeof(git_cred_ssh_key));
|
||||
GITERR_CHECK_ALLOC(c);
|
||||
|
||||
c->parent.credtype = GIT_CREDTYPE_SSH_KEY;
|
||||
c->parent.credtype = credtype;
|
||||
c->parent.free = ssh_key_free;
|
||||
|
||||
c->username = git__strdup(username);
|
||||
|
@ -370,6 +370,25 @@ static int _git_ssh_authenticate_session(
|
||||
session, c->username, c->prompt_callback);
|
||||
break;
|
||||
}
|
||||
#ifdef GIT_SSH_MEMORY_CREDENTIALS
|
||||
case GIT_CREDTYPE_SSH_MEMORY: {
|
||||
git_cred_ssh_key *c = (git_cred_ssh_key *)cred;
|
||||
|
||||
assert(c->username);
|
||||
assert(c->privatekey);
|
||||
|
||||
rc = libssh2_userauth_publickey_frommemory(
|
||||
session,
|
||||
c->username,
|
||||
strlen(c->username),
|
||||
c->publickey,
|
||||
c->publickey ? strlen(c->publickey) : 0,
|
||||
c->privatekey,
|
||||
strlen(c->privatekey),
|
||||
c->passphrase);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED;
|
||||
}
|
||||
@ -740,6 +759,9 @@ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *use
|
||||
if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) {
|
||||
*out |= GIT_CREDTYPE_SSH_KEY;
|
||||
*out |= GIT_CREDTYPE_SSH_CUSTOM;
|
||||
#ifdef GIT_SSH_MEMORY_CREDENTIALS
|
||||
*out |= GIT_CREDTYPE_SSH_MEMORY;
|
||||
#endif
|
||||
ptr += strlen(SSH_AUTH_PUBLICKEY);
|
||||
continue;
|
||||
}
|
||||
|
@ -501,6 +501,74 @@ void test_online_clone__ssh_cert(void)
|
||||
cl_git_fail_with(GIT_EUSER, git_clone(&g_repo, "ssh://localhost/foo", "./foo", &g_options));
|
||||
}
|
||||
|
||||
static char *read_key_file(const char *path)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf;
|
||||
long key_length;
|
||||
|
||||
if (!path || !*path)
|
||||
return NULL;
|
||||
|
||||
cl_assert((f = fopen(path, "r")) != NULL);
|
||||
cl_assert(fseek(f, 0, SEEK_END) != -1);
|
||||
cl_assert((key_length = ftell(f)) != -1);
|
||||
cl_assert(fseek(f, 0, SEEK_SET) != -1);
|
||||
cl_assert((buf = malloc(key_length)) != NULL);
|
||||
cl_assert(fread(buf, key_length, 1, f) == 1);
|
||||
fclose(f);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int ssh_memory_cred_cb(git_cred **cred, const char *url, const char *user_from_url,
|
||||
unsigned int allowed_types, void *payload)
|
||||
{
|
||||
const char *remote_user = cl_getenv("GITTEST_REMOTE_USER");
|
||||
const char *pubkey_path = cl_getenv("GITTEST_REMOTE_SSH_PUBKEY");
|
||||
const char *privkey_path = cl_getenv("GITTEST_REMOTE_SSH_KEY");
|
||||
const char *passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE");
|
||||
|
||||
GIT_UNUSED(url); GIT_UNUSED(user_from_url); GIT_UNUSED(payload);
|
||||
|
||||
if (allowed_types & GIT_CREDTYPE_USERNAME)
|
||||
return git_cred_username_new(cred, remote_user);
|
||||
|
||||
if (allowed_types & GIT_CREDTYPE_SSH_KEY)
|
||||
{
|
||||
char *pubkey = read_key_file(pubkey_path);
|
||||
char *privkey = read_key_file(privkey_path);
|
||||
|
||||
int ret = git_cred_ssh_key_memory_new(cred, remote_user, pubkey, privkey, passphrase);
|
||||
|
||||
if (privkey)
|
||||
free(privkey);
|
||||
if (pubkey)
|
||||
free(pubkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
giterr_set(GITERR_NET, "unexpected cred type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void test_online_clone__ssh_memory_auth(void)
|
||||
{
|
||||
const char *remote_url = cl_getenv("GITTEST_REMOTE_URL");
|
||||
const char *remote_user = cl_getenv("GITTEST_REMOTE_USER");
|
||||
const char *privkey = cl_getenv("GITTEST_REMOTE_SSH_KEY");
|
||||
|
||||
#ifndef GIT_SSH_MEMORY_CREDENTIALS
|
||||
clar__skip();
|
||||
#endif
|
||||
if (!remote_url || !remote_user || !privkey || strncmp(remote_url, "ssh://", 5) != 0)
|
||||
clar__skip();
|
||||
|
||||
g_options.fetch_opts.callbacks.credentials = ssh_memory_cred_cb;
|
||||
|
||||
cl_git_pass(git_clone(&g_repo, remote_url, "./foo", &g_options));
|
||||
}
|
||||
|
||||
void test_online_clone__url_with_no_path_returns_EINVALIDSPEC(void)
|
||||
{
|
||||
cl_git_fail_with(git_clone(&g_repo, "http://github.com", "./foo", &g_options),
|
||||
|
Loading…
Reference in New Issue
Block a user