0

I have been trying to establish a Jsch session in a Java Spring Controller, so I can execute a shell script. The session is established and commands are run during local testing and manually testing on machine, but failing to connect with

java.net.SocketException : Permission Denied, Connect Failed message in the war file deployed in tomcat on the same machine.

The following code executes when I run on my machine, and also the deployment machine when I login into it and run the class using java RunClass but not when the classes are packed into a war file and deployed into the tomcat. I get this message at either session.connect() or channelExec.connect() code.

java.net.SocketException : Permission Denied, Connect Failed

Why does this behaviour occur?

Earlier, when I was using ProcessBuilder class, I was also able to execute commands on the machine but not via war deployed on tomcat. I had to face Permission Denied, Cannot Execute command chmod (or command conda).

Controller.java

@RequestMapping(value="/endpoint", method=RequestMethod.GET)
public Response<String> generateOrderTrail2(@RequestParam("id) String id){

ScriptCaller scriptCaller = new ScriptCaller();
scriptCaller.setId(id);
scriptCaller.executeCommand();

if(scriptCaller.isSuccessful()){
   return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body("Successful");
}
else{
   return ResponseEntity.badRequest().contentType(MediaType.APPLICATION_JSON).body("Unsuccessful");
}

}

ScriptCaller.java

boolean isSuccessful = false;
public void executeCommand(){
   String command = './dir/folder/executeFile.sh';
try{
JSch jsch = new JSch();
Session session = jsch.getSession(this.username, this.hostname, 22);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);

session.setPassword(this.password);
session.connect();
StringBuilder output = new StringBuilder("");
ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
channelExec.setInputStream((InputStream)null);
InputStreamReader stream = new InputStreamReader(channelExec.getInputStream());
channelExec.setInputStream((InputStream) null);
channelExec.setCommand(command);
channelExec.connect();
char[] buffer = new char[128];
int read;
while ((read=stream.read(buffer 0, buffer.length))>=0){
output.append(buffer, 0, read);
}
this.callerResponse = outputString.toString();
int exitCode = channelExec.getExitStatus();
channelExec.disconnect();
session.disconnect();
if(exitCode == 0){
 System.out.println("Shell Script Executed Successfully");
 isSuccessful = true;
}
else{
 System.out.println("Shell Script Failed to Execute");
 isSuccessful = false;

}
}
catch(Exception e){
  e.printStackTrace();
  isSuccessful = false;
}

Maven Build Command.

mvn clean deploy -Denvironment=local -Dskip.webapp=true -Dmaven.test.skip=true

Exception

java.net.SocketException: Permission Denied(connect failed)
..
..
..
..
at com.jcraft.jsch.Util.createSocket(Util.java)

Tomcat version 7.0.76.0

I checked if the non-root user doesn't have permission or the file doesn't have execute permissions,

The shell file has rwx on all users (777 permissions). The same file is executable with the same user when tested locally or when the code is run inside a single java file if I login and run on the machine.

It's just denying permissions when I call the end point after deploying war file in the tomcat server

7
  • Is SSH enabled in the server? Is the port open?
    – aled
    Commented Jul 8 at 15:52
  • Yes @aled , I was able to ssh via putty into the machine and also, I can use JSch to connect to the machine from local desktop
    – Sarath M
    Commented Jul 9 at 0:11
  • How do you execute your Tomcat? (a) Use System Service (b) Or directly execute ./startup.sh under your user account to execute Tomcat?
    – life888888
    Commented Jul 17 at 14:43
  • Your Tomcat service account should create a privateKey for ssh use, or specify the privateKey in your program. ` String privateKey = "path_to_your_private_key";` jsch.addIdentity(privateKey);
    – life888888
    Commented Jul 17 at 14:47
  • hi @life888888, Thnx for following up! I'm using (b) running the starup.sh command. Do I add need to add private key if I am following (b)?
    – Sarath M
    Commented Jul 18 at 15:22

1 Answer 1

0

I cannot reproduce the error you describe.

The following is the test project:

Project Directory

jschdemoweb-tomcat7
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           ├── Hello2Servlet.java
        │           └── ScriptCaller.java
        └── webapp
            ├── index.jsp
            └── WEB-INF
                └── web.xml

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>jschdemoweb</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>jschdemoweb</name>
    <properties>
        <maven.compiler.target>1.7</maven.compiler.target>
        <maven.compiler.source>1.7</maven.compiler.source>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.55</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>jschdemo</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

ScriptCaller.java

package com.example;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;

public class ScriptCaller {
    private String username = "demo";
    private String password = "your-password";
    private String hostname = "192.168.56.123";
    //private String script="ls -l";
    //private String script="/home/demo/Downloads/demotest.sh";
    private String callerResponse;
    private boolean isSuccessful = false;

    public void executeCommand() {
        //String command = "./dir/folder/executeFile.sh";
        //String command = "/home/demo/Downloads/demotest.sh";
        String command = "cd / && /home/demo/Downloads/demotest.sh";

        try {
            JSch jsch = new JSch();
            Session session = jsch.getSession(this.getUsername(), this.getHostname(), 22);
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);

            session.setPassword(this.getPassword());
            session.connect();
            //StringBuilder output = new StringBuilder("");
            StringBuilder output = new StringBuilder();
            ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
            channelExec.setInputStream((InputStream) null);
            InputStreamReader stream = new InputStreamReader(channelExec.getInputStream());
            channelExec.setInputStream((InputStream) null);
            channelExec.setCommand(command);
            channelExec.connect();
            char[] buffer = new char[128];
            int read;
            while ((read = stream.read(buffer, 0, buffer.length)) >= 0) {
                output.append(buffer, 0, read);
            }
            //this.callerResponse = outputString.toString();
            this.setCallerResponse(output.toString());
            int exitCode = channelExec.getExitStatus();
            channelExec.disconnect();
            session.disconnect();
            if (exitCode == 0) {
                System.out.println("Shell Script Executed Successfully");
                setSuccessful(true);
            } else {
                System.out.println("Shell Script Failed to Execute");
                setSuccessful(false);
            }
        } catch (Exception e) {
            e.printStackTrace();
            setSuccessful(false);
        }
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getHostname() {
        return hostname;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }

    public String getCallerResponse() {
        return callerResponse;
    }

    public void setCallerResponse(String callerResponse) {
        this.callerResponse = callerResponse;
    }

    public boolean isSuccessful() {
        return isSuccessful;
    }

    public void setSuccessful(boolean successful) {
        isSuccessful = successful;
    }
}

Hello2Servlet.java

package com.example;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;

public class Hello2Servlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public Hello2Servlet() {
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().append("Served at: ").append(request.getContextPath() + "\n");
        PrintWriter w = response.getWriter();

        ScriptCaller scriptCaller = new ScriptCaller();
        //scriptCaller.setId(id);
        scriptCaller.executeCommand();

        if (scriptCaller.isSuccessful()) {
            //return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body("Successful");
            System.out.println(scriptCaller.getCallerResponse());
            w.println(scriptCaller.getCallerResponse());
        } else {
            System.out.println("FAIL");
            w.println("FAIL");
            //return ResponseEntity.badRequest().contentType(MediaType.APPLICATION_JSON).body("Unsuccessful");
        }

    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
index JSP HERE
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">
    <display-name>jsch tomcat 7 web</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.jsp</welcome-file>
        <welcome-file>default.htm</welcome-file>
    </welcome-file-list>

    <servlet>
        <description></description>
        <display-name>Hello2Servlet</display-name>
        <servlet-name>Hello2Servlet</servlet-name>
        <servlet-class>com.example.Hello2Servlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Hello2Servlet</servlet-name>
        <url-pattern>/hello2jsch</url-pattern>
    </servlet-mapping>
</web-app>

compile and package

mvn clean package

deploy war to tomcat

copy target/jschdemo.war to Tomcat/webapps

start tomcat

cd Tomcat/bin

./startup.sh

remote pc ssh server

sudo apt update
sudo apt install openssh-server

restart remote pc.

no more config.

remote pc /home/demo/Downloads/demotest.sh

#!/bin/bash
ls -l

Testing

"http://localhost:8080/jschdemo/hello2jsch"

The test results can display the files and directories in the directory normally.

Test environment:

  • The machine used for testing (remote pc) has just been installed and there are no more settings.
  • Tomcat 7.0.76
  • Java version: 1.7.0_352
  • Apache Maven 3.5.4

I can't reproduce your error. I can only deduce that it may be a problem with your shell script.

Or, you can use the war generated by my project settings, install it into your Tomcat to test it, and put testdemo.sh on your remote host for testing. If it works normally, it should not be a problem with Tomcat's settings.

It is also recommended that you add

  • System.out.println(username);,
  • System.out.println(password);,
  • System.out.println(hostname);

to ScriptCaller.java to confirm the connection. Is the information what you expected?

Not the answer you're looking for? Browse other questions tagged or ask your own question.