Running a Shell Script using java ( process Builder ) with a specific unix user - jsch

I have developed a web application ( deployed on a weblogic server ) , I want to connect to the solaris server and execute a shell script with a specific unix user.
At present , the script runs with a wls user. Here's the portion of my code :
String CLA="-d";
out.println("Stopping ASAP for the changes to reflect ...");
ProcessBuilder processBuilder = new ProcessBuilder("/bin/ksh","/apps/vpn/asap/scripts/stop_asap_sys_tool"+" "+CLA);
process = processBuilder.start();
InputStream is = process.getInputStream();
InputStream isErr = process.getErrorStream();
InputStreamReader isr = new InputStreamReader(is);
InputStreamReader isrErr = new InputStreamReader(isErr);
BufferedReader br = new BufferedReader(isr);
BufferedReader brErr = new BufferedReader(isrErr);
String line;
String lineErr;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
while ((lineErr = brErr.readLine()) != null) {
System.out.println(lineErr);
}
My search result suggests to use Jsch. Can some one give me an example with respect to my implementation on using Jsch. Or any other way of doing it ?!
THanks ,
Bhavin

Jsch is a good way to go, here is something to assist you with what you trying to do:
Examples from the Main Site which covers Remote Execution
[click]
Also here is the code already done for you on StackOverflow [click]
A word of advice, when you execute scripts, and you have written then on Windows or opened them there, you will need to run a dos2unix on the file (if you executing on Linux); otherwise your remote execution is going to fail horribly.

I think this can help you
/**
* This method allows you to send and execute *nix command through SSH
* to specified removed host and returns command output, in case incorrect
* command will return command output error
*
* #param user - ssh user name for login
* #param password - ssh password for login
* #param host - ip or domain with ssh server
* #param command - command to execute
* #return string with command output or output error
* #author Roman Kukharuk
*/
public String execNixComAndGetRez(String user, String password, String host,
String command) {
int port = 22;
String rez = "+!";
try {
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
// System.out.println("Establishing Connection...");
session.connect();
// System.out.println("Connection established.");
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command); //setting 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;
// System.out.print(new String(tmp, 0, i));
rez = new String(tmp, 0, i);
}
if (channel.isClosed()) {
// System.out.println("exit-status: "+channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception e) {
rez = e.toString();
}
}
channel.disconnect();
session.disconnect();
}
catch (Exception e) {
rez = e.toString();
}
return rez;
}

Related

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

JSCH read from input stream hangs from time to time

I'm using jsch-0.1.53.
In order to execute a command and return it's output, I wrote the next block of code:
#Override
public String executeAndGetOutput(CheckPointSSHConnection connection, String command) throws IOException , JSchException{
logger.debug("Executing command \"" + command + "\"");
StringBuilder retVal = new StringBuilder();
ChannelExec channel = null;
InputStream in=null;
InputStream errStream=null;
try {
Session session = connection.getSession();
channel = (ChannelExec) session.openChannel("exec");//only shell
in = channel.getInputStream();
errStream = channel.getErrStream();
channel.setCommand(command);
channel.connect(10000);
String errInStr = StringUtils.toString(errStream);
String inStr = StringUtils.toString(in);
return inStr+errInStr;
} finally {
IOUtils.close(in);
IOUtils.close(errStream);
if (channel != null) {
try {
channel.disconnect();
} catch (Throwable throwable) {
logger.warn("An exception occured while trying to close ssh chanel. Message:",
throwable.getMessage());
}
}
}
}
The problem is that from time to time, reading the errStream just hangs and blocking the thread.
Can someone please tell me what I'm doing wrong?
The command that I'm executing is load_indicators --add -a detect -i /tmp/sample_file.csv , it's Checkpoint CLI

using oPort option in Apache commons SFTP

I have a sftp server which i can connect manually using the command below
sftp -oport=4022 user#xxxxxx.com
but I am finding difficulty in doing the same with apache commons vfs.
Below is the method I am using to establish connection to the sftp server. But it not working and fails with the error "org.apache.commons.vfs2.FileSystemException: Could not connect to SFTP server at xxxxxx.com"
public boolean connect(String host, String login, String password,
int port) throws Exception {
//If the client is already connected, disconnect
if (command != null) {
disconnect();
}
FileSystemOptions fso = new FileSystemOptions();
try {
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fso,
"no");
session =
SftpClientFactory.createConnection(host, port, login.toCharArray(),
password.toCharArray(),
fso);
System.out.println("pass");
Channel channel = session.openChannel("ssh");
channel.connect();
command = (ChannelSftp)channel;
} catch (FileSystemException e) {
throw e;
// return false;
}
return command.isConnected();
}
Please help me with this

How to interact with the script after its execution using Jsch

Scenario:
1.I am able to execute a bash script on remote ssh server successfully.
2.The script wants the user to enter some input's to proceed.
The Program hangs after the script is executed.
Q:1 Is this possible using JSCH or any other java based libraries?
Q:2 Which is the best library in java to handle such scenario?
Below is my piece of code :
public class SshMultiCommands
{
public void execute(String u,String h,String p) throws Exception
{
JSch jsch = new JSch();
String user = u;
String host = h;
String passwd = p;
int port = 22;
Session session = jsch.getSession(user, host, port);
session.setPassword(passwd);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Channel channel = session.openChannel("shell");
OutputStream ops = channel.getOutputStream();
channel.setOutputStream(ops,true);
((ChannelShell)channel).setPtyType("vt102");
((ChannelShell)channel).setEnv("LANG", "ja_JP.eucJP");
PrintStream ps = new PrintStream(channel.getOutputStream());
channel.connect();
Thread.sleep(1000);
InputStream input = channel.getInputStream();
//commands
ps.println("ls -l");
ps.println("bash /opt/dla.sh");
ps.println("3"); // The sample user Input to script.This is getting printed but is not getting executed
printResult(input, channel);
ps.close();
channel.disconnect();
session.disconnect();
//System.out.println("OT Session Completed");
}
private static void printResult(InputStream input,
Channel channel) throws Exception
{
int SIZE = 1024;
byte[] tmp = new byte[SIZE];
while (true)
{
while (input.available() > 0)
{
int i = input.read(tmp, 0, SIZE);
if(i < 0)
break;
System.out.print(new String(tmp, 0, i));
}
if(channel.isClosed())
{
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try
{
Thread.sleep(300);
}
catch (Exception ee)
{
}
}
}
}
Solution: Put sleep of 5-10 sec after you run the script or program. And keep flushing the output stream after every command. If you already used sleep, extend its time.
The program or script that u run takes a bit of time to take over the system's standard input and out streams. If u pass all the commands and params immediately the parameters which were intented for the program goes to the system's bash instead !

Starting bbcomm in Java v3 Bloomberg API

When I use the Java Bloomber V3 API it usually works. However, sometimes, especially after a reboot, bbcomm.exe is not running in the background. I can start it manually by running blp.exe, but I wondered if there was a way of doing this via the API?
After talking to the help desk, it turns out that on 64 bit Windows, running under a 64bit JVM bbcomm is not automatically started. This does not happen under 32bit Java - under 32 bit bbcomm automatically runs.
So my solutions are either to wait for the problem to be fixed by Bloomberg (now I understand it) or to check this specific case.
To check the specific case:
if running under a 64 bit windows (System property os.arch)
and if running under a 64bit JVM (System property java.vm.name)
then try and start a session
If this fails, assume bbcomm.exe is not running. Try to run bbcomm.exe using Runtime.exec()
I haven't tested the above yet. It may have exactly the same issues as Bloomberg have with 64bit VMs.
After spending some time with Help Help, it seems that bbcomm gets started either when you use the Excel API or run the API demo. But it does not get started automatically when called from the Java API. Possible ways to start it are:
adding an entry in the registry to automatically start bbcomm on startup: in HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run add a String value called bbcomm with value C:\blp\API\bbcomm.exe - but that opens a command window which remains visible, so not really an option (and if you close that window it terminates the bbcomm process)
create a batch file START /MIN C:\blp\API\bbcomm.exe and replace the entry in the registry with that (not tested) to call bbcomm silently
manually launch bbcomm from your java code as already suggested. As a reference, I post below the code that I'm using.
private final static Logger logger = LoggerFactory.getLogger(BloombergUtils.class);
private final static String BBCOMM_PROCESS = "bbcomm.exe";
private final static String BBCOMM_FOLDER = "C:/blp/API";
/**
*
* #return true if the bbcomm process is running
*/
public static boolean isBloombergProcessRunning() {
return ShellUtils.isProcessRunning(BBCOMM_PROCESS);
}
/**
* Starts the bbcomm process, which is required to connect to the Bloomberg data feed
* #return true if bbcomm was started successfully, false otherwise
*/
public static boolean startBloombergProcessIfNecessary() {
if (isBloombergProcessRunning()) {
logger.info(BBCOMM_PROCESS + " is started");
return true;
}
Callable<Boolean> startBloombergProcess = getStartingCallable();
return getResultWithTimeout(startBloombergProcess, 1, TimeUnit.SECONDS);
}
private static Callable<Boolean> getStartingCallable() {
return new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
logger.info("Starting " + BBCOMM_PROCESS + " manually");
ProcessBuilder pb = new ProcessBuilder(BBCOMM_PROCESS);
pb.directory(new File(BBCOMM_FOLDER));
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.toLowerCase().contains("started")) {
logger.info(BBCOMM_PROCESS + " is started");
return true;
}
}
return false;
}
};
}
private static boolean getResultWithTimeout(Callable<Boolean> startBloombergProcess, int timeout, TimeUnit timeUnit) {
ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "Bloomberg - bbcomm starter thread");
t.setDaemon(true);
return t;
}
});
Future<Boolean> future = executor.submit(startBloombergProcess);
try {
return future.get(timeout, timeUnit);
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
return false;
} catch (ExecutionException | TimeoutException e) {
logger.error("Could not start bbcomm", e);
return false;
} finally {
executor.shutdownNow();
try {
if (!executor.awaitTermination(100, TimeUnit.MILLISECONDS)) {
logger.warn("bbcomm starter thread still running");
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
ShellUtils.java
public class ShellUtils {
private final static Logger logger = LoggerFactory.getLogger(ShellUtils.class);
/**
* #return a list of processes currently running
* #throws RuntimeException if the request sent to the OS to get the list of running processes fails
*/
public static List<String> getRunningProcesses() {
List<String> processes = new ArrayList<>();
try {
Process p = Runtime.getRuntime().exec(System.getenv("windir") + "\\system32\\" + "tasklist.exe");
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
int i = 0;
while ((line = input.readLine()) != null) {
if (!line.isEmpty()) {
String process = line.split(" ")[0];
if (process.contains("exe")) {
processes.add(process);
}
}
}
} catch (IOException e) {
throw new RuntimeException("Could not retrieve the list of running processes from the OS");
}
return processes;
}
/**
*
* #param processName the name of the process, for example "explorer.exe"
* #return true if the process is currently running
* #throws RuntimeException if the request sent to the OS to get the list of running processes fails
*/
public static boolean isProcessRunning(String processName) {
List<String> processes = getRunningProcesses();
return processes.contains(processName);
}
}
In case someone needs help checking/starting bbcomm.exe process from the code hiding console window, this snippet is written in C#; I hope you can easily translate it to Java.
void Main()
{
var processes = Process.GetProcessesByName("bbcomm");
if (processes.Any())
{
Console.WriteLine(processes.First().ProcessName + " already running");
return;
}
var exePath = #"C:\blp\DAPI\bbcomm.exe";
var processStart = new ProcessStartInfo(exePath);
processStart.UseShellExecute = false;
processStart.CreateNoWindow = true;
processStart.RedirectStandardError = true;
processStart.RedirectStandardOutput = true;
processStart.RedirectStandardInput = true;
var process = Process.Start(processStart);
Console.WriteLine(process.ProcessName + " started");
}
bbcomm.exe is automatically started by the V3 API.