使用带有 JGit 的密钥安全地访问 Git 存储库

Posted

技术标签:

【中文标题】使用带有 JGit 的密钥安全地访问 Git 存储库【英文标题】:Using Keys with JGit to Access a Git Repository Securely 【发布时间】:2012-11-21 02:51:27 【问题描述】:

我正在使用JGit 访问远程Git 存储库,我需要为此使用SSH。 JGit 使用JSch 提供安全访问。但是,我不确定如何为 JGit 设置密钥文件和知道主机文件。我尝试过的如下。

创建了SshSessionFactory 的自定义配置,通过子类化JSchConfigSessionFactory 使用:

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

在我访问远程 Git 存储库的课程中,执行了以下操作:

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);

我不知道如何将此 JSch 对象与 JGit 相关联,以便它可以成功连接到远程存储库。当我尝试使用 JGit 克隆它时,出现以下异常:

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

我已将 git.test.com 条目添加到我的 /etc/hosts 文件中。我使用相同的代码通过 http url 访问 git repo,因此代码运行良好。这是失败的关键处理部分。关于如何处理这个问题的任何想法?

【问题讨论】:

我看到你创建了一个 jsch 对象,但你还没有将它分配给任何东西。为什么要创建它? 【参考方案1】:

您需要在自定义工厂类中覆盖getJSch 方法:

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;
    

致电jsch.removeAllIdentity 很重要;没有它似乎无法工作。

一个警告:我用 Scala 编写了上面的代码,然后将它翻译成 Java,所以它可能不太正确。原来的Scala如下:

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
    

【讨论】:

我的问题是我需要能够指定私钥的密码,您可以将其作为另一个参数添加到 addIdentity 或创建自己的实现 UserInfo 的类和然后将session 参数设置为CustomConfigSessionFactoryconfigure 方法以使用该UserInfo 特别感谢jsch.removeAllIdentity() 的提示!【参考方案2】:

Jsch 不喜欢采用 hashed 格式的 known_hosts 文件——它必须符合以下生成的格式:

ssh-keyscan -t rsa hostname &gt;&gt; ~/.ssh/known_hosts

例如

<hostname> ssh-rsa <longstring/longstring>

不是:

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

【讨论】:

【参考方案3】:

设法找到问题。服务器端的公钥与通常的 id_rsa.pub 名称不同,而我这边的私钥是 id_rsa。默认情况下,JSch 期望公钥与私钥同名并加上 .pub 后缀。使用具有通用名称的密钥对(例如:private = key_1 和 public = key_1.pub)可以解决此问题。

【讨论】:

以上是关于使用带有 JGit 的密钥安全地访问 Git 存储库的主要内容,如果未能解决你的问题,请参考以下文章

如何安全地存储和使用客户的 AWS 密钥

使用 JGit 从 Git 存储库中查看特定修订

如何安全地存储加密密钥?

如何使用 jgit 查找所有提交,而不仅仅是可引用的提交

使用 JGit 授权错误推送到 GitLab

使用PHP / MySQLI / Apache时,在哪里安全地存储证书/密钥?