I am need to spawn a SSH connection from a JAVA program using ProcessBuilder and a USERID/PASSWORD combination.
I have already successfully implemented SSH connections using Ganymed, JSch, a combination of JAVA Processbuilder and Expect scripting (Expect4J also), JAVA ProcessBuilder and SSHPASS script and SSH Shared Key.
Security is NOT a concern at this point in time and all I am after is to be able to support programmatically all kinds of combinations for SSH connection.
My problem is the Password prompt that SSH throws somewhere that is not on STDIN/STDOUT (on a tty I believe). This is my last hurdle to overcome.
My question is there a way to intercept SSH password request and provide it from my JAVA code?
Please, note this is a very narrow question (and all the above information was to guarantee the answer would not be too broad).
Here is a sample code of what I am trying:
import java.io.*;
import java.util.*;
public class ProcessBuilderTest {
public static void main(String[] args) throws IOException, Exception {
ProcessBuilder pb = new ProcessBuilder(
"/usr/bin/ssh",
"nyuser#myserver.com",
"export NOME='Jennifer Lawrence'; echo $NOME"
);
pb.redirectErrorStream(); //redirect stderr to stdout
Process process = pb.start();
InputStream inputStream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while((line = reader.readLine())!= null) {
System.out.println(line);
}
process.waitFor();
}
}
But, when I run it I got this:
[memphis BuilderTest]# java ProcessBuilderTest
myuser#myserver's password:
and after I type the password, I got the rest of the output:
Jennifer Lawrence
[memphis BuilderTest]#
Again, the specific question is:
Is there a way to spawn an external ssh client (OpenSSH, Tectia SSH, SecureCRT, etc) using PasswordAuthentication method (no other method can be used) process using JAVA ProcessBuilder interface (no other language can be used), intercept/capture the password prompt and respond/interact providing that password from my JAVA code (so the user does not need to type it)?
You need to learn about pseudo-ttys, assuming that you are operating on Linux. The password prompt is on the tty device. You will need to build a separate process running against a pseudo-tty instead of just inheriting your tty device, and then you can intercept the password prompt.
This is a moderately complex process.
There is a library that supports some of this: http://www.ganymed.ethz.ch/ssh2/FAQ.html. You might find reading its source illuminating if it is available.
While it has been suggested that a pseudo-tty (pty) is required to simulate a terminal, the accepted answer doesn't provide a working solution - there are also lots of similar questions with no working answers.
Here are two solutions that allow you to capture the "Password:" prompt in SSH and enter the password in an automated way without using SSH_ASKPASS or Expect.
Why use one programming language when you can use two - the first option isn't ideal, but it demonstrates the solution:
ProcessBuilder pb = new ProcessBuilder("/usr/bin/python", "-c", "import pty; pty.spawn(['/usr/bin/ssh', '<hostname>'])");
The above example makes use of the Python pty module to wrap SSH into a PTY. Although it is simple, it doesn't provide any flexibility to allow you to modify any terminal properties like the passed window size.
The other more lightweight option is to use a PTY wrapper in C - the pty tool from the "Advanced Programming in the UNIX® Environment" book is just this - the source can be found at https://github.com/abligh/pty.
You will then use it in a similar way, but referencing the pty tool instead of Python:
ProcessBuilder pb = new ProcessBuilder("/usr/local/bin/pty", "/usr/bin/ssh", "<hostname>");
This is the same approach that Expect uses to simulate a PTY, which is why you are able to intercept it using Expect. It goes without saying that tunneled clear text passwords are insecure and public key authentication should always be the preferred way of doing this.
Related
I'm using IntelliJ IDEA to remote debug a Java CLI program with the debugger listening for connections.
This works fine for the first invocation, but the debugger stops listening after the CLI program disconnects. I want the debugger to keep listening since multiple CLI invocations will be made (in sequence, not in parallel) and only one of these will trigger the breakpoint I've set.
Here's my client debug config:
-agentlib:jdwp=transport=dt_socket,server=n,address=5005,suspend=y
Is it possible to keep the debugger listening?
Well since your CLI program terminates, debugger also stops. If you still want to continue debugger session for multiple runs of CLI program, then you can try as below,
Write a wrapper program from which you invoke your CLI program multiple times and debug the wrapper program instead of your CLI program.
Something like this,
public class Wrapper {
public static void main(String[] args) {
YourCLIProgram yp = new YourCLIProgram();
// First Invocation
String[] arg1 = { }; // Arguments required for your CLI program
yp.main(arg1);
// Second Invocation
String[] arg2 = { }; // Arguments required for your CLI program
yp.main(arg2);
// Third Invocation
String[] arg3 = { }; // Arguments required for your CLI program
yp.main(arg3);
// Fourth Invocation
String[] arg4 = { }; // Arguments required for your CLI program
yp.main(arg4);
}
}
I hope it works.
It depends also what you are trying to achieve.
If you want to check what parameters are passed to your CLI you can just log them to the file or save any information that you need in DB (or file as well).
In JPDA by specification transport service could support or not multiple connections.
For example, in Eclipse it doesn't. I suppose the same for IDEA.
When setting up your run configuration, did you select the "Listen" Debugger mode? The command line arguments you show look like the normal "Attach" settings, whereas the arguments for "Listen" look like this:
-agentlib:jdwp=transport=dt_socket,server=n,address=yourhost.yourdomain:5005, suspend=y,onthrow=<FQ exception class name>,onuncaught=<y/n> (Specifically, your arguments are missing the address for the application - your CLI program - to connect to IDEA at on start-up.)
I read a post that suggests the "onthrow" argument may not be necessary for general debugging, but I haven't tried it myself.
Try with suspend=n:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
On my local app (tomcat web app), even though I run on JDK8, I still use the older way of doing it and it works fine (another thing you could try):
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
In some code i use similar code to Oracle's tutorial: Reading directly from a URL. Oracle's code also here below:
import java.net.*;
import java.io.*;
public class URLReader {
public static void main(String[] args) throws Exception {
URL oracle = new URL("http://www.oracle.com/");
BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
This code worked before but it doesnt anymore. Even if i try the exact same code, inputLine never has any value. I dont know if it has something to do with java versions or something elso but i would like to know why this happens, and what is a good alternative.
If you replace http://www.oracle.com/ by http://www.google.com/ it works.
It's because a GET http://www.oracle.com/ gives
HTTP/1.1 301 Moved Permanently
If you run
curl www.oracle.com
You obtain the same effect. You have to follow the redirect with
curl -L www.oracle.com
to obtain the html content. In Java, you also have to follow the redirect, such as in this article :
https://www.mkyong.com/java/java-httpurlconnection-follow-redirect-example/
Oracle -
When you run the program, you should see, scrolling by in your command
window, the HTML commands and textual content from the HTML file
located at http://www.oracle.com/. Alternatively, the program might
hang or you might see an exception stack trace. If either of the
latter two events occurs, you may have to set the proxy host so that
the program can find the Oracle server.
You can set the proxy host through the command line. Depending on
your network configuration, you might also need to set the proxy
port. If necessary, ask your system administrator for the name of the
proxy host on your network.
UNIX
java -Dhttp.proxyHost=proxyhost
[-Dhttp.proxyPort=portNumber] URLReader
DOS shell (Windows 95/NT)
java -Dhttp.proxyHost=proxyhost
[-Dhttp.proxyPort=portNumber] URLReader
Also, I have actually ran it on my IDE but it only works with HTTPS
As loris securo commented i needed to use https instead of http. And that fixed my problems.
As a security measure Windows forwards local smartcard readers to the remote machine. The problem is that
readers you already have handles for become unusable
it's not possible to get new readers
If you try to use a terminal or CardTerminals object, you get a PCSCException: SCARD_E_SERVICE_STOPPED.
I have code to demonstrate the issue:
import javax.smartcardio.*;
public class ScRdp {
public static void main( final String[] args ) throws Exception
{
TerminalFactory factory = TerminalFactory.getDefault();
System.out.println( "Factory: " + factory.hashCode() );
final CardTerminals terminals = factory.terminals();
List<CardTerminal> termNames = terminals.list();
BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) );
in.readLine();
main( args );
}
}
Launch the code on machine A, RDP in using machine B and hit enter. You can even RDP in, immediately disconnect and hit enter on machine A.
In C, I would use SCardReleaseContext and SCardEstablishContext (ref). Is there any way to do this through the Java API?
Followup
AFAICT this is not possible. However see link, link. It should be possible to disable smartcard redirection on the server, circumventing the problem.
On Win7 Pro I found the setting in gpedit.msc: "Computer Configuration/Administrative Templates/Windows Components/Remote Desktop Services/Remote Desktop Session Host/Device and Resource Redirection/Do not allow smart card device redirection". That said I do not have this working yet. Even unchecking the "forward smartcards" checkbox in the RDP client before connection doesn't help.
This is only an issue if you RDP in as the same user as the one using the readers. We circumvented it by running the server using JavaService.exe from ObjectWeb to run as "Local System" user.
I have Gui Application written which running on windows,and i want to connect to remote unix machine and perform actions there such like API's ,go over the log file in the machines and send back to the application the last log file or others API that i want to perform on the remote machine.
In the remote machine i don;t have application server i just have Java which installed there.
I want to use Java in order to perform remote API over the remote machine;
what is the advice ,can i use web services ,can any one please advise.
Thanks in advance.
If Java can perform the actions you're talking about, I would use Sockets to communicate with the UNIX-Machine (over TCP/IP).
Your Windows-PC would be the client sending commands to the Unix-PC.
Web services would be a bit heavy handed option, esp if you opt for the SOAP ones. If you don't have a problem with the client and server always being Java, RMI seems to be the simplest solution to this problem since it's communication between two different JVM's using the normal method calling mechanism (with some additional interfaces and rules to be followed to please the RMI specification).
The Spring Framework ships with a number of remoting options that are all very easy to setup. You can use their classes for simpler configuration of something standard like RMI or JMS, or use a lightweight web services protocol such as Spring's HTTP invoker or Hessian.
For analyzing log files of remote machines you can always use Apache Commons sftp programmatically to FTP a copy of the remote log file to your PC.
If you configure the log files to be rotatable or to rotate each time they reach a specific size, you can avoid reloading the same information over and over.
You can use Ganymed SSH-2 for Java to ssh to the remote host from Client Java App and run the commands. No need to run any additional components on remote server. You can do password based authentication or key based authentication to login to remote host. We had successfully used it to administer (start/stop/grep log files, etc.) applications running on remote UNIX hosts. You can capture output of the remote command using the StreamGobbler class provided in the package. You can pass multiple commands separated by semi-colon in one remote call.
Basic Example included in the package:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
public class Basic
{
public static void main(String[] args)
{
String hostname = "127.0.0.1";
String username = "joe";
String password = "joespass";
try
{
/* Create a connection instance */
Connection conn = new Connection(hostname);
/* Now connect */
conn.connect();
/* Authenticate.
* If you get an IOException saying something like
* "Authentication method password not supported by the server at this stage."
* then please check the FAQ.
*/
boolean isAuthenticated = conn.authenticateWithPassword(username, password);
if (isAuthenticated == false)
throw new IOException("Authentication failed.");
/* Create a session */
Session sess = conn.openSession();
sess.execCommand("uname -a && date && uptime && who");
System.out.println("Here is some information about the remote host:");
/*
* This basic example does not handle stderr, which is sometimes dangerous
* (please read the FAQ).
*/
InputStream stdout = new StreamGobbler(sess.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
while (true)
{
String line = br.readLine();
if (line == null)
break;
System.out.println(line);
}
/* Show exit status, if available (otherwise "null") */
System.out.println("ExitCode: " + sess.getExitStatus());
/* Close this session */
sess.close();
/* Close the connection */
conn.close();
}
catch (IOException e)
{
e.printStackTrace(System.err);
System.exit(2);
}
}
}
I know that by using AT commands we can control the handset.As example unlocking screen we can give a specific AT command or moving right to the menu or left or bottom or up we can give specific AT commands. What all are the AT commands for doing this kind of control.
Thank you.
From what I understand, the AT commands are more used for phone-type functions (making calls, or sending SMS, etc), rather than menu navigation, etc.
I'm not entirely sure if that was your end-goal after menu navigation, but you can find more details here: http://en.wikipedia.org/wiki/Hayes_command_set (the original +AT command set)
If you wanted to send SMS from a handset connected to your computer you might want to take a peek at this page: http://www.developershome.com/sms/atCommandsIntro.asp
If you wanted more control when performing functions, like sending SMS, etc, you might want to investigate "PDU Mode."
It is entirely possible that some handset manufacturers may have implemented additional +AT commands to allow other functions to be performed, so you might do better by specifically searching for the commands related to the handset you are using.
(Of course, if you're having issues connecting to the handset hardware itself, you need to ensure you have either the javax.comm extension or some favoured Java USB API installed)
If post doesn't help, perhaps you could provide more details in your question? (eg. what you are ultimately trying to do, if you think it would help)
List of AT commands
sample java code to use AT command
public void servicesDiscovered(int transID, ServiceRecord serviceRecord[])
{
String url = serviceRecord[0].getConnectionURL(1, false);
try
{
//ClientSession conn= (ClientSession)Connector.open(url);
StreamConnection meineVerbindung = (StreamConnection) Connector.open(url);
if(conn== null)
System.out.println("Kann Service URL nicht oeffnen\n");
else
{
OutputStream out = conn.openOutputStream();
InputStream in = conn.openInputStream();
String message = "AT+CGMI\r\n";
// send AT-command
System.out.println("send AT Comand request: "+message);
out.write(message.getBytes());
out.flush();
out.close();
byte buffer[] = new byte[10000];
// read the response from mobile phone
in.read(buffer);
System.out.println("AT Comand response: "+buffer.toString());}
}
catch(IOException e)
{
System.out.println("Service Error(3): "+e.getMessage());
}
}