Using Keys with JGit to Access a Git Repository Se

2019-01-17 08:40发布

问题:

I'm using JGit to access a remote Git repo, and I need to use SSH for it. JGit uses JSch to provide secure access. However, I'm not sure how to set the key file and the knows hosts file for JGit. What I have tried is as follows.

Created a custom configuration of the SshSessionFactory, using by subclassing JSchConfigSessionFactory:

public class CustomJschConfigSessionFactory extends JschConfigSessionFactory {
    @Override
    protected void configure(OpenSshConfig.Host host, Session session) {
        session.setConfig("StrictHostKeyChecking", "yes");
    }
}

In the class which I access the remote Git repo, did the following:

CustomJschConfigSessionFactory jschConfigSessionFactory = new CustomJschConfigSessionFactory();

JSch jsch = new JSch();
try {
    jsch.addIdentity(".ssh/id_rsa");
    jsch.setKnownHosts(".ssh/known_hosts");
} catch (JSchException e) {
    e.printStackTrace();  
}
    SshSessionFactory.setInstance(jschConfigSessionFactory);

I can't figure out how to associate this JSch object with JGit so that it can successfully connect to the remote repository. When I try to clone it with JGit, I get the following exception:

org.eclipse.jgit.api.errors.TransportException: git@git.test.com:abc.org/test_repo.git: reject HostKey: git.test.com
at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:137)
at org.eclipse.jgit.api.CloneCommand.fetch(CloneCommand.java:178)
at org.eclipse.jgit.api.CloneCommand.call(CloneCommand.java:125)
at GitTest.cloneRepo(GitTest.java:109)
at GitTest.main(GitTest.java:223)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.eclipse.jgit.errors.TransportException: git@git.test.com:abc.org/test_repo.git: reject HostKey: git.test.com
at org.eclipse.jgit.transport.JschConfigSessionFactory.getSession(JschConfigSessionFactory.java:142)
at org.eclipse.jgit.transport.SshTransport.getSession(SshTransport.java:121)
at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:248)
at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:147)
at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:136)
at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:122)
at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1104)
at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:128)
... 9 more
Caused by: com.jcraft.jsch.JSchException: reject HostKey: git.test.com
at com.jcraft.jsch.Session.checkHost(Session.java:748)
at com.jcraft.jsch.Session.connect(Session.java:321)
at org.eclipse.jgit.transport.JschConfigSessionFactory.getSession(JschConfigSessionFactory.java:116)
... 16 more

I have added the git.test.com entry to my /etc/hosts file. I have used the same code to access a git repo with a http url, so the code it working fine. It's the key handling part that is failing. Any idea on how to handle this?

回答1:

You need to override the getJSch method in your custom factory class:

class CustomConfigSessionFactory extends JschConfigSessionFactory
{
    @Override
    protected JSch getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
        JSch jsch = super.getJSch(hc, fs);
        jsch.removeAllIdentity();
        jsch.addIdentity( "/path/to/private/key" );
        return jsch;
    }
}

Calling jsch.removeAllIdentity is important; it doesn't seem to work without it.

A caveat: I wrote the above in Scala, and then translated it over to Java, so it might not be quite right. The original Scala is as follows:

class CustomConfigSessionFactory extends JschConfigSessionFactory
{
    override protected def getJSch( hc : OpenSshConfig.Host, fs : FS ) : JSch =
    {
        val jsch = super.getJSch(hc, fs)
        jsch.removeAllIdentity()
        jsch.addIdentity( "/path/to/private/key" )
        jsch
    }
}


回答2:

Jsch sesems to not like a known_hosts file in the hashed format-- it must conform to the format produced by:

ssh-keyscan -t rsa hostname >> ~/.ssh/known_hosts

e.g.

<hostname> ssh-rsa <longstring/longstring>

not:

 |1|<hashed hostname>= ecdsa-sha2-nistp256 <hashed fingerprint>=


回答3:

Managed to find the issue. The public key in the server side had a different name other than the usual id_rsa.pub, while the private key on my side was id_rsa. JSch expects by default the public key to have the same name as the private key plus the .pub suffix. Using a key pair with a common name (ex.: private = key_1 and public = key_1.pub) solves the issue.