JGit Authentication Explained

Home  >>  Eclipse  >>  JGit Authentication Explained

JGit Authentication Explained

On December 9, 2014, Posted by , In Eclipse, By ,,, , With 13 Comments

Authentication in JGit is mostly on par with native Git. Commonly used protocols like SSH and HTTP(S) and their authentication methods are supported. This article summarizes how to use the JGit authentication API to access remote Git repositories securely.

Though the examples in this article use the CloneCommand, the described techniques can be applied to all classes that connect to remote repositories like FetchCommand, PushCommand, LsRemoteCommand, etc. All of these commands have a common base class – TransportCommand – which offers the methods discussed here.

HTTP(S) – https://example.com/repo.git

Authenticating via HTTP and HTTPS is straightforward. An implementation of CredentialsProvider is used to return the authentication credentials when the command requests them. The CredentialsProvider to be used for a certain command is specified through setCredentialsProvider().

For example, the code below clones a repository over HTTPS and authenticates with username and password.

CloneCommand cloneCommand = Git.cloneRepository();
cloneCommand.setURI( "https://example.com/repo.git" );
cloneCommand.setCredentialsProvider( new UsernamePasswordCredentialsProvider( "user", "password" ) );

The UsernamePasswordCredentialsProvider is an implementation of CredentialsProvider that comes with JGit and uses the given username and password to authenticate.

Alternatively, JGit (version 3.5 and later) can also read credentials from the user’s .netrc file. The NetRCCredentialsProvider uses the first machine entry from the file for authentication.

Though it is not recommendable to send credentials over unsecured connections, the described approach also works for plain HTTP connections like http://example.com/repo.git.


As of now, the CloneCommand does not consider the http.sslVerify configuration setting when connecting via https. SSL certificates and host names will always be verified.

This prevents JGit from being able to clone from servers that use self-signed certificates out of the box. See this SO post for how to work around this limitation.

SSH with Public Key – ssh://user@example.com/repo.git

JGit delegates creating and destroying SSH connections to the abstract SshSessionFactory. To use public key authentication for an SSH connection, such a session factory has to be specified for the executed command.

With setTransportConfigCallback(), a TransportConfigCallback interface can be specified to intercept the connection process. Its sole method – named configure() – is called just before a connection is established. It is passed a parameter of type Transport which will be used to copy objects between the local and the remote repository. For each protocol, there is a distinct subclass of Transport that handles the respective details of that protocol.

Like shown below the callback can be used to configure the Transport instance right before it is put into use:

SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
  @Override
  protected void configure( Host host, Session session ) {
    // do nothing
  }
};
CloneCommand cloneCommand = Git.cloneRepository();
cloneCommand.setURI( "ssh://user@example.com/repo.git" );
cloneCommand.setTransportConfigCallback( new TransportConfigCallback() {
  @Override
  public void configure( Transport transport ) {
    SshTransport sshTransport = ( SshTransport )transport;
    sshTransport.setSshSessionFactory( sshSessionFactory );
  }
} );

JGit provides an abstract JSchConfigSessionFactory that uses JSch to establish SSH connections and requires its configure() to be overridden. Because in the simplest case there isn’t anything to be configured, the example above just overrides the method to let the code compile.

JSchConfigSessionFactory is mostly compatible with OpenSSH, the SSH implementation used by native Git. It loads the known hosts and private keys from their default locations (identity, id_rsa and id_dsa) in the user’s .ssh directory.

If your private key file is named differently or located elsewhere, I recommend to override createDefaultJSch(). After calling the base method, custom private keys can be added like so:

@Override
protected JSch createDefaultJSch( FS fs ) throws JSchException {
  JSch defaultJSch = super.createDefaultJSch( fs );
  defaultJSch.addIdentity( "/path/to/private_key" );
  return defaultJSch;
}

In this example a private key from a custom file location is added. If you look into the JSch JavaDoc you will find further overloaded addIdentity() methods.

For the sake of completeness, I should mention that there is also a global session factory. It can be obtained and changed through SshSessionFactory.get/setInstance() and is used as a default if no specific shSessionFactory was configured for a command. However, I recommend refraining from using it. Apart from making it harder to write isolated tests, there might be code outside of your control that changes the global session factory.

SSH with Password – ssh://user@example.com/repo.git

As with using SSH with public keys, an SshSessionFactory must be specified to use password-secured SSH connections. But this time, the session factory’s configure() method has a purpose.

SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
  @Override
  protected void configure( Host host, Session session ) {
    session.setPassword( "password" );
  }
} );

CloneCommand cloneCommand = Git.cloneRepository();
cloneCommand.setURI( "ssh://user@example.com/repo.git" );
cloneCommand.setTransportConfigCallback( new TransportConfigCallback() {
  @Override
  public void configure( Transport transport ) {
    SshTransport sshTransport = ( SshTransport )transport;
    sshTransport.setSshSessionFactory( sshSessionFactory );
  }
} );

A JSch session represents a connection to an SSH server and in line 4, the password for the current session is set. The rest of the code is the same that was used to connect via SSH with public key authentication.

Which Authentication Method to Use?

Some authentication methods discussed here can also be combined. For example, setting a credentials provider while attempting to connect to a remote repository via SSH with public-key won’t harm. However, you usually want to know what Transport will be used for a given repository-URL beforehand.

To determine that, use the TransportProtocol’s canHandle() method. It returns true if the protocol can handle the given URL and false otherwise. A list of all registered TransportProtocols can be obtained from Transport.getTransportProtocols(). And once the protocol is known, the appropriate authentication method can be chosen.

Authentication @ GitHub

GitHub supports a variety of protocols and authentications methods, but certainly not all possible combinations. A common mistake, for example, is to try to use SSH with password authentication. But this combination is not supported – only SSH with public keys is.

This comparison of protocols offered by GitHub lists what is supported and what not. Summarized, there is:

  • Plain Git (e.g. git://github.com/user/repo.git): The transfer is unencrypted and the server is not verified.
  • HTTPS (e.g. https://github.com/user/repo.git): Works practically everywhere. Uses password authentication for pushing but allows anonymous fetch and clone.
  • SSH (e.g. ssh://git@github.com:user/repo.git): Uses public key authentication, also for fetch and clone.

Please note one thing if you are accessing a GitHub repository through HTTPS with an OAuth access token. The token does not need to be specified in the URL but only given as a user name. The example below illustrates this:

command.setURI( "https://github.com/user/repo.git" );
command.setCredentialsProvider( new UsernamePasswordCredentialsProvider( "token", "" ) );

Authentication @ GitLab

GitLab offers slightly different authentication methods.

Of course, SSH is also among them (e.g. git@gitlab.com:user/repo.git). It uses public key authentication and, like at GitHub, it can be used to fetch and push.

HTTPS with username and password (e.g. https://gitlab.com/user/repo.git) is also supported. It uses password authentication for pushing but allows anonymous fetch and clone. The username and password need to be passed through a UsernamePasswordCredentialsProvider like this:

command.setCredentialsProvider( new UsernamePasswordCredentialsProvider( "username", "password" ) );

In addition, the GitLab Profile Settings allow to create Personal Access Tokens. These can also be used to authenticate HTTPS connections. Access tokens can have an expiration date or can be revoked manually at any time.

In order to use an access token, it must be encoded into the URL and given as a password as shown below:

command.setURI( "https://gitlab-ci-token:a1b2..x7z@gitlab.com/user/repo.git" );
command.setCredentialsProvider( new UsernamePasswordCredentialsProvider( "username", "a1b2..x7z" ) );

Concluding JGit Authentication

While I find the authentication facilities are a bit widely scattered over the JGit API, they get the task done. The recipes given here hopefully provide you with the necessary basics to authenticate connections in JGit and to hide the complexities of the API could be seen as an exercise to practice clean code 😉

In order to help with setting up the development environment, you may want to also read An Introduction to the JGit Sources. If you have difficulties or further questions, please leave a comment or ask the friendly and helpful JGit community for assistance.

Follow me

Rüdiger Herrmann

Routined programmer, team lead, presenter, blog writer, and convinced open source contributor with two decades experience in the field.

Strong focus on quality backed up by agile methods like test driven development, modularization, pair programming, clean code, continuous integration.

Specialized in Java with JEE, REST, OSGi, RCP, RAP and building developer tools based on the Eclipse IDE (or any other platform if an opportunity arises).
Follow me

Latest posts by Rüdiger Herrmann (see all)

13 Comments so far:

  1. Saurav Tapader says:

    SshTransport sshTransport = ( SshTransport )transport;

    how does this downcast work? Technically i should get a ClassCastException.

    And confirmed I do get one at runtime.

    • Rüdiger Herrmann says:

      You probably didn’t specify an ssh URL. The actual Transport subclass that is passed to TransportConfigCallback#configure() depends on the URL. In the example given in the post, the cast succeeds because an ssh URL (ssh://user@example.com/repo.git) was specified that results in an instance of SshTransport being passed.

      A more general TransportConfigCallback implementation would of course have to check the transport argument if it matches the expected type.

  2. Saurav Tapader says:

    Indeed, my remote url was https. And thus it was generating an instance of TransportHttp resulting in the ClassCastException.

    Overriding the remote to ssh solved the prob.

  3. Martijn says:

    The explanation on how to use an OAuth token with jGit was very useful, thanks for explaning!

  4. Houssem says:

    thanks for your tutorial, but i have always an Auth fail ..
    i posted a question on stackoverflow :
    http://stackoverflow.com/questions/33410092/using-ssh-authentication-with-jgit-to-access-a-git-repository-securely-auth-fa

    can u take a look please ? thanks

  5. Dapper says:

    Dear

    Could you explain me, how to input detph parameters in CloneCommand?

  6. Vijay says:

    Dear All,

    I want to clone/pull/checkout remote project to my local in java.

    And I want to checkout a particular tag at my local machine.

    Below are the codes I am using

    try {
    SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
    @Override
    protected void configure(Host arg0, Session arg1) {
    // TODO Auto-generated method stub
    }
    @Override
    protected JSch createDefaultJSch(FS fs) throws JSchException {
    // TODO Auto-generated method stub
    return super.createDefaultJSch(fs);
    }
    };

    CloneCommand cloneCommand = Git.cloneRepository();
    cloneCommand.setURI( “ssh://XXX.git” );
    cloneCommand.setTransportConfigCallback( new TransportConfigCallback() {
    @Override
    public void configure( Transport transport ) {
    SshTransport sshTransport = ( SshTransport )transport;
    sshTransport.setSshSessionFactory( sshSessionFactory );
    }

    } );

    cloneCommand.setDirectory(new File(“C:/XXX/TempProject”));
    cloneCommand.call();

    } catch (GitAPIException e) {
    e.printStackTrace();
    }
    Please help!

    • Rüdiger Herrmann says:

      Please note that we aren’t able to maintain a please-solve-my-problem form here. You may want to post a question on StackOverflow that includes what the expected outcome is, what you’ve tried so far, and what the actual outcome is.

      • Vijay says:

        Thanks for your reply Rudiger.

        I am using URI : ssh://XXX.git

        Caused by: com.jcraft.jsch.JSchException: Auth fail
        at com.jcraft.jsch.Session.connect(Session.java:512)
        at org.eclipse.jgit.transport.JschConfigSessionFactory.getSession(JschConfigSessionFactory.java:117)
        … 10 more

        Could you please tell me how to fix it?

        • Rüdiger Herrmann says:

          I am afraid, no. With the few information, that you gave I am unable to tell what is going on.

          And again, this is no Q&A forum. Use StackOverflow for such questions.

  7. velly says:

    How to disable sslVerify? when clone

Leave a Reply

Your email address will not be published. Required fields are marked *