So I'm writing a little program that needs to connect to a remote server through SFTP, pull down a file, and then processes the file. I came across JSch through some answers here and it looked perfect for the task. So far, easy to use and I've got it working, with one minor thing I'd like to fix. I'm using the following code to connect and pull the file down:
JSch jsch = new JSch();
Session session = null;
try {
session = jsch.getSession("username", "127.0.0.1", 22);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword("password");
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp) channel;
sftpChannel.cd(REMOTE_FTP_DIR);
sftpChannel.lcd(INCOMING_DIR);
sftpChannel.get(TMP_FILE, TMP_FILE);
sftpChannel.exit();
session.disconnect();
} catch (JSchException e) {
e.printStackTrace();
} catch (SftpException e) {
e.printStackTrace();
}
So this works and I get the file. I'm running this code on a linux server and when I run the code JSch asks me for my Kerberos username and password. It looks like:
Kerberos username [george]:
Kerberos password for george:
I just hit enter for both questions and then the program seems to continue on with no problems. However I need this code to be automated through a cron task and so I'd rather not having it pausing the program to ask me these two questions. Is there something I'm not supplying it so that it won't ask this? Something I need to do to stop it asking? Hopefully someone has some ideas. Thanks.
Thought I'd post an answer here since in case anyone else ends up running into a similar issue. Turns out I am missing a piece of code that makes all the difference. I just needed to add
session.setConfig("PreferredAuthentications",
"publickey,keyboard-interactive,password");
before
session.connect();
and everything works perfectly now.
While the solution in the self-accepted answer is correct, it lacks any explanation.
The problem is that the OP have a Kerberos/GSSAPI authentication set as the preferred (the JSch default). Yet OP does not seem to actually use/want it, as OP claims not to specify any username or password for the Kerberos prompts.
This problem can appear spontaneously, when either Kerberos gets installed on the the client PC or the server starts to support Kerberos.
The solution is to remove the Kerberos/GSSAPI (gssapi-with-mic) from the list of preferred authentication methods in JSch:
session.setConfig(
"PreferredAuthentications", "publickey,keyboard-interactive,password");
All answers are correct, I'll just add here the way it can be done for Spring Integration when trying to integrate with an SFTP server.
So, if you are using SFTP Spring Integration and the weird user and password for Kerberos is prompting in the same way the OP is asking.
Then modify your Spring configuration (I'm using Java Spring Integration config, if you are using XML config you can try to translate it yourself - I really don't like XML config :P ):
So in the bean you are using as SessionFactory you need to add this change in config:
#Bean
public SessionFactory<LsEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost("hostname");
factory.setPort(22);
factory.setUser("username");
factory.setPassword("superstrongpassword");
factory.setAllowUnknownKeys(true);
factory.setSessionConfig(buildSessionProperties());
return new CachingSessionFactory<>(factory);
}
/**
* Build JSch property PreferredAuthentications without "gssapi-with-mic"
* This way it won't prompt for Kerberos authentication every time it tries to connect
* to the SFTP.
*/
private Properties buildSessionProperties() {
Properties sessionProperties = new Properties();
sessionProperties.setProperty("PreferredAuthentications", "publickey,keyboard-interactive,password");
return sessionProperties;
}
Related
I tried to use JSch:
#Test
public void test() throws Exception {
var session = new JSch().getSession("host");
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
var version = session.getServerVersion();
System.out.println("version = " + version);
}
but I'm getting
java.lang.NullPointerException: Cannot read the array length because "str" is null
It seems that this implementation requires you to connect and authenticate.
How can I get this information with Java, without the need to authenticate?
This Python code works for me on a server that requires authentication yet I didn't have to authenticate in order to get the remote version.
import paramiko
ssh = paramiko.Transport(("host", 22))
ssh.start_client()
print(ssh.remote_version)
ssh.close()
The SSH identification string is sent in plain text right after opening the connection.
So you do not need an SSH library to obtain the string.
You can do with a simple code like shown here:
Read Data from a Java Socket
Or just try to login using dummy credentials with JSch and then read Session.getServerVersion.
You do not even have to try to login. You can abort the connection right at the host key check:
config.put("StrictHostKeyChecking", "yes");
I have two VM's. On machine 'A' SSH login happens using Private Key and on machine 'B' login happens using UserName and Pwd.
So, I would like to keep my code generic for both the systems. Let me know is this possible, if yes can you help me out.
jsch.addIdentity(Private_Key_Path);
session = jsch.getSession(telnetUser, telnetHost, port);
session.setConfig("PreferredAuthentications", "publickey,keyboard-interactive,password");
session.setPassword(telnetPwd);
session.setConfig("config");
session.connect();
Maybe this question is already answered, but I couldn't find the proper answer.
I have a web application based in JSF, and I want to share the same email session between all the instances of the application, yet I haven't found how to do that.
My questions are:
a) What I am thinking is stupid? Should I just create a new session every time that I want to send a new mail?
b) If a is false, is there a proper way to do that?
Additional info: I'm working with PrimeFaces 4.0, Apache Tomcat 7.0.41, and JDK 7.
EDIT: I'm establishing an email connection like this (using sun's java mail)
Properties datos = new Properties();
datos.put("mail.smtp.host", "smtp.gmail.com");
datos.setProperty("mail.smtp.starttls.enable", "true");
datos.setProperty("mail.smtp.port", "587");
datos.setProperty("mail.smtp.user", usuarioAutenticacion);
datos.put("mail.smtp.timeout", 5000);
System.out.println(usuarioAutenticacion + " - " + contrasenaAutenticacion);
sesionCorreo = Session.getDefaultInstance(datos, null);
sesionCorreo.setDebug(true);
try {
conexionCorreo = sesionCorreo.getTransport("smtp");
} catch (NoSuchProviderException ex) {
Logger.getLogger(NotificacionesManager.class.getName()).log(Level.SEVERE, null, ex);
}
try {
conexionCorreo.connect(usuarioAutenticacion, contrasenaAutenticacion);
Then I proceed to send the messages in the Queue, but I'm looking for a way for just set that connection once then start sending the mails in the queue when necessary.
The way that the Java EE designers intended you to do this is that you configure your javax.mail.Session object in your server. This is described in the Tomcat 7 JavaMail Sessions documentation.
Your managed beans should then be able to access the session via #Resource:
class MyManagedBean {
#Resource(name="mail/Session") // this name is defined by your configuration
private Session mailSession;
public void someBusinessMethod() {
...
Message message = new MimeMessage(mailSession);
// compose message
...
Transport.send(message);
}
}
If you need to do this from a non-managed bean then you grab your Session instance using JNDI. This is described in the documentation linked above.
I'm using com.jcraft.jsch.JSch to create an SFTP connection.
Is there a way to bypass/skip the authenticity warning that pops up when the connection's authenticity can't be established?
Here's more detail:
My code looks a little like this:
Session session = jsch.getSession(user, host, port);
UserInfo ui = new MyUserInfo();
session.setUserInfo(ui);
session.connect();
When the session.connect(); line is called, I get a popup that reads:
The authenticity of host <MY HOST> can't be established.
...
Are you sure you want to continue connecting?
[No] [Yes]
Is there a way to programmatically bypass/skip this popup and accept the connection?
Take a look at these examples from Jsch: http://www.jcraft.com/jsch/examples/Exec.java.html http://www.jcraft.com/jsch/examples/Shell.java.html You'll notice that both of them create a custom UserInfo class and pass it to the session object with session.setUserInfo(UserInfo ui);.
The way to avoid that popup window is to pass in your own UserInfo object. You can do this by extending the UserInfo class and overriding the promptYesNo function, like this:
public boolean promptYesNo(String str){ return true; }
Note that all of the functions whose names start with the word "prompt" are used to prompt the user for information with a popup dialog. You can override those functions to pass in the information in some other way.
I know this thread is very old and doesn't require any reply if its already solved, But a week back I too was working on an application that had a similar requirement.
What Jon7 said was right; Adding to that theres a different way too i.e. without extending any class.
Session session = jsch.getSession(user, host, port);
...
Properties prop = new Properties();
prop.setProperty("StrictHostKeyChecking", "no");
session.setConfig(prop);
session.connect();
Just another way that can help others :)
regards,
icr
I try to send a message in a grails application. I use Java code with this problem tho, here is my code
SimpleMailMessage message_ref = new SimpleMailMessage();
JavaMailSenderImpl sender_ref = new JavaMailSenderImpl();
sender_ref.setHost("smtp.gmail.com")
sender_ref.setUsername("testAccount#googlemail.com")
sender_ref.setPassword("topsecret")
message_ref.setTo("testRecipient#gmx.de")
message_ref.setSubject("Hello there")
message_ref.setText("How are you")
sender_ref.send(message_ref)
I'm getting the following exception:
SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS command first
I found a similar problem here on stackoverflow here
Must issue a STARTTLS command first. Sending email with Java and Google Apps
but it didn't help me cause he used an different approach.
Can somebody tell me what's wrong? I'm expecting the error is not in the code but in some configuration file and this is where my knowledge edges.
Quoting from the Grails mail plugin docs:
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "youracount#gmail.com"
password = "yourpassword"
props = ["mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"]
} }
I can't help you much, but your problem is basically that you need to use SSL to communicate with the server. Google does not allow plain-text communication for a lot of good reasons. I don't know much about grails, but I assume it has some sort of ssl-support. If it does not, you're probably better off doing it in javax.mail.
StartTLS is just a text-command you send to the smtp-server to explicitly start secure communications.
Properties properties = new Properties();
properties.put("mail.smtp.host", smtpHost);
properties.put("mail.smtp.port", smtpPort);
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.user", userName);
properties.put("mail.password", password);