Tomcat cannot create TCPS Oracle JDBC connection - oracle

I'm using database connection through JDBC in tomcat.
Our environment is Tomcat 7 + JDK 8 and Oracle 12c.
As I can only connect to Oracle database through TCPS (and which we are using Oracle's wallet), so I have to modify my current Tomcat server.xml to create JDBC connection to Oracle.
My updated configuration snippet
<Resource auth="Container" driverClassName="oracle.jdbc.driver.OracleDriver"
initialSize="10"
jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx(threshold=10000)"
jmxEnabled="true" logAbandoned="true" maxActive="100" maxIdle="100"
maxWait="10000"
name="jdbc/jndiconnection" password="XXXXXX" removeAbandoned="true"
type="javax.sql.DataSource" url=""jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=hostname)(PORT=1234))(CONNECT_DATA=(SERVICE_NAME=servicename)))"
username="XXXXXXXX" validationInterval="30000" validationQuery="SELECT 1 FROM DUAL" />
I added truststore/trusttypey/keystore/keytype as parameters,however I got error:
Caused by: oracle.net.ns.NetException: Unable to initialize ssl context.
at oracle.net.nt.CustomSSLSocketFactory.getSSLSocketFactory(CustomSSLSocketFactory.java:296)
at oracle.net.nt.TcpsNTAdapter.connect(TcpsNTAdapter.java:117)
at oracle.net.nt.ConnOption.connect(ConnOption.java:133)
at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:370)
... 73 more
Caused by: oracle.net.ns.NetException: Unable to initialize the key store.
at oracle.net.nt.CustomSSLSocketFactory.getKeyManagerArray(CustomSSLSocketFactory.java:369)
at oracle.net.nt.CustomSSLSocketFactory.getSSLSocketFactory(CustomSSLSocketFactory.java:279)
... 76 more
Caused by: java.security.KeyStoreException: SSO not found
at java.security.KeyStore.getInstance(KeyStore.java:851)
at oracle.net.nt.CustomSSLSocketFactory.getKeyManagerArray(CustomSSLSocketFactory.java:357)
... 77 more
Caused by: java.security.NoSuchAlgorithmException: SSO KeyStore not available
at sun.security.jca.GetInstance.getInstance(GetInstance.java:159)
at java.security.Security.getImpl(Security.java:695)
at java.security.KeyStore.getInstance(KeyStore.java:848)
... 78 more
Then I followed the instruction from : https://sysapp.wordpress.com/2010/08/31/how-to-oracle-wallet-with-jdbc-thin-driver-datasource-tomcat/
However in the article it is using PROTOCAL as TCP but not TCPS.
<Resource
name="jdbc/confluence"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:/#mywallet"
connectionProperties=”oracle.net.wallet_location=/opt/wallet"/>
Then I got error:
Caused by: oracle.net.ns.NetException: The method specified in wallet_location is not supported. Location: /opt/wallet
at oracle.net.nt.CustomSSLSocketFactory.getSSLSocketFactory(CustomSSLSocketFactory.java:219)
at oracle.net.nt.TcpsNTAdapter.connect(TcpsNTAdapter.java:117)
at oracle.net.nt.ConnOption.connect(ConnOption.java:133)
at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:370)
... 73 more
I have written Java sample code to connect through TCPS and the connection works fine.
Did I missed some key points in the configuration file? And is there any other way to create Oracle's TCPS connection through JDBC?

”oracle.net.wallet_location=/opt/wallet"
That's not what the property is supposed to be. It is supposed to be :
(SOURCE=(METHOD=file)(METHOD_DATA=(DIRECTORY=/opt/wallet)))
The error message you get is because it cannot find a "METHOD=" in the one you provided.

There are a few steps that you need to follow.
(1) Make sure you have oraclepki.jar, osdt_core.jar, osdt_cert.jar in the classpath
(2) Also, specify the location of cwallet.sso file through the following system property. You can create a setenv.sh and add required system properties.
Also, enable another system property as shown here.
export JAVA_OPTS="$CATALINA_OPTS -Doracle.net.wallet_location='(SOURCE=(METHOD=file)(METHOD_DATA=(DIRECTORY=/test/wallet/)))'"
export JAVA_OPTS="$CATALINA_OPTS -Doracle.net.ssl_server_dn_match=true"
(3) Make sure you have the certificate information in the URL as shown here.
Please copy the 'security' part of the URL from your certificate.
(description=
(address=(protocol=tcps)(port=1522)(host=myorclhostname))
(connect_data=(service_name=myorcldb))
(security=(ssl_server_cert_dn=
"CN=CMAN, O=Oracle Database , C=US"))
)
(4) You need to activate oracle PKI provider. To statically enable it:
Change java.security file of JRE (JRE_HOME/jre/lib/security/java.security):
security.provider.7=oracle.security.pki.OraclePKIProvider
Refer to "SSL with JDBC driver" for more details.

Related

Why does Test Connection fail in Wildfly 20 Using SQL Anywhere sajdbc4 driver?

I had Wildfly 10 running previously and have just upgraded to Wildfly 20 (under Ubuntu 20). My configuration from Wildfly 10 no longer works when it comes to getting the Sybase SQL Anywhere 17 sajdbc4 driver working. When I "Test Connection" it fails. I am using the same configuration and testing against the exact same (SQL Anywhere High Availability) database server.
"Test Connection" on the following Datasource triggers an "Invalid ODBC handle" error:
<datasource jndi-name="java:jboss/datasources/TestDB" pool-name="TestDB" spy="true" tracking="true" enlistment-trace="true">
<connection-url>jdbc:sqlanywhere:Host=192.168.1.45:19000,192.168.1.45:19001;ServerName=TestDB</connection-url>
<driver>sajdbc4.jar</driver>
<security>
<user-name>...</user-name>
<password>...</password>
</security>
</datasource>
Connection is not valid
Caused by: java.sql.SQLException: Invalid ODBC handle
at deployment.sajdbc4.jar//sap.jdbc4.sqlanywhere.IDriver.makeODBCConnection(Native Method)
at deployment.sajdbc4.jar//sap.jdbc4.sqlanywhere.IDriver.connect(IDriver.java:809)
at org.jboss.ironjacamar.jdbcadapters#1.4.22.Final//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.createLocalManagedConnection(LocalManagedConnectionFactory.java:321)
... 35 more
How I set this up:
I used the console to Deploy the sajdbc4.jar and that appears to work fine. I see no errors and sajdbc4 shows up as Deployed in the console and it also shows up as a JDBC Driver in the Subsystems. Here is what was created in standalone.xml after using the console:
deployment name="sajdbc4.jar" runtime-name="sajdbc4.jar">
content sha1="b690ff7a8ba1a3c2e8dd5079138b7970d969c2b9"/>
/deployment>
(I had to drop the leading angle brackets to get the previous lines to show - even when marked as Code!)
Next I had to ensure that the java.library.path and classpath included the path to the sajdbc4.jar and its support files so Wildfly can find them. To do so I added the "HACK" to the following in standalone.conf:
if [ "x$JAVA_OPTS" = "x" ]; then
JAVA_OPTS="-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true"
JAVA_OPTS="$JAVA_OPTS -Djboss.modules.system.pkgs=$JBOSS_MODULES_SYSTEM_PKGS -Djava.awt.headless=true"
# ADDED FOLLOWING HACK
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=/opt/wildfly-20.0.1.Final/modules/system/layers/base/com/sybase/main -cp .:/opt/wildfly-20.0.1.Final/modules/system/layers/base/com/sybase/main/sajdbc4.jar"
echo "Java Properties Next:"
java -XshowSettings:properties -version
else
echo "JAVA_OPTS already set in environment; overriding default settings with values: $JAVA_OPTS"
fi
Finally, I added the datasource block shown at the top. After starting Wildfly TestDB shows up as a Datasource in the Datasources Subsystem but when I Test Connection I get the "Invalid ODBC handle" error.
I feel confident that the driver and all its support files are "working" because I have a very simple Java test app that just makes a connection to TestDB, fetches from a table and displays the rows. Note that it uses the exact same java.library.path and classpath as I set in standalone.conf:
cd $HOME/Desktop
export LD_LIBRARY_PATH=/opt/wildfly-20.0.1.Final/modules/system/layers/base/com/sybase/main
export CLASSPATH=.:/opt/wildfly-20.0.1.Final/modules/system/layers/base/com/sybase/main/sajdbc4.jar
java sajdbc4DriverTest.java
Note that server.log shows no errors and in fact shows lines like:
[org.jboss.as.server.deployment] (MSC service thread 1-3) WFLYSRV0027: Starting deployment of "sajdbc4.jar" (runtime-name: "sajdbc4.jar")
...
[org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-4) WFLYJCA0005: Deploying non-JDBC-compliant driver class sap.jdbc4.sqlanywhere.IDriver (version 4.0)
[org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-3) WFLYJCA0018: Started Driver service with driver-name = sajdbc4.jar
[org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-3) WFLYJCA0001: Bound data source [java:jboss/datasources/TestDB]
...
[org.jboss.as.server] (Controller Boot Thread) WFLYSRV0010: Deployed "sajdbc4.jar" (runtime-name : "sajdbc4.jar")
Note that my connection string is for connecting to a SQL Anywhere High Availability system (hence the two URLS). In Wildfly 20 I see that there is now a new "HA URL Separator" field in the console's Datasource definition page. I tried setting that to a comma and that just changed the Test Connection error to "Unable to create connection from URL":
2020-08-25 11:45:08,378 WARN [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool] (External Management Request Threads -- 1) IJ000604: Throwable while attempting to get a new connection: null: javax.resource.ResourceException: IJ031085: Unable to create connection from URL: jdbc:sqlanywhere:Host=192.168.1.45:19000,192.168.1.45:19001;ServerName=TestDB
at org.jboss.ironjacamar.jdbcadapters#1.4.22.Final//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.getHALocalManagedConnection(LocalManagedConnectionFactory.java:381)
How do I get "Test Connection" to work?
Thank you in advance.
The problem turned out to be related to the fact that I was running Wildfly as a service and apparently my efforts above to set the java.library.path is failing. I know the reason for the error but I do not know how to set the path when running as a service.

Cannot create PoolableConnectionFactory (IO 오류: Invalid number format for port number)

<Context>
<Resource name="jdbc/myoracle"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#localhost:xe"
username="basic"
password="basic"
maxTotal="10"
maxIdle="5"
maxWaitMillis="1" />
</Context>
this is my context.xml, and when I load the main.jsp, it shows me this error msg. oracle username and password are basic, basic. I dont understand why it's not working
Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (IO 오류: Invalid number format for port number)
Replace "xe" with your port number in the url-field. It should look like i.e. jdbc:oracle:thin:#localhost:1521 or jdbc:oracle:thin:#localhost:1521:xe

OpenAM with OpenDJ - NameNotFoundException: ldap/idp/userDN - when starting up JBoss

I'm using OpenAM, with its embedded OpenDJ as the LDAP service, to protect my web application running on JBoss 7.
When I start my JBoss I get this error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ldapUserDN'
...
Caused by: javax.naming.NameNotFoundException: ldap/idp/userDN -- service jboss.naming.context.java.ldap.idp.userDN
So apparently Spring is looking for the JNDI node ldap/idp/userDN. But the jboss configuration file that I got with the project has these entries:
<simple name="ldap/opendj/url" value="ldap://localhost:50389"/>
<simple name="ldap/opendj/userDN" value="cn=Directory Manager"/>
<simple name="ldap/opendj/password" value="mypassword"/>
<simple name="ldap/opendj/baseDN" value="dc=opensso,dc=java,dc=net"/>
And these properties are added to my JNDI tree on JBoss.
If I change these to "ldap/idp/userDN", for instance, then I get rid of the error, but I was wondering if there's anywhere, where "ldap/opendj/userDN" should be mapped to "ldap/idp/userDN", that I've missed.
If you're using Spring LDAP, the actual configuration of the ldap-context-source goes in the a spring config file, and might look like this:
<jee:jndi-lookup jndi-name="ldap/idp/url" id="ldapUrl"/>
<jee:jndi-lookup jndi-name="ldap/idp/userDN" id="ldapUserDN"/>
<jee:jndi-lookup jndi-name="ldap/idp/password" id="ldapPassword"/>
<jee:jndi-lookup jndi-name="ldap/idp/baseDN" id="ldapBaseDN"/>
<ldap:context-source url="#{ldapUrl}"
username="#{ldapUserDN}"
password="#{ldapPassword}"
base="#{ldapBaseDN}"
native-pooling="true"/>
So the jndi entries in your jboss config file should match the ones above.

How to access read-only Derby databases over a network client connection?

I'm trying to open a read-only Derby database over a network client connection (using ij / derbyclient.jar).
I have created a read-only database:
jar cMf sample.jar sample
The Derby Network Server is started.
I have tried the following connection URLs:
connect 'jdbc:derby:jar://localhost:1527/sample.jar';
connect 'jdbc:derby:jar://localhost:1527/(sample.jar)sample';
connect 'jdbc:derby://localhost:1527/jar:(sample.jar)sample';
But none of the above URLs work.
The only URL that works is:
connect 'jdbc:derby:jar:(sample.jar)sample';
It appears that read-only Derby databases can only be opened in embedded mode. Is this true ?
Solved:
After checking the "derby.log", the problem was that the read-only database needs to be able to create a temporary file.
derby.log:
java.sql.SQLException: Failed to start database 'jar:(sample.jar)sample' with class loader sun.misc.Launcher$AppClassLoader#1d450337, see the next exception for details.
...
Caused by: java.sql.SQLException: Failed to start database 'jar:(sample.jar)sample' with class loader sun.misc.Launcher$AppClassLoader#1d450337, see the next exception for details.
...
Caused by: java.sql.SQLException: Java exception: 'Unable to create temporary file: java.lang.SecurityException'.
...
Caused by: java.lang.SecurityException: Unable to create temporary file
The solution is to define a temporary directory for the database. This can be done with the "derby.storage.tempDirectory" property:
System-wide in "derby.properties":
derby.storage.tempDirectory=c:/temp
Database-wide
CallableStatement cs =
conn.prepareCall("CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(?, ?)");
cs.setString(1, "derby.storage.tempDirectory");
cs.setString(2, "c:/temp");
cs.execute();
cs.close();
The network URL is:
connect 'jdbc:derby://localhost:1527/jar:(sample.jar)sample';

Tomcat 6/7 JNDI with multiple datasources

When there are more than one <Resource> elements in context.xml and more than one <resource-ref> elements in web.xml, my application begins to throw
TNS:no appropriate service handler found
and
ORA-01017: invalid username/password; logon denied
However, if there is only one of the data sources in JNDI, meaning the other one use regular JDBC data source, the application runs like a charm
Both data sources come from same db URL but use different schema.
My guess is that it may be caused by the same database URL of each resources with different username/password(schema). But tomcat should be capable of handling such situation, so my reasoning is that there maybe some configuration I missed?
Another interesting finding is:
When I use jdbc url jdbc:oracle:thin:#myhost:1521:orcl with SQL Developer to setup a connection, sometimes it connects without issue, but sometimes it gets rejected with the same issue: appropriate service handler found while this web application is active at the same time. However, the same JDBC URL works fine with another Spring application with regular JDBC connection(not JNDI). So what is the trick?
Here are the details of current config:
In Context.xml
<Resource name="jdbc/app_A" auth="Container" type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver" url="jdbc:oracle:thin:#myhost:1521:orcl"
username="usernameA" password="passwordA" maxActive="20" maxIdle="10" maxWait="-1" />
<Resource name="jdbc/app_B" auth="Container" type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver" url="jdbc:oracle:thin:#myhost:1521:orcl"
username="usernameB" password="usernameB" maxActive="20" maxIdle="10" maxWait="-1" />
In Web.xml of the application:
<resource-ref>
<description>Oracle Datasource for app_A</description>
<res-ref-name>jdbc/app_A</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<description>Oracle Datasource for app_B</description>
<res-ref-name>jdbc/app_B</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
In ApplicationContext.xml
<jee:jndi-lookup id="dataSource1" jndi-name="java:comp/env/jdbc/app_A" resource-ref="true" />
<jee:jndi-lookup id="dataSource2" jndi-name="java:comp/env/jdbc/app_B" resource-ref="true" />
And finally I get exception piled up like this:
Jan 31, 2013 3:36:55 PM org.apache.catalina.core.NamingContextListener addResource
WARNING: Failed to register in JMX: javax.naming.NamingException: ORA-01017: invalid username/password; logon denied
Jan 31, 2013 3:36:56 PM org.apache.naming.NamingContext lookup
WARNING: Unexpected exception resolving reference
java.sql.SQLException: Listener refused the connection with the following error:
ORA-12519, TNS:no appropriate service handler found
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:412)
at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:531)
at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:221)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:503)
at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:278)
at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:182)
at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:699)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:631)
at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:485)
at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:143)
at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:116)
at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:103)
at org.apache.tomcat.jdbc.pool.DataSourceFactory.createDataSource(DataSourceFactory.java:539)
at org.apache.tomcat.jdbc.pool.DataSourceFactory.getObjectInstance(DataSourceFactory.java:237)
at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:143)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)
at org.apache.naming.NamingContext.lookup(NamingContext.java:843)
at org.apache.naming.NamingContext.lookup(NamingContext.java:154)
at org.apache.naming.NamingContext.lookup(NamingContext.java:831)
at org.apache.naming.NamingContext.lookup(NamingContext.java:168)
at org.apache.catalina.core.NamingContextListener.addResource(NamingContextListener.java:1061)
at org.apache.catalina.core.NamingContextListener.createNamingContext(NamingContextListener.java:671)
at org.apache.catalina.core.NamingContextListener.lifecycleEvent(NamingContextListener.java:270)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5173)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:618)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1100)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1618)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: oracle.net.ns.NetException: Listener refused the connection with the following error:
ORA-12519, TNS:no appropriate service handler found
at oracle.net.ns.NSProtocol.connect(NSProtocol.java:385)
at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1042)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:301)
... 38 more
Jan 31, 2013 3:36:56 PM org.apache.catalina.core.NamingContextListener addResource
WARNING: Failed to register in JMX: javax.naming.NamingException: Listener refused the connection with the following error:
ORA-12519, TNS:no appropriate service handler found
Jan 31, 2013 3:36:56 PM org.apache.naming.NamingContext lookup
WARNING: Unexpected exception resolving reference
java.sql.SQLException: Listener refused the connection with the following error:
ORA-12519, TNS:no appropriate service handler found
Really not sure why the no appropriate service handler found error pops up, it seems the connection is not accepted/understood by orcl Listener.
Here is what I insert into persisntence.xml
<persistence-unit name="persistenceUnit1">
....
<jta-data-source>jdbc/app_A</jta-data-source>
....
</persistence-unit>
<persistence-unit name="persistenceUnit2">
....
<jta-data-source>jdbc/app_B</jta-data-source>
....
</persistence-unit>
ORA-12519, TNS:no appropriate service handler found error might be the result of using an old-style JDBC connection string. According to chapter 8 Data Sources and URLs of Oracle 11.1 JDBC Developer's Guide and Reference, connection string format is following:
jdbc:oracle:thin:#//host_name:port_number/service_name
There's also a note saying "Starting Oracle Database 10g, Oracle Service IDs are not supported". So the syntax you're using must have been suitable for Oracle 9i. It might work on newer versions, but that's not guaranteed.
So consider changing the format of your JDBC connection strings to follow the format suggested in the guide.
Also, for Oracle 9i onwards you should use oracle.jdbc.OracleDriver rather than oracle.jdbc.driver.OracleDriver as Oracle have stated that oracle.jdbc.driver.OracleDriver is deprecated and support for this driver class will be discontinued.

Resources