Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

authentication required but no callback set #329

Closed
JMLX42 opened this issue Jul 8, 2018 · 6 comments
Closed

authentication required but no callback set #329

JMLX42 opened this issue Jul 8, 2018 · 6 comments

Comments

@JMLX42
Copy link
Contributor

JMLX42 commented Jul 8, 2018

I'm using an env var to get the path to the SSH private key.
This key is a passphrase-less GitLab deploy key. That key works great when I use it with a classic git clone.

But it doesn't work with RepoBuilder::clone().

Expected result

Repository is cloned.

Actual result

The following error:

authentication required but no callback set; class=Ssh (23)

How to reproduce

pub fn git_credentials_callback(
    _user: &str,
    _user_from_url: Option<&str>,
    _cred: git2::CredentialType,
) -> Result<git2::Cred, git2::Error> {
    match env::var("GPM_SSH_KEY") {
        Ok(k) => {
            debug!("authenticate with private key located in {}", k);
            
            git2::Cred::ssh_key("git", None, std::path::Path::new(&k), None)
        },
        _ => Err(git2::Error::from_str("unable to get private key from GPM_SSH_KEY")),
    }
}

fn get_or_init_repo(cache : &std::path::Path, remote : &String) -> Result<git2::Repository, git2::Error> {
    let data_url = match Url::parse(remote) {
        Ok(data_url) => data_url,
        Err(e) => panic!("failed to parse url: {}", e),
    };
    let path = cache.deref().join(data_url.host_str().unwrap()).join(&data_url.path()[1..]);

    if path.exists() {
        debug!("use existing repository already in cache {}", path.to_str().unwrap());
        return git2::Repository::open(path);
    }

    let mut callbacks = git2::RemoteCallbacks::new();
    callbacks.credentials(git_credentials_callback);

    let mut opts = git2::FetchOptions::new();
    opts.remote_callbacks(callbacks);
    opts.download_tags(git2::AutotagOption::All);

    let mut builder = git2::build::RepoBuilder::new();
    builder.fetch_options(opts);
    builder.branch("master");

    debug!("start cloning repository {} in {}", remote, path.to_str().unwrap());
    
    match builder.clone(remote, &path) {
        Ok(r) => {
            debug!("repository cloned");

            Ok(r)
        },
        Err(e) => Err(e)
    }
}
@JMLX42
Copy link
Contributor Author

JMLX42 commented Jul 8, 2018

It turns ou _cred contains only git2::CredentialType::USERNAME.
But my git server clearly works with a SSH key when I do a git clone.
Is there a way to make sure the requested credentials are git2::CredentialType::SSH_KEY?

@JMLX42
Copy link
Contributor Author

JMLX42 commented Jul 8, 2018

Ok got it working by reading this comment:

libgit2/git2go#199 (comment)

The callback is called twice:

  • first to get the username;
  • then to get the SSH key.

Here is the right callback implementation:

pub fn git_credentials_callback(
    _user: &str,
    _user_from_url: Option<&str>,
    _cred: git2::CredentialType,
) -> Result<git2::Cred, git2::Error> {
    let user = _user_from_url.unwrap_or("git");

    if _cred.contains(git2::CredentialType::USERNAME) {
        return git2::Cred::username(user);
    }

    match env::var("GPM_SSH_KEY") {
        Ok(k) => {

            debug!("authenticate with user {} and private key located in {}", user, k);
            git2::Cred::ssh_key(user, None, std::path::Path::new(&k), None)
        },
        _ => Err(git2::Error::from_str("unable to get private key from GPM_SSH_KEY")),
    }
}

@JMLX42 JMLX42 closed this as completed Jul 8, 2018
@neithernut
Copy link

Maybe it would make sense to extend the documentation for either the callback or the function accepting it.

@alexcrichton
Copy link
Member

Certainly! I think the documentation around authenticated clones could definitely use a boost

@darakeon
Copy link

darakeon commented Aug 2, 2022

I'm using callback as:

fn git_credentials_callback(
	_url: &str,
	username: Option<&str>,
	_cred_type: CredentialType,
) -> Result<Cred, Error> {
	let public = get_key_path(Some("pub"));
	let private = get_key_path(None);

	let password = env::var("GIT_PASSWORD")
		.expect("No GIT_PASSWORD environment variable found");

	let cred = Cred::ssh_key(
		username.unwrap(),
		Some(public.as_path()),
		private.as_path(),
		Some(&password),
	);

	let result = cred.unwrap();
	println!("{:?}", _cred_type);

	return Ok(result);
}

But it hangs. Prints a bunch of the cred_type, then fails saying could not get response, Failed to retrieve list of SSH authentication methods. Tried to find a solution at google, but always find people saying this auth method should work. An issue of this was quoted here, but did not solve my problem either.

It was working before, not working for some months now. Some said it is about new way to generate ssh keys of github, but already tried old way, same response.

@jinseok9338
Copy link

I know that it might be a long shot but is there a way to authenticate with personal access code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants