How to connect to Sybase ASE using JDBC driver and SSL connection - java

I'm trying to establish an SSL connection to a Sybase ASE 15.7 using JDBC driver with no luck.
I tried the following options:
Using JTDS 1.25 driver (jtds-1.2.5.jar)
With the following connection string: jdbc:jtds:sybase://host:port;databaseName=dbname;ssl=request
I got Network error IOException: Connection refused
Using Jconnect 4 (jconn4.jar)
with the following connection string:
jdbc:sybase:Tds:host:port/dbname?ENABLE_SSL=true
I got java.sql.SQLException: JZ00L: Login failed. Examine the SQLWarnings chained to this exception for the reason(s)
...
java.sql.SQLException: I/O Error: DB server closed connection.
I checked the Sybase log see the following error:
kernel SSL or Crypto Error Message: 'The SSL handshake failed. Root error: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol'.
it looks like the Sybase server expects SSL connection but the java client still not using SSL (although connection string property marks ssl=true).
tried searching Sybase documentation with not much luck, neither for this error nor for SSL with JConnect.
Any answer will be much appreciated - i'm flexible with the type of driver and the configuration.
Thanks

After much investigation, I found a solution. 2 actually.
Using trust all certificate JDBC connection string parameter:
if you don't mind to trust all certificates (do this only if you entirely trust the network you're working in, especially not anything going on the public internet), you may add a connection string indicating the SSLSocketFactory creating the connection to trust all certificates. The connection string will look as follows: jdbc:sybase:Tds:host:port/dbname?ENABLE_SSL=true&SSL_TRUST_ALL_CERTS=true
Using the sybase certificate:
the certificate needs to be imported to the java application trust store.
in case you're not working with a designated trust store, it may be imported to the Java default trust store found under $JAVA_HOME\jreX\lib\security\cacerts. The certificate may be imported using keytool as explained here.

Although zuckermanori's answer provides some key details, adding more steps below which are required -
Provide right jdbc jar which supports ssl while creating spark session. I was earlier using jconn3-6.0.0.jar which doesnt support ssl. Later, I used jconnect-16.0_SP02.jar which worked fine.
Example pyspark command to pass the driver jar would be -
pyspark --jars
/path/to/your/jdbc/driver/jar
Provide additional java args as follows in the same command to provide trust store location(which has the certificates) -
--conf spark.driver.extraJavaOptions="-Djavax.net.ssl.trustStore=/path/to/truststore -Djavax.net.ssl.trustStorePassword=your_truststore_password"​
​
3. Use right string to load driver in option. Earlier I was using 'com.sybase.jdbc4.jdbc.SybDriver' which didnt work. Then below worked for me -
.option("driver", "com.sybase.jdbc4.jdbc.SybDriver")
​
4. Use right connection string to provide additional ssl options as per the driver. E.g. -
.option("url", "jdbc:sybase:Tds:host_name:ssl_port/database_name?ENABLE_SSL=true&SSL_TRUST_ALL_CERTS=true&ssl=request")
Additional options required -
.option("ssl", True).option("sslmode", "require")
To sum it up, this is how your pyspark command should look like(if you are using yarn mode, then truststore should be accessible on all nodes. Below is the example of spark local mode) -
pyspark --jars /path/to/your/jdbc/driver/jar --conf spark.driver.extraJavaOptions="-Djavax.net.ssl.trustStore=/path/to/truststore -Djavax.net.ssl.trustStorePassword=your_truststore_password"​ --master local
And this is how your jdbc read look like -
spark.read.format("jdbc").option("url", "jdbc:sybase:Tds:host_name:ssl_port/database_name?ENABLE_SSL=true&SSL_TRUST_ALL_CERTS=true&ssl=request").option("driver", "com.sybase.jdbc4.jdbc.SybDriver").option("ssl", True).option("sslmode", "require").option("user", "your_user_name").option("password", "your_password").option("dbtable", "db.dbo.table_name").load().show(5)

Related

Connecting to SQL Server 13 with Java 17

I'm trying to connect to SQL Server 13 in a Springboot 2.7.5 after upgrading java to version 17
This is the key points the stacktrace when the application starts up and attempts to connect
Failed to obtain JDBC Connection; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: \"Certificates do not conform to algorithm constraints\". ClientConnectionId:3dd8afba-ccaf-451e-a8f1-5687b548ee3b\
java.security.cert.CertPathValidatorException: Algorithm constraints check failed on keysize limits: RSA 1024 bit key used with certificate: CN={SERVER_URL}
I've tried to add encrypt=true and trustServerCertificate=true to the connection url and still get the same issue.
Looking at the SQL version compatbiity list: https://learn.microsoft.com/en-us/sql/connect/jdbc/microsoft-jdbc-driver-for-sql-server-support-matrix?view=sql-server-ver16
I should be able to use com.microsoft.sqlserver:mssql-jdbc:11.2.0.jre17 also downgrading major versions also get the same result.
I'm able to connect the server using the same creds using intellij thats configured to use java 17 and using driver 11.2.1
I figured out the issue, since RHEL8 it has removed weak crypto algorithms. So, I had to update the Docker file to have RUN update-crypto-policies --set LEGACY, see also https://access.redhat.com/articles/3642912

How do I fix this SSL error when making a SQL request from a jetty server

I'm in the process of upgrading a java application. Originally, the application was built with jdk 8 and the server was jetty 9. Since upgrading to jetty 10 and jdk 11, I'm running into an issue when trying to make requests to our sql datasource. When the application attempts to query the database, it fails with the error:
java.sql.SQLException: Cannot create PoolableConnectionFactory
(The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target". ClientConnectionId:redacted)
at org.apache.commons.dbcp2.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:653)
at org.apache.commons.dbcp2.BasicDataSource.createDataSource(BasicDataSource.java:531)
at org.apache.commons.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:731)
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:181)
I understand that either the jetty server or the sql server are missing a security certificate, but I'm not sure what to do about it. I read through the documentation here:
https://www.eclipse.org/jetty/documentation/jetty-10/operations-guide/index.html#og-keystore but the sql server is a remote server that I don't have admin access to, so I'm not sure I can even do what they describe. Do I need to get the certificate and key from the sql server somehow? What am I missing here?
Your program is failing because it is trying to connect to an "unsecure" location, you have to connect to the destination manually, get the certificate/or certificates, install them into your local keystore, and restart your program.
Some instructions on how to do that can be gound here.
https://www.thesslstore.com/knowledgebase/ssl-install/jetty-java-http-servlet-webserver-ssl-installation/
If you connect to multiple locations, yes, you need to have an entry for each, unless that they have a wildcard certificate (a certificate that applies for all of them).
Alternatively! (not sure but handy) you can start the connection without enforcing certificate validation, in this case the connection will happen no matter is the destination is actually false, this is a security issue, but there are cases when this is needed, in fact, this happens a lot when you run balancers where they validate the certs for you and you connect in http to them, automatically the validation is getting dropped since most of those balancers won't fail to connect even if the validation fails, but this is a different topic!
Cheers.

Nifi and Postgresql with certificate: how to set client certificate and key?

I have a NIFI image running in openshift and a postgres in the cloud "owned" by another department.
They sent to us a certificate(".crt") and a key(".key"), since the log-in is made trough client certificate, instead of username and password. I have succeeded to log-in in pgAdmin 4, but not to connect the NIFI to the Postgres with certificate and key.
I have uploaded the certificate and the key to the image (using a secret and mounting it) so if I go to the pod terminal I can access it.
But, when I pass to a DBCPConnectionPoll service the connection string bellow and activates an ExecuteSQL processor, I receive an exception that the certificate is not valid, as follows:
ERROR
ExecuteSQL[id=...] Unable to execute SQL query <...>;
due to java.sql.SQLException: Cannot create a PoolableConnectionFactory (FATAL: connection requires a valid client certificate).
No FlowFile to route to failure: org.apache.nifi.processor.exception.ProcessException: java.sql.SQLException: Cannot create a PoolableConnectionFactory (FATAL: connection requires a valid client certificate)
I have tried to pass the certificate in two ways to the DBCPConnectionPoll service:
1) as parameters in the connection string ("database connection url" property:
jdbc:postgresql://<ip>:<port>/<username>?user=<username>&sslTrue&sslcert=/etc/.../mycerts/mycert.der&sslkey=/etc/.../mycerts/mykey.key.pk8
2) adding properties in the service (+ button and the just parameter name and the path as the value) and just passing this as url:
jdbc:postgresql://<ip>:<port>/<username>
Both seems to work generally speaking, since I can connect to another postgres I have which not requires ssl certification.
Some considerations:
1) My assumption here is that the connection string in the NIFI does not know to read properly the file path for the certificate and key.
2) I have converted the certificates a bunch of times to different types that java can receive in order to see if that was the problem, but I still receive the same exception. So it seems that the connection pool just does not "achieve" the files at all. Nevertheless, if some one has a say in this topic, it can be handy, after the main problem is solved. So appreciate some tips here as well.
3) I have also read the NIFI source code and it seems that NIFI uses normally JDBC classes to create the connection pool, so a connection string as I passed would have worked in java code, but somehow doesn't work in NIFI (which is written in java).
4) The jdbc driver and everything else is configured properly, since I can work with a non-secure postgres in NIFI.
Thank you very much.
A co-worker found the 'simple solution' to the problem I asked and I would like to share so it can help others.
What was missing was the property sslmode = require. After including that, the service worked perfectly. Actually, I am not sure why it didn't work with sslmode = prefer, since it is what my pgadmin is using for the same database and there it works perfectly. It seems like we must 'force' nifi to use ssl in this case - see documentation here: https://jdbc.postgresql.org/documentation/head/ssl-client.html.
Moreover, some insights:
It worked with certificate in '.der' and key in '.pk8' formats (didn't have to use trust-store and key-store as needed in other services).
One can add in the 'plus' button the properties and give them the right name as we would do in java code, instead of concatenating every property in the connection string (see second option in the question above).
Make it helps others as well.

Liberty for Java app on Bluemix throws SQLNonTransientException

My Liberty for Java app is throwing the following exception when I attempt to connect with the dashDB Service on Bluemix:
[err] SQLException informationjava.sql.SQLNonTransientException:
[jcc][t4][2030][11211][4.8.86] A communication error occurred during
operations on the connection's underlying socket, socket input stream,
or socket output stream. Error location: T4Agent.sendRequest().
Message: Received fatal alert: handshake_failure. ERRORCODE=-4499,
SQLSTATE=08001 DSRA0010E: SQL State = 08001, Error Code = -4,499
This looks like it may be an SSL failure. Try following the instructions in this technote: http://www-01.ibm.com/support/docview.wss?uid=swg22001150.
You will need to make sure you are using the correct version of Java, the correct JDBC driver, and ensure that your ciphers are set up properly.
This could be due to the dashdb ssl certificate not being available in the truststore used by your liberty application.
You have a few options:
repackage liberty with the truststore
import the certificate programatically at runtime
You can see more information on both of these options here: Add certificate to truststore to enable SSL communication

Exception while connecting to DB2 in java using JDBC

I am trying to connect to a db2 database in Java. Below the driver and the connection string and the driver details i am giving
Class.forName("COM.ibm.db2.jdbc.net.DB2Driver");
String url="jdbc:db2://hostname:portnumber/databasename";
sourceConnection=DriverManager.getConnection(url,"username","password");
But I am getting the below exception
"COM.ibm.db2.jdbc.DB2Exception: [IBM][JDBC Driver] CLI0615E Error receiving from socket, server is not responding. SQLSTATE=08S01"
I also tried changing the connection string to
String url="jdbc:db2:hostname:portnumber/databasename";
Still it is resulting the same exception above while trying to get the Connection.
And i have tried the below option also using JDBC app driver
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver");
DB2DataSource db2ds = new DB2DataSource();
db2ds.setServerName("hostname");
db2ds.setPortNumber(portnumber);
db2ds.setDatabaseName("databasename");
db2ds.setUser("username");
db2ds.setPassword("password");
sourceConnection=db2ds.getConnection();
For the above two connection I used the jar "db2java.jar"
And i have tried using the JCC driver:
Class.forName("com.ibm.db2.jcc.DB2Driver");
String url="jdbc:db2://hostname:portnumber/databasename";
sourceConnection=DriverManager.getConnection(url,"username","password");
For this connection i have added the below jars
1)db2jcc.jar
2)db2jcc_license_cu.jar
This time around I am getting the below error,
"com.ibm.db2.jcc.am.go: [jcc][t4][201][11237][3.57.82] Connection authorization failure occurred.
Reason: Security mechanism not supported. ERRORCODE=-4214, SQLSTATE=28000"
I tried to connect to the same db2 source using "Quest for DB2" tool and the connection was successful.
Am i missing something in the code and is it a problem with DB2 drivers or connection string?
Can someone please guide me.
Thanks in advance.
Cause:
If the DB2® instance where InfoSphere Optim Performance Manager is running has the authentication configuration parameter set to DATA_ENCRYPT, you cannot log in to the web console.
Resolving the problem:
Do the following steps:
On the DB2 instance where Optim Performance Manager is running, set the authentication configuration parameter to SERVER by issuing the following command:
db2 update dbm cfg using authentication server
Restart the DB2 instance and InfoSphere Optim Performance Manager.
For more details visit here.
Your first two attempts were not supposed to work. You're using the JCC driver URL format, so it wouldn't be valid for either "net" or "app" drivers, which are deprecated anyway.
Use the JCC driver (com.ibm.db2.jcc.DB2Driver) and the URL format of "jdbc:db2://hostname:portnumber/databasename" and see this technote for the solution to the "Security mechanism not supported" problem. In short, you need to use a supported JDK.

Categories

Resources