Remotely accessing mySQL through SSH in Java - java

I'm trying to connect my local Java application to a remote mySQL server. I have shell access to the server and its mySQL, but no root access.
I attempted to implement some code I found online that seems to accomplish this goal. First I SSH into the server, and then I attempt to access the mySQL database. However, I get the following error:
Jul 09, 2014 2:20:06 PM [myClassName] connect
SEVERE: null, message from server: "Host '[remoteHost]' is not allowed to connect to this MySQL server"
I understand that mySQL by default disallows remote client access, but what I don't understand is that in this case it seems to be disallowing itself access to its own mySQL server. (i.e. ["remoteHost"] in the error message is the same host as the one that hosts the mySQL server I'm trying to access.)
The code template I'm using is below. I've left all the fields (user, pass, host, etc.) the same as on the template for the purposes of this question.
Do I need to ask my system administrator to give me special permissions? I have no trouble accessing the mySQL server through terminal. Thanks in advance everyone
Credit to The Kahimyang Project (http://kahimyang.info/kauswagan/code-blogs/1337/ssh-tunneling-with-java-a-database-connection-example).
import java.util.logging.Logger;
import com.jcraft.jsch.*;
import java.util.logging.Level;
public class MysqlManager {
// Logger
private final static Logger LOGGER =
Logger.getLogger(MysqlManager.class.getName());
public static void main(String args[]) {
MysqlManager mng = new MysqlManager ();
mng.connect();
}
public void connect() {
//
int assigned_port;
final int local_port=3309;
// Remote host and port
final int remote_port=3306;
final String remote_host="kahimyang.info";
try {
JSch jsch = new JSch();
// Create SSH session. Port 22 is your SSH port which
// is open in your firewall setup.
Session session = jsch.getSession("user", remote_host, 22);
session.setPassword("ssh_password");
// Additional SSH options. See your ssh_config manual for
// more options. Set options according to your requirements.
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
config.put("Compression", "yes");
config.put("ConnectionAttempts","2");
session.setConfig(config);
// Connect
session.connect();
// Create the tunnel through port forwarding.
// This is basically instructing jsch session to send
// data received from local_port in the local machine to
// remote_port of the remote_host
// assigned_port is the port assigned by jsch for use,
// it may not always be the same as
// local_port.
assigned_port = session.setPortForwardingL(local_port,
remote_host, remote_port);
} catch (JSchException e) {
LOGGER.log(Level.SEVERE, e.getMessage()); return;
}
if (assigned_port == 0) {
LOGGER.log(Level.SEVERE, "Port forwarding failed !");
return;
}
// Database access credintials. Make sure this user has
// "connect" access to this database;
// these may be initialized somewhere else in your code.
final String database_user="user";
final String database_password="password";
final String database = "database";
// Build the database connection URL.
StringBuilder url =
new StringBuilder("jdbc:mysql://localhost:");
// use assigned_port to establish database connection
url.append(assigned_port).append ("/").append(database).append ("?user=").
append(database_user).append ("&password=").
append (database_password);
try {
Class.forName(
"com.mysql.jdbc.Driver").newInstance();
java.sql.Connection connection =
java.sql.DriverManager.getConnection(url.toString());
java.sql.DatabaseMetaData metadata = connection.getMetaData();
// Get all the tables and views
String[] tableType = {"TABLE", "VIEW"};
java.sql.ResultSet tables = metadata.getTables(null, null, "%", tableType);
String tableName;
while (tables.next()) {
tableName = tables.getString(3);
// Get the columns from this table
java.sql.ResultSet columns =
metadata.getColumns(null, tableName, null, null);
String columnName;
int dataType;
while (columns.next()) {
columnName = columns.getString(4);
dataType = columns.getInt(5);
// Your actual task;
}
}
} catch (ClassNotFoundException |
IllegalAccessException |
InstantiationException |
java.sql.SQLException e) {
LOGGER.log(Level.SEVERE, e.getMessage());
}
}
}

To figure out if your problem is Java-related or not, you could try to telnet to the SQL server.
$ telnet localhost 3306
If you are not allowed to connect, you will receive an error message similar to yours.
To allow access, your system administrator needs to run something like this:
$ mysql -u root -p
Enter password:
mysql> use mysql
mysql> GRANT ALL ON *.* to root#'localhost' IDENTIFIED BY 'your-root-password';
mysql> FLUSH PRIVILEGES;
About your concern (SQL server disallowing access from localhost): access should only allowed, if it is really necessary. So if you have only remote SQL clients, there is no need to allow access from the host localhost.

Related

Create connection to SQL database using JDBC Driver- SQLException [duplicate]

I am trying to connect to my database by JDBC on localhost. Connecting via windows authentication is no problem, but I want to connect via SQL authentication. Therefore, I created a login and a user corresponding to this login in my database. I can normally log in SSMS:
My connection string for JDBC:
jdbc:sqlserver://localhost:1433;databaseName=TestBazyDanych;user=doszke;password=doszke123
Thrown exception:
com.microsoft.sqlserver.jdbc.SQLServerException: Login failed for user 'doszke'. ClientConnectionId:b7005fe3-904d-40c5-a89e-af0cb61250d6
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:254)
at com.microsoft.sqlserver.jdbc.TDSTokenHandler.onEOF(tdsparser.java:258)
at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:104)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.sendLogon(SQLServerConnection.java:4772)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.logon(SQLServerConnection.java:3581)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.access$000(SQLServerConnection.java:81)
at com.microsoft.sqlserver.jdbc.SQLServerConnection$LogonCommand.doExecute(SQLServerConnection.java:3541)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7240)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2869)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:2395)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:2042)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:1889)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1120)
at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:700)
at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:677)
at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:251)
at main.Main.main(Main.java:38)
The username and password are the same, as those used for loging to SSMS.
Here my class code:
package main;
import java.sql.*;
public class Main {
private static ResultSet selectStan(Connection connection) throws SQLException {
String sql_stmt = "SELECT * FROM STAN;";
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery(sql_stmt);
System.out.println("Select executed");
return result;
}
public static void main(String[] args) {
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String userName = "doszke";
String password = "doszke123";
String url = "jdbc:sqlserver://localhost:1433;databaseName=TestBazyDanych;user=doszke;password=doszke123";
try (Connection con = DriverManager.getConnection(url)) {
if(con != null){
System.out.println("connected");
} else {
System.out.println("unable to connect");
}
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
As Mark Rotteveel pointed out, I was trying to connect to a LocalDB instance with JDBC, which seemed undoable. (ref: here)
However, I installed jTDS and added to my classpath, changed my connection string to
jdbc:jtds:sqlserver://./TestBazyDanych;instance=LOCALDB#EB7165FD;namedPipe=true
create a connection by the use of this connection string, username and password and it worked. The instance pipe number was taken from cmd line via
sqllocaldb i MSSQLLocalDB
There are few things need to check:
Did you create doszke user under the database and SSMS?
Are you able to login with doszke/doszke123 credentials in SSMS?
Please check 1433 port are open or not in your inbound and outbound firewall.
Trying to telnet on localhost 1433. If it's getting failed change below setting:
Go to Configuration tools -> SQL Server Configuration Manager Select SQL Server Network Configuration -> Select protocol in the right side window enable tcp/ip and restart the services in services.

SAP DBTech JDBC: Cannot connect to jdbc:sap://192.168.33.114:39015/ [SAP DBTech JDBC: [2]: general error: SYSTEMDB not connected]

When i am connecting to my sap hana data base so its throwing below exception
but if i am not specifying any Database name then it connecting by default to HEX data base of sap hana.
com.sap.db.jdbc.exceptions.JDBCDriverException: SAP DBTech JDBC: Cannot connect to jdbc:sap://192.168.33.114:39015/ [SAP DBTech JDBC: [2]: general error: SYSTEMDB not connected]
Here is dummy code
import java.sql.Connection;
import java.sql.ResultSet;
public class SapConnection {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Class.forName("com.sap.db.jdbc.Driver");
String url = "jdbc:sap://192.168.33.114:39015/?databaseName=abcd";
String user = "abc";
String password = "xyz";
Connection cn = java.sql.DriverManager.getConnection(url, user, password);
// ... do whatever with the results ...
}
catch (Exception e) {
e.printStackTrace();
}
}
}
When connecting to a MDC tenant DB the port to connect against is not 30..15 but 30..13 as the connection goes against the nameserver process listening on the 30..13 port.
Changing your connection string to
String url = "jdbc:sap://192.168.33.114:39013/?databaseName=abcd";
should make it work.
EDIT
An alternative method to connect is to avoid providing the port numbers altogether and to let HANA figure these details out itself. Just providing the instanceNumber and the databaseName is sufficient in this case.
Example (DB runs on host skullbox.lab.cat5):
> java -jar ngdbc.jar -u <username>,<password> -n skullbox.lab.cat5 -d S20 -i
20
Connected.
| |
-------------------------------
| 2017-08-15 17:04:53.0730000 |
1 rows.
The corresponding JDBC URL would look like this:
jdbc:sap://skullbox.lab.cat5?databaseName=S20&instanceNumber=20

How can the java SQL connector be used to connect to a database on a different computer

I have a simple database on my computer for testing purposed, and I'm trying to retrieve some information from the database, from my laptop. So I want my laptop to make a request to see the information inside my computers MySQL database. Below shows the java code I'm trying to run on my laptop to collect the first entry in the students table, which is located on my computer.
I have MySQL workbench installed on both my laptop and computer, is it necessary to be on both machines if the computer will store the data and the laptop only extracts data.
What I've learnt so far from researching is that the public ip should be used in the url instead of the ip for the computer, so I added that in but I received a CommunicationsException along with "Connection timed out" in the stack trace. I've read through this answer and this answer to a similar problem, but I'm having difficulty understanding both solutions, could someone refer me to a beginners guide to remotely accessing data from a database using MySQL.
public class TestRemote{
//JDBC variables
Connection connection;
Statement statement;
ResultSet resultSet;
//String variables
String url;
String user;
String password;
public static void main(String[] args) {
TestRemote sql = new TestRemote();
ArrayList<String> firstnames = sql.getColumn("students", "firstname", "studentid=4");
System.out.println(firstnames.get(0));
}
// Constructor
public TestRemote()
{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.out.println("couldnt find class");
}
url = "jdbc:mysql://81.159.3.167:3306/test"; //?autoReconnect=true&useSSL=false";
user = "user";
password = "pass123";
connection = null;
statement = null;
resultSet = null;
}
private void closeConnection(){
try{
if(connection != null)
connection.close();
if(statement != null)
statement.close();
if(resultSet != null)
resultSet.close();
connection=null; resultSet=null; statement=null;
}catch(Exception e){
e.printStackTrace();
}
}
public ArrayList<String> getColumn(String table, String column, String where) {
ArrayList<String> resultsArray = new ArrayList<String>();
try {
connection = DriverManager.getConnection(url, user, password);
statement = connection.createStatement();
if(!where.equals(""))
resultSet = statement.executeQuery("SELECT "+column+" FROM "+table + " WHERE "+where);
else
resultSet = statement.executeQuery("SELECT "+column+" FROM "+table);
while(resultSet.next()) {
String val = resultSet.getString(1);
if(val==null)
resultsArray.add("");
else
resultsArray.add(val);
}
//resultsArray = (ArrayList<String>) resultSet.getArray(column);
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Model.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
closeConnection();
return resultsArray;
}
}
Your Java code is probably fine. But the question is, is on the other machine a MySQL server running and listening on port 3306 on the public IP? By default it should only listen on localhost, so you need to change your MySQL installation so that it listens to the public IP. Also make sure that no Firewall is blocking the access. Try connecting with the Workbench on the Laptop to reach the MySQL server on the other box. If you got this running, try your Java code again.
I have MySQL workbench installed on both my laptop and computer, is it
necessary to be on both machines if the computer will store the data
and the laptop only extracts data.
No what you call the "Computer" is your server here. it doesn't need mysql workbench. it only needs mysql server
the public ip should be used in the url instead of the ip for the
computer
A database should almost never be exposed on the public IP address. If you are having both computers on the LAN, the private network IP is what the server should listen on and that's what you should use on the connection string.
CommunicationsException along with "Connection timed out" in the stack
trace
Because the server is not running, not listening on that ip:port or firewalled to drop packets.

Unable to connect to Remedy AR System server

I am sure that I am using the correct connection information:
import com.bmc.arsys.api.ARException;
import com.bmc.arsys.api.ARServerUser;
/**
*
* A class to automate deletion of BMC Remedy incidents after deploying or decommissioning servers
*
*/
#SuppressWarnings("unused")
public class BMCIncidentDelete {
public static void main(String[] args) {
/*
* Authentication information
*/
String host = "";
String server = "";
String user = "";
String pass = "";
ARServerUser ctx = new ARServerUser();
ctx.setServer(host);
// ctx.setServer(server);
ctx.setUser(user);
ctx.setPassword(pass);
ctx.setPort(8080);
/*
* Verify user or print stack trace if not possible
*/
try {
ctx.verifyUser();
System.out.println("Connection verified!");
} catch (ARException e) {
System.out.println(e.getMessage().toString());
}
}
}
Unfortunately, I get the following error:
ERROR (90): Cannot establish a network connection to the AR System server; Connection refused: connect
Anyone with experience with the AR System API see this issue before? https://communities.bmc.com/docs/DOC-17514
This error (Connection refused) indicates that the Remedy server is not reachable from your server on the host and port provided. You can validate by using telnet, substituting the hostname for $host:
$ telnet $host 8080
A successful connection should say "Connected to host.", but based on your question you will likely see "Connection refused". Double check the hostname and port number of the Remedy server, and if necessary check that there are no firewalls, etc. between you and the server.

JSch SSH connection throws NPE when initializing reverse tunnel

When I'm adding a reverse tunnel to a com.jcraft.jsch.Session object, the connection initialization fails with the following stacktrace:
com.jcraft.jsch.JSchException: java.lang.NullPointerException
at com.jcraft.jsch.Session._setPortForwardingR(Session.java:2165)
at com.jcraft.jsch.Session.setPortForwardingR(Session.java:1937)
at com.jcraft.jsch.Session.setPortForwardingR(Session.java:1883)
at com.project.client.handlers.SshClientHandler.<init>(SshClientHandler.java:41)
at com.project.client.pcConnection.init(SdConnection.java:30)
at Sdclient.main(Unknown Source)
Caused by: java.lang.NullPointerException
at com.jcraft.jsch.Packet.padding(Packet.java:58)
at com.jcraft.jsch.Session.encode(Session.java:892)
at com.jcraft.jsch.Session._write(Session.java:1362)
at com.jcraft.jsch.Session.write(Session.java:1357)
at com.jcraft.jsch.Session._setPortForwardingR(Session.java:2160)
... 5 more
The full code there is
private static JSch sshConn = null;
private Session sshSession;
public SshClientHandler(int _sshLocalSp, int _sshRemoteSp) {
JSch.setLogger(new JSCHLogger());
sshConn = new JSch();
try {
createTemporarySshFiles();
sshConn.setKnownHosts(GeneralMethods.getPreference(PcPreferencesEnum.SSH_KNOWN_HOSTS_FILE));
sshConn.addIdentity(GeneralMethods.getPreference(PcPreferencesEnum.SSHC_PRIVATE_KEY_FILE), GeneralMethods.getPreference(PcPreferencesEnum.SSHC_PUBLIC_KEY_FILE), "".getBytes());
sshSession = sshConn.getSession(GeneralMethods.getPropValue("pcclient.id"), "sshserver.project.com", 22);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
sshSession.setConfig(config);
sshSession.setTimeout(15000);
sshSession.setPassword("");
//sshSession.setPortForwardingR("50000:localhost:22");
sshSession.setPortForwardingR(50000, "127.0.0.1", 22);
sshSession.connect();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The connection estabishes successfully w/ publickey authentication when I remove the line
sshSession.setPortForwardingR(50000, "127.0.0.1", 22);
The SSH user has the right to connect to the local port 50000 on the remote machine. Here is a snippet from it's authorized_keys
no-pty,permitopen="localhost:50000",command="/bin/echo not-allowed-to-do-this",no-X11-forwarding ssh-rsa AAAA[...]
I switched arguments for setPortForwardingR back and forth, as - for example - some documents I found online use the remote machine as second argument, some use localhost, but with no success.
Watching auth.log on the remote server indicates that the connection is not even initiated. The NullPointerException gets thrown on the actual line of the setPortForwardingR call. I ensured that my local SSH server is running on the local port 22, and I can connect manually to it. I tried different ports (to my local MySQL server, e.g.), but it always fails with the same stacktrace.
I'm using jsch-0.1.52.jar.
You have to call the .setPortForwardingR() only after the .connect().
See for example:
http://www.jcraft.com/jsch/examples/Daemon.java.html

Categories