JGit clone repository - repository

I'm trying to clone Git repository with JGit and I have problem with UnsupportedCredentialItem.
My code:
FileRepositoryBuilder builder = new FileRepositoryBuilder();
Repository repository = builder.setGitDir(PATH).readEnvironment().findGitDir().build();
Git git = new Git(repository);
CloneCommand clone = git.cloneRepository();
clone.setBare(false);
clone.setCloneAllBranches(true);
clone.setDirectory(PATH).setURI(url);
UsernamePasswordCredentialsProvider user = new UsernamePasswordCredentialsProvider(login, password);
clone.setCredentialsProvider(user);
clone.call();
It will occur Exception:
org.eclipse.jgit.errors.UnsupportedCredentialItem: ssh://git#github.com:22: Passphrase for C:\Users\Marek\.ssh\id_rsa at
org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider.get(UsernamePasswordCredentialsProvider.java:110)....
But if I delete file known_hosts in .ssh\ It will occur different Exception
org.eclipse.jgit.errors.UnsupportedCredentialItem: ssh://git#github.com:22: The authenticity of host 'github.com' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting?
at org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider.get(UsernamePasswordCredentialsProvider.java:110)....
Is there any possibility to type "yes" to that question or just skip it?
Thank you!

I think if you login with username and password, you need https. For ssh you will need a public key that matches the one on record with github.

This will do it (like #michals, only less code) if using username / password with ssh
public void gitClone() throws GitAPIException {
final File localPath = new File("./TestRepo");
Git.cloneRepository()
.setURI(REMOTE_URL)
.setDirectory(localPath)
.setCredentialsProvider(new UsernamePasswordCredentialsProvider("***", "***"))
.call();
}

I suppose you would want to check the github help:
http://help.github.com/win-set-up-git/
Especially the part about generating ssh keys (ssh-keygen -t rsa -C "your_email#youremail.com"). Read the article for your environment, and you'll understand how to get a better configuration.

I had the same problem. The reason was passphrase set for rsa private key. When I remove passphrase for this key it started work without any CredentialsProvider.
UsernamePasswordCredentialsProvider probably don't support passphrase. If you would like to have passphrase set, you could define you own CredentialProvider, which will support it, for example:
CloneCommand clone = Git.cloneRepository()
.setURI("...")
.setCredentialsProvider(new CredentialsProvider() {
#Override
public boolean supports(CredentialItem... items) {
return true;
}
#Override
public boolean isInteractive() {
return true;
}
#Override
public boolean get(URIish uri, CredentialItem... items)
throws UnsupportedCredentialItem {
for (CredentialItem item : items) {
if (item instanceof CredentialItem.StringType) {
((CredentialItem.StringType) item).
setValue(new String("YOUR_PASSPHRASE"));
continue;
}
}
return true;
}
});
clone.call();
It works for me ;)

I had a similar issue, though my setup was a bit different. Leaving this here in case anyone else encounters something similar. I had overridden my configure method and createDefaultJSch method according to this tutorial: https://www.codeaffine.com/2014/12/09/jgit-authentication/
I had something like:
#Override
public void configure( Transport transport ) {
SshTransport sshTransport = ( SshTransport )transport;
sshTransport.setSshSessionFactory( sshSessionFactory );
}
#Override
protected JSch createDefaultJSch( FS fs ) throws JSchException {
JSch defaultJSch = super.createDefaultJSch( fs );
defaultJSch.addIdentity( "/path/to/private_key" );
return defaultJSch;
}
I ended up changing my createdDefaultJSch method to getSch (adding the appropriate parameters) and adding removeAllIdentity():
#Override
public 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
}
No idea why this worked, but I found the getSch thing from this answer (coincidentally by the same guy who wrote the tutorial): Using Keys with JGit to Access a Git Repository Securely

It is not clear to me whether you want to do username/password authentication or public/private key authentication. Either way, CredentialsProvider will not be used, according to this. You need to configure the transport. First, create a transport configuration callback:
SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
#Override
protected void configure( Host host, Session session ) {
// If you are using username/password authentication, add the following line
session.setPassword( "password" );
}
} );
TransportConfigCallback transportConfigCallback = new TransportConfigCallback() {
#Override
public void configure( Transport transport ) {
SshTransport sshTransport = ( SshTransport )transport;
sshTransport.setSshSessionFactory( sshSessionFactory );
}
};
Then configure the command with it:
clone.setTransportConfigCallback( transportConfigCallback );

If the repository is private and needs authentication, you(#Scruger) will do it using username/password with ssh for clone repository.
private UsernamePasswordCredentialsProvider configAuthentication(String user, String password) {
return new UsernamePasswordCredentialsProvider(user, password );
}
public void clonneRepositoryWithAuthentication(String link, String directory,String branch,String user, String password){
System.out.println("cloning repository private from bitcketebuk");
try {
Git.cloneRepository()//function responsible to clone repository
.setURI(link)// set link to repository git
.setDirectory(new File(Constants.PATH_DEFAULT + directory))//Defined the path local the cloning
.setCredentialsProvider(configAuthentication(user, password))
.setCloneAllBranches(true)//Defined clone all branch exists on repository
.call();//execute call the clone repository git
System.out.println("Cloning sucess.....");
} catch (GitAPIException e) {
System.err.println("Error Cloning repository " + link + " : "+ e.getMessage());
}
}

Related

Problem using git token with jgit sshFactory (JschConfigSessionFactory)

I have the following code running with JGIT and when I set the repo to the origin to HTTPS protocol I'm able to fetch using JGIT with no issues. However, when I change the repo's origin to an SSH protocol I get an AUTH failed error. I've looked through stack overflow and the JGIT documentation and am wondering if someone can take a look at this code and advise on how to use a git token to auth through SSH. is this even possible? Thanks
FetchResult result = git.fetch().setTransportConfigCallback(transport -> {
if (transport instanceof SshTransport) {
SshTransport sshTransport = (SshTransport) transport;
SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
#Override
protected void configure(OpenSshConfig.Host host, Session session) {
session.setPassword("<TOKEN>");
session.setConfig("StrictHostKeyChecking", "no");
}
#Override
protected JSch getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
JSch jsch = super.getJSch(hc, fs);
jsch.removeAllIdentity();
return jsch;
}
};
sshTransport.setSshSessionFactory(sshSessionFactory);
} else if (transport instanceof HttpTransport) {
HttpTransport httpTransport = (HttpTransport) transport;
httpTransport.setCredentialsProvider(new UsernamePasswordCredentialsProvider("<SERVICE_NAME", "<TOKEN>"));
}
}).setCheckFetchedObjects(true).call();
}

Public Key Authentication using j2ssh-maverick-1.5.5.jar

Below is a code snippet for connecting to a remote server using public key authentication. I have generated public and private keys using Putty Key Gen tool and have modified the authorized_keys file in .ssh folder as required. I am able to connect to remote server using Putty and providing the prompted passphrase. I am however not able to connect via the below code. It shows me -
java.io.IOException: The PuTTY key could not be read! Invalid encryption key
Any thoughts around this ?
SocketTransport transport = new SocketTransport(hostname, port);
ssh = con.connect(transport, username);
FileInputStream in;
ByteArrayOutputStream out;
try
{
in = new FileInputStream("E:\\Projects\\RBL\\Finacle Interface\\Finacle\\AuthenticationKeys\\RBLTestPrivateKey.ppk");
out = new ByteArrayOutputStream();
int read;
while((read = in.read()) > -1)
out.write(read);
in.close();
SshPrivateKeyFile pkf = SshPrivateKeyFileFactory.parse(out.toByteArray());
SshKeyPair pair = pkf.toKeyPair("calypso");
PublicKeyAuthentication pk = new PublicKeyAuthentication();
pk.setPrivateKey(pair.getPrivateKey());
pk.setPublicKey(pair.getPublicKey());
if(ssh.authenticate(pk)==SshAuthentication.COMPLETE)
{
Log.info(LOG_CATEGORY, "Authentication completed");
session = ssh.openSessionChannel();
return session;
}
}
catch (IOException | InvalidPassphraseException | SshException e1)
{
e1.printStackTrace();
}
/*PasswordAuthentication pwd = new PasswordAuthentication();
pwd.setPassword(this.password);
if(ssh.authenticate(pwd)==SshAuthentication.COMPLETE)
{
session = ssh.openSessionChannel();
return session;
}*/
}
catch(Exception e)
{
isConnected = false;
e.printStackTrace();
}
If you change your keypair to OpenSSH key(s), it could be work...
SshPrivateKeyFile pkf = SshPrivateKeyFileFactory.parse(new FileInputStream("E:\\Projects\\RBL\\Finacle Interface\\Finacle\\AuthenticationKeys\\TestRBL"));
SshKeyPair pair = pkf.toKeyPair("calypso");
solved my issue

How can I get username and name of active local changes from git project in IntelliJ plugin

I would like to create a plugin that would use a username and name of active local changes in git project. Can I get this information from action or context?
I found a solution.
For git username:
private static String getGitUsername() {
try {
Process process = Runtime.getRuntime().exec("git config user.name");
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
return reader.readLine();
} catch (Exception e) {
return DEFAULT_USER;
}
}
For name of active local changes:
private static String getChangeListName(Project project) {
return ChangeListManager.getInstance(project).getDefaultListName();
}

Netty: How to implement a telnet client handler which needs authentication

This is my first time ask question through this platform. I am sorry. I am not good in English. I will try my best to let you understand my questions.
I am totally beginner in Netty. I would like to implement a program to send commands to a telnet server and receive response message. I modified the sample telnet program to connect and get response from the serve when there is no authentication of serve.
The question is that
When the authentication processes are setup in server. (Require login name and password)
How to implement the client side program?
How can I receive the serve login request and response it?
Should I implement another handler to handle the authentication?
below shows how i send the commands to the server
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new TelnetClientInitializer(sslCtx));
// Start the connection attempt.
ChannelFuture lastWriteFuture = null;
lastWriteFuture = b.connect(HOST, PORT).sync();
Channel ch = lastWriteFuture.channel();
lastWriteFuture = ch.writeAndFlush("ls" + "\r\n", ch.newPromise());
lastWriteFuture = ch.writeAndFlush("status" + "\r\n");
lastWriteFuture = ch.writeAndFlush("ls" + "\r\n");
lastWriteFuture = ch.writeAndFlush("exit" + "\r\n");
// Wait until the connection is closed.
lastWriteFuture.channel().closeFuture().sync();
} finally {
// Shut down the event loop to terminate all threads.
group.shutdownGracefully();
}
but what should i do before send the above commands to login into the serve?
The following picture shows what i want to do in the program
Thank you very much!!!
If we talk about TELNET as a protocol you should know that Telnet client from Netty examples does not support TELNET protocol. His name is just confusing and you can't connect to any standard telnet servers. You can read more about TELNET protocol here - THE TELNET PROTOCOL .
I see 2 ways:
write your implementation for TELNET on Netty
use another implementation for examples Apache Commons Net
Example for the first way - modified netty client, i tested him on Linux servers. He has several dirty hacks like a timer but he works.
Example for the second - Java – Writing An Automated Telnet Client:
import org.apache.commons.net.telnet.*;
import java.io.InputStream;
import java.io.PrintStream;
public class AutomatedTelnetClient {
private TelnetClient telnet = new TelnetClient();
private InputStream in;
private PrintStream out;
private String prompt = "~>";
public AutomatedTelnetClient(String server) {
try {
// Connect to the specified server
telnet.connect(server, 8023);
TerminalTypeOptionHandler ttopt = new TerminalTypeOptionHandler("VT100", false, false, true, false);
EchoOptionHandler echoopt = new EchoOptionHandler(true, false, true, false);
SuppressGAOptionHandler gaopt = new SuppressGAOptionHandler(true, true, true, true);
try {
telnet.addOptionHandler(ttopt);
telnet.addOptionHandler(echoopt);
telnet.addOptionHandler(gaopt);
} catch (InvalidTelnetOptionException e) {
System.err.println("Error registering option handlers: " + e.getMessage());
}
// Get input and output stream references
in = telnet.getInputStream();
out = new PrintStream(telnet.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
// public void su(String password) {
// try {
// write(“su”);
// readUntil(“Password: “);
// write(password);
// prompt = “#”;
// readUntil(prompt + ” “);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
public String readUntil(String pattern) {
try {
char lastChar = pattern.charAt(pattern.length() - 1);
StringBuffer sb = new StringBuffer();
boolean found = false;
char ch = (char) in.read();
while (true) {
System.out.print(ch);
sb.append(ch);
if (ch == lastChar) {
if (sb.toString().endsWith(pattern)) {
return sb.toString();
}
}
ch = (char) in.read();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void write(String value) {
try {
out.println(value);
out.flush();
System.out.println(value);
} catch (Exception e) {
e.printStackTrace();
}
}
public String sendCommand(String command) {
try {
write(command);
return readUntil(prompt + " ");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void disconnect() {
try {
telnet.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String user = "test";
String password = "test";
AutomatedTelnetClient telnet = new AutomatedTelnetClient("localhost");
// Log the user on
telnet.readUntil("login:");
telnet.write(user);
telnet.readUntil("Password:");
telnet.write(password);
// Advance to a prompt
telnet.readUntil(telnet.prompt + " ");
telnet.sendCommand("ps -ef");
telnet.sendCommand("ls");
telnet.sendCommand("w");
telnet.disconnect();
}
}
Telnet has no real concept of a password packet, a password prompt is just like any normal text output. This means that you can just send the username and password when connection as separate lines, and the telnet server will use them correctly.
ch.writeAndFlush("administrator" + "\r\n");
ch.writeAndFlush("LetMeIn4!!" + "\r\n");
If you require connecting to server that don't always require the password, then you should read the output from the server, check if it contains "username", send the username, then keep reading if it contains "password" and send the password. This is prone to breaking as servers are not required to send those strings, and legit output may also contain those. This is the downside of the telnet protocol.
I hope this my article is helpful to someone.
Netty | Implement Telnet Automated Authentication
I had to use Telnet to control the sub-equipment while developing the space ground station software. Except for the authentication, Telnet is quite similar to regular TCP server communication. So, I implemented a Handler that automatically handles Telnet authentication to communicate with the Telnet server. When connecting to the Telnet server, the following introductory message, “Username: “, “Passwrod: “ messages are displayed in sequence, and user authentication is requested. Handler automatically handles the authentication process as if a human would input account information. Below is a brief description of the implementation.
c:\> telnet 192.168.0.1 12345
Power On Self Test (POST) Passed.
Integrated Control Unit (ICU) Build xxx (Build:xxxxxx) - Feb 7 2022, 17:57:16 (Network/TCP)
Date and Time: 2022-02-16 20:01:19 (GMT)
MAC Address : [00:xx:xx:xx:C6:8F]
Username: User
Password: 1234
>
Handler
TelnetAuthenticator Handler simply works as follows.
If the message contains the string “Username: “, send the username.
If the message contains the string “Password: “, the password is sent.
If the message contains the string “>” waiting for input, delete the authentication handler from the Pipeline. After authentication, TelnetAuthenticator Handler is unnecessary.
If the account is not registered on the Telnet server or the password does not match, the string “Username: “ or “Password: “ is repeatedly received. The authentication failure error is unrecoverable, notifying the user of a failed authentication process and forcing them to disconnect.
#Slf4j
#RequiredArgsConstructor
public class TelnetAuthenticator extends SimpleChannelInboundHandler<String> {
private final ChannelSpec channelSpec;
private boolean alreadyUserTried = false;
private boolean alreadyPasswordTried = false;
#Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
// If the message contains the string “Username: “, send the username.
if (msg.contains(channelSpec.getReqUserTag())) {
if (alreadyUserTried) {
processFail(ctx);
}
ctx.channel().writeAndFlush(channelSpec.getAccount().getUser() + channelSpec.getEndLine());
alreadyUserTried = true;
return;
}
// If the message contains the string “Password: “, the password is sent.
if (msg.contains(channelSpec.getReqPasswordTag())) {
if (alreadyPasswordTried) {
processFail(ctx);
}
ctx.channel().writeAndFlush(channelSpec.getAccount().getPassword() + channelSpec.getEndLine());
alreadyPasswordTried = true;
return;
}
// If the incoming message contains an input waiting message, the Pipeline deletes the current handler.
if (msg.contains(channelSpec.getStandByTag())) {
ctx.pipeline().remove(this.getClass());
}
}
private void processFail(ChannelHandlerContext ctx) {
ctx.fireUserEventTriggered(ErrorMessage.AUTHENTICATE_FAIL);
ctx.close();
}
}
Initialize ChannelPipeline
A ChannelPipeline configuration with a TelnetAuthenticator Handler can be: First, register InboundHandlers as follows.
First, add DelimiterBasedFrameDecoder with “Username: “, “Password: “, “>” strings as delimiters. The stripDelimiter option is set to false because all delimiters must be received to recognize the authentication process.
Add StringDecoder.
Add the implemented TelnetAuthenticator Handler.
Add other necessary business logic.
Simply add StringEncoder to Outbound. You can add other Handlers as needed.
public class PipelineInitializer extends ChannelInitializer<SocketChannel> {
private ChannelSpec channelSpec;
public void init(ChannelSpec channelSpec) {
this.channelSpec = channelSpec;
}
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
// Inbound
.addLast(new DelimiterBasedFrameDecoder(1024, false,
channelSpec.getDelimiter().reqUserTag(),
channelSpec.getDelimiter().reqPasswordTag(),
channelSpec.getDelimiter().standByTag()))
.addLast(new StringDecoder())
.addLast(new TelnetAuthenticator(channelSpec))
.addLast(new BusinessLogic())
// Outbound
.addLast(new StringEncoder());
}
}
ChannelSpec
ChannelSpec defines specifications required for communication with Telnet server. Manage server IP, port, account information, separator, etc.
#Getter
public class ChannelSpec {
private final String serverIp = "192.168.0.1";
private final int serverPort = 12345;
private final String endLine = "\r\n";
private final String standByTag = ">";
private final String reqUserTag = "Username: ";
private final String reqPasswordTag = "Password: ";
private final Account account = new Account("User", "1234");
private final Delimiter delimiter = new Delimiter();
public class Delimiter {
public ByteBuf standByTag() {
return toByteBuf(standByTag);
}
public ByteBuf reqUserTag() {
return toByteBuf(reqUserTag);
}
public ByteBuf reqPasswordTag() {
return toByteBuf(reqPasswordTag);
}
private ByteBuf toByteBuf(String input) {
ByteBuf delimiterBuf = Unpooled.buffer();
delimiterBuf.writeCharSequence(input, StandardCharsets.UTF_8);
return delimiterBuf;
}
}
}
#RequiredArgsConstructor
#Getter
public class Account {
private final String user;
private final String password;
}

com.jcraft.jsch.JSchException: Auth fail error

Trying to connect to a host using ssh key auth. Below is my code:
package com.mkyong.common;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
/**
*
*/
public class UserAuthPubKey {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
JSch jsch = new JSch();
String user = "XXXXXXXX";
String host = "XXXXXXXX.XXXXXXX.com";
int port = 22;
String privateKey = "~/.ssh/WF_OPENSSH.ppk";
String passphrase = "XXXXXXXXXXX";
jsch.addIdentity(privateKey,passphrase);
System.out.println("identity added ");
Session session = jsch.getSession(user, host, port);
System.out.println("session created.");
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
System.out.println("session connected.....");
Channel channel = session.openChannel("sftp");
channel.setInputStream(System.in);
channel.setOutputStream(System.out);
channel.connect();
System.out.println("shell channel connected....");
ChannelSftp c = (ChannelSftp) channel;
// String fileName = "test.txt";
// c.put(fileName, "./in/");
// c.exit();
// System.out.println("done");
} catch (Exception e) {
System.err.println(e);
}
}
}
what change should i make here. On debugging the error seems to occur at session.connect(); statement. I am using a private key and a passphrase to connect.
String privateKey = "~/.ssh/WF_OPENSSH.ppk";
Is that a PuTTY-format keyfile? Was it generated from puttygen, the PuTTY key generation utility? Jsch only reads OpenSSH-format key files, not PuTTY-format files.
You can use puttygen to convert the key to OpenSSH format if you want to use that key. See this question.
Get the lastest version of JSch. The old version shows Auth Fail for no reason