I can't connect to a SSH host using the Gradle SSH Plugin with my private key.
Specifying the password in the build.gradle works fine:
remotes {
webServer {
host = '<IP>'
user = '<USER>'
password = '<PASSWORD>'
}
}
But to avoid writing my password in the build file, I've set my environment to connect using my private key without entering the password from shell:
ssh <user>#<ip>
This command works from the shell but I can't achieve this with the Gradle plugin. This is my configuration:
remotes {
webServer {
host = '<IP>'
user = '<USER>'
identity = file("${System.getProperty('user.home')}/.ssh/id_rsa")
}
}
The error is:
Caused by: com.jcraft.jsch.JSchException: USERAUTH fail at com.jcraft.jsch.UserAuthPublicKey.start(UserAuthPublicKey.java:119)
Since I'm able to connect from the shell, what's wrong with my configuration?
I fixed this by adding the agent = true property:
remotes {
webServer {
host = '54.233.77.171'
user = 'denis'
agent = true
identity = file("${System.getProperty('user.home')}/.ssh/id_rsa")
}
}
agent - If this is set, Putty Agent or ssh-agent will be used on
authentication
For more information: Connections settings
I tried this property after analyzing the class UserAuthPublicKey:
if(userinfo==null) throw new JSchException("USERAUTH fail");
I think JCraft only supports PEM keys - when generating the keys, you need to specify the format:
ssh-keygen -t rsa -m PEM
Related
I am new to Terraform , OCI .
So I am now trying to ssh on a linux host in my OCI via cloud shell, but that host is in a private subnet. So I am trying below command but getting timeout error.
Could you please tell me where I am getting this wrong
resource "null_resource" "remote-exec" {
provisioner "remote-exec" {
connection {
agent =false
timeout = "5m"
host ="xx.xx.xx.x" --- This is in a private subnet(private ip address to connect to linux env)
user = var.host_user_name
private_key =file("${path.module}/sshkey.pem")
}
inline = [
"sleep 10",
"sudo su - oracle",
"source EBSapps.env run",
"cd /u01/",
"touch ytest.txt",
]
}
}
#Deepak .. I guess you cannot connect to instance in private subnet using private IP. You would need bastion host in this case. Before trying it from terraform, did you try it out from OCI console?. I believe you will not be able to connect to instance just by private IP. If you want complete setup in terraform, you would need to create resource for bastion-host and then you can get connect to private subnet instance via bastion host. In this case, you remote execution block will have bastion-host IP. Something similar to below
provisioner "remote-exec" {
connection {
agent =false
timeout = "5m"
host ="xx.xx.xx.x" --- This should be bastion host IP
user = var.host_user_name
private_key =file("${path.module}/sshkey.pem")
}
References:
https://medium.com/#harjulthakkar/connect-to-private-compute-instance-using-oci-bastion-service-ca96a3ceea49
https://registry.terraform.io/providers/hashicorp/oci/latest/docs/resources/bastion_bastion
I can establish a port forwarding session in Ubuntu as follows:
ssh -L 8000:dev.mycompany.com:443 jump.mycompany.com
now I'd like to emulate this with Jsch:
public static void openTunnel() {
JSch jsch = new JSch();
String privateKey = "~/.ssh/id_rsa";
try {
jsch.addIdentity(privateKey);
log.info("Connecting to {}#{}", getJumpUser(), getJumpServer());
Session session = jsch.getSession(getJumpUser(), getJumpServer(), 22);
session.connect();
session.setPortForwardingL(8000, getHost(), 433);
} catch (JSchException e) {
log.error("", e);
}
}
However I get the following exception after the tunnel is set up, and trying to connect to it with RestTemplate (Spring HTTP Client - but curl gives an error as well):
ssl.SSLHandshakeException: Remote host closed connection during handshake
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:744)
What do I have to confiugre in Jsch so that it does exactly the same as the openssh client?
I suppose, you're trying to get a connection to a https webserver that's not public available.
The port forwarding works, BUT https will not work on localhost:8000, because the certificate is for dev.mycompany.com and not localhost.
You can cheat, by adding an entry into your hosts file.
127.0.0.1 dev.mycompany.com
But probably it's easier to try socks5.
ssh jump.mycompany.com -D 8005
And then setting in your browser (sample for firefox):
Select: Manual proxy configuration:
Socks Host: localhost
Port: 8005
Socks5
I have a piece of code which connects to a Unix server and executes commands.
I have been trying with simple commands and they work fine.
I am able to login and get the output of the commands.
I need to run an Ab-initio graph through Java.
I am using the air sandbox run graph command for this.
It runs fine, when I login using SSH client and run the command. I am able to run the graph. However, when I try to run the command through Java it gives me a "air not found" error.
Is there any kind of limit on what kind of Unix commands JSch supports?
Any idea why I'm not able to run the command through my Java code?
Here's the code:
public static void connect(){
try{
JSch jsch=new JSch();
String host="*****";
String user="*****";
String config =
"Host foo\n"+
" User "+user+"\n"+
" Hostname "+host+"\n";
ConfigRepository configRepository =
com.jcraft.jsch.OpenSSHConfig.parse(config);
jsch.setConfigRepository(configRepository);
Session session=jsch.getSession("foo");
String passwd ="*****";
session.setPassword(passwd);
UserInfo ui = new MyUserInfo(){
public boolean promptYesNo(String message){
int foo = 0;
return foo==0;
}
};
session.setUserInfo(ui);
session.connect();
String command="air sandbox run <graph-path>";
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
channel.connect();
byte[] tmp=new byte[1024];
while(true){
while(in.available()>0){
int i=in.read(tmp, 0, 1024);
if(i<0)break;
page_message=new String(tmp, 0, i);
System.out.print(page_message);
}
if(channel.isClosed()){
if(in.available()>0) continue;
System.out.println("exit-status: "+channel.getExitStatus());
break;
}
try{Thread.sleep(1000);}catch(Exception ee){}
}
channel.disconnect();
session.disconnect();
}
catch(Exception e){
System.out.println(e);
}
}
public static void main(String arg[]){
connect();
}
public String return_message(){
String ret_message=page_message;
return ret_message;
}
public static abstract class MyUserInfo
implements UserInfo, UIKeyboardInteractive{
public String getPassword(){ return null; }
public boolean promptYesNo(String str){ return false; }
public String getPassphrase(){ return null; }
public boolean promptPassphrase(String message){ return false; }
public boolean promptPassword(String message){ return false; }
public void showMessage(String message){ }
public String[] promptKeyboardInteractive(String destination,
String name,
String instruction,
String[] prompt,
boolean[] echo){
return null;
}
}
The "exec" channel in the JSch (rightfully) does not allocate a pseudo terminal (PTY) for the session. As a consequence a different set of startup scripts is (might be) sourced (particularly for non-interactive sessions, .bash_profile is not sourced). And/or different branches in the scripts are taken, based on absence/presence of the TERM environment variable. So the environment might differ from the interactive session, you use with your SSH client.
So, in your case, the PATH is probably set differently; and consequently the air executable cannot be found.
To verify that this is the root cause, disable the pseudo terminal allocation in your SSH client. For example in PuTTY, it's Connection > SSH > TTY > Don't allocate a pseudo terminal. Then, go to Connection > SSH > Remote command and enter your air ... command. Check Session > Close window on exit > Never and open the session. You should get the same "air not found" error.
Ways to fix this, in preference order:
Fix the command not to rely on a specific environment. Use a full path to air in the command. E.g.:
/bin/air sandbox run <graph-path>
If you do not know the full path, on common *nix systems, you can use which air command in your interactive SSH session.
Fix your startup scripts to set the PATH the same for both interactive and non-interactive sessions.
Try running the script explicitly via login shell (use --login switch with common *nix shells):
bash --login -c "air sandbox run sandbox run <graph-path>"
If the command itself relies on a specific environment setup and you cannot fix the startup scripts, you can change the environment in the command itself. Syntax for that depends on the remote system and/or the shell. In common *nix systems, this works:
String command="PATH=\"$PATH;/path/to/air\" && air sandbox run <graph-path>";
Another (not recommended) approach is to force the pseudo terminal allocation for the "exec" channel using the .setPty method:
Channel channel = session.openChannel("exec");
((ChannelExec)channel).setPty(true);
Using the pseudo terminal to automate a command execution can bring you nasty side effects. See for example Is there a simple way to get rid of junk values that come when you SSH using Python's Paramiko library and fetch output from CLI of a remote machine?
For a similar issues, see
Certain Unix commands fail with "... not found", when executed through Java using JSch even with setPty enabled
Commands executed using JSch behaves differently than in SSH terminal (bypasses confirm prompt message of "yes/"no")
JSch: Is there a way to expose user environment variables to "exec" channel?
Command (.4gl) executed with SSH.NET SshClient.RunCommand fails with "No such file or directory"
you could try to find out where "air" resides with
whereis air
and then use this outcome.
something like
/usr/bin/air sandbox run graph
You can use an ~/.ssh/environment file to set your AB_HOME and PATH variables.
Jsch, private.ppk based login.
Currently i have following code to ssh login but getting exception due to does not provide key.
Following is my error i am getting
om.jcraft.jsch.JSchException: Auth cancel
JSch jsch = new JSch();
Session session = jsch.getSession(user_name, host, 22);
UserInfo ui = new SSHUserInfo(password, true);
session.setUserInfo(ui);
//connect to remove server
session.connect();
//sudo login bamboo
if (null != session && session.isConnected()) {
session.disconnect();
}
JSch jsch = new JSch();
// Here privateKey is a file path like "/home/me/.ssh/secret_rsa "
// passphrase is passed as a string like "mysecr"
jsch.addIdentity(privateKey, passphrase);
session = jsch.getSession(user, host, port);
session.setConfig("StrictHostKeyChecking", "no");
// Or yes, up to you. If yes, JSch locks to the server identity so it cannot
// be swapped by another with the same IP.
session.connect();
channel = session.openChannel("shell");
out = channel.getOutputStream();
channel.connect();
The file suffix ".ppk" means that you are trying to use Putty's private key, I guess.
JSch has supported the Putty's private keys since 0.1.49,
and if your key is ciphered, you must install "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"[1] on your environment.
And then, if you are using Pageant usually, you may be interested in trying jsch-agent-proxy[2].
[1] http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
[2] https://github.com/ymnk/jsch-agent-proxy
I have a password protected internal maven repository I'd like to use to resolve dependencies in grails.
Does anyone know how to configure grails to use authentication when accessing a repository?
I'm running grails 1.2.1.
You can look in the docs: 3.7.2) Dependency Repositories -> Authentication
From the Docs:
If your repository requires some form of authentication you can specify as such using a credentials block:
credentials {
realm = ".."
host = "localhost"
username = "myuser"
password = "mypass"
}
Just making Brandon answer a bit more specific for the Nexus and Artifactory Maven repositories, as the realm attribute is key for this to work.
If you are using Nexus the credentials block look like this:
credentials {
realm = "Sonatype Nexus Repository Manager"
host = "hostname"
username = "username"
password = "password"
}
, but if you are using Artifactory, it should look like this:
credentials {
realm = "Artifactory Realm"
host = "hostname"
username = "username"
password = "password"
}
You need to add this block to your BuildConfig.groovy file, but if your code is going to be open sourced or you want this setting for all your projects, you can add the block inside your ~/.grails/settings.groovylike this:
grails.project.ivy.authentication = {
credentials {
realm = "your realm"
host = "hostname"
username = "username"
password = "password"
}
}
Cheers,
Angel.