user2393009
user2393009

Reputation: 31

Connect to EMS JMS queue using Spring + SSL

I'm having some issues to create a connection to (and reading from) a Tibco EMS JMS queue, using SSL and mutual authentication with certicates. Here is my Spring config:

<!-- TIBCO Connection Factory Bean -->
<bean id="tibcoConnectionFactory" class="com.tibco.tibjms.TibjmsConnectionFactory">
  <constructor-arg value="ssl://mytibco.server.address:30113" />
  <property name="userName" value="userName" />
  <property name="userPassword" value="${tibcoPwd}" />
  <property name="connAttemptCount" value="10" />
  <property name="connAttemptDelay" value="100" />
  <property name="connAttemptTimeout" value="1000" />
  <property name="reconnAttemptCount" value="10" />
  <property name="reconnAttemptDelay" value="100" />
  <property name="reconnAttemptTimeout" value="1000" />
  <property name="SSLVendor" value="j2se" />
  <property name="SSLEnableVerifyHost" value="false" />
  <property name="SSLEnableVerifyHostName" value="false" />
  <property name="SSLTrace" value="true" />
  <property name="SSLDebugTrace" value="true" />
  <property name="SSLIdentity" value="c:\\cert\\testCert.p12" />
  <property name="SSLPassword" value="*******" />
</bean>

<!-- Spring CachingConnectionFactory Bean -->
<bean id="tibcoJmsConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
  <constructor-arg ref="tibcoConnectionFactory" />
  <property name="reconnectOnException" value="true" />
  <property name="sessionCacheSize" value="10" />
</bean>

When I try to put something on the queue, I receive the following stack trace:

[TIBCO EMS]: [J] [SSL] initializing security with vendor 'j2se'
[TIBCO EMS]: [J] [SSL] client version 5.1.0, security version 3.0.0, SSL initialized with vendor 'j2se'
[TIBCO EMS]: [J] [SSL] WARNING: server verification is disabled, will trust any server.
[TIBCO EMS]: [J] [SSL] reading client identity from byte array, format=AUTO
WARN  [jmsContainer-1] org.springframework.jms.listener.DefaultMessageListenerContainer - Execution of JMS message listener failed
org.springframework.jms.JmsSecurityException: Error occured while reading identity data: Invalid or not supported identity data; nested exception is javax.jms.JMSSecurityException: Error occured while reading identity data: Invalid or not supported identity data
   at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:283)
   at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:168)
   at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:474)
   at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:436)
   ...
   at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:543)
   at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:482)
   at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:451)
   at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:323)
   at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:241)
   at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:982)
   at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:974)
   at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:876)
   at java.lang.Thread.run(Thread.java:662)
Caused by: javax.jms.JMSSecurityException: Error occured while reading identity data: Invalid or not supported identity data
   at com.tibco.tibjms.TibjmsSSL._identityFromStore(TibjmsSSL.java:2670)
   at com.tibco.tibjms.TibjmsSSL.createIdentity(TibjmsSSL.java:2575)
   at com.tibco.tibjms.TibjmsxLinkSSL._initSSL(TibjmsxLinkSSL.java:309)
   at com.tibco.tibjms.TibjmsxLinkSSL.connect(TibjmsxLinkSSL.java:390)
   at com.tibco.tibjms.TibjmsConnection._create(TibjmsConnection.java:1288)
   at com.tibco.tibjms.TibjmsConnection.<init>(TibjmsConnection.java:4115)
   at com.tibco.tibjms.TibjmsxCFImpl._createImpl(TibjmsxCFImpl.java:209)
   at com.tibco.tibjms.TibjmsxCFImpl._createConnection(TibjmsxCFImpl.java:253)
   at com.tibco.tibjms.TibjmsConnectionFactory.createConnection(TibjmsConnectionFactory.java:36)
   at org.springframework.jms.connection.SingleConnectionFactory.doCreateConnection(SingleConnectionFactory.java:343)
   at org.springframework.jms.connection.SingleConnectionFactory.initConnection(SingleConnectionFactory.java:290)
   at org.springframework.jms.connection.SingleConnectionFactory.createConnection(SingleConnectionFactory.java:227)
   at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:184)
   at org.springframework.jms.core.JmsTemplate.access$500(JmsTemplate.java:90)
   at org.springframework.jms.core.JmsTemplate$JmsTemplateResourceFactory.createConnection(JmsTemplate.java:1028)
   at org.springframework.jms.connection.ConnectionFactoryUtils.doGetTransactionalSession(ConnectionFactoryUtils.java:298)
   at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:458)
   ... 12 more

Until now, I can't succeed to resolve the ssl handshake. How to resolve this issue?

Upvotes: 3

Views: 17461

Answers (4)

Nick Holt
Nick Holt

Reputation: 34311

The problem you having is due to a combination of Spring and the fact that com.tibco.tibjms.TibjmsConnectionFactory overloads the setSSLIdentity method, allowing either a byte[] or String to be passed.

This is confusing Spring which is invoking setSSLIdentity(byte[]) meaning that com.tibco.tibjms.TibjmsConnectionFactory is treating the bytes of the string c:\\cert\\testCert.p12 as a certificate (which it clearly isn't).

Unfortunately Spring doesn't let you force the type on the property element (like it does on constructor-arg, at least at the time of writing), so you'll use the constructor that takes a java.utils.Map and pass the configuration as properties:

<bean id="tibcoConnectionFactory" class="com.tibco.tibjms.TibjmsConnectionFactory">
  <constructor-arg value="ssl://mytibco.server.address:30113" />
  <constructor-arg><null/></constructor-arg>
  <constructor-arg>
    <util:map>
      <entry key="com.tibco.tibjms.factory.username" value="userName"/>
      <entry key="com.tibco.tibjms.factory.password" value="${tibcoPwd}"/>
      <entry key="com.tibco.tibjms.connect.attemptcount" value="10"/>
      <entry key="com.tibco.tibjms.connect.attemptdelay" value="100"/>
      <entry key="com.tibco.tibjms.connect.attempttimeout" value="1000"/>  
      <entry key="com.tibco.tibjms.reconnect.attemptcount" value="10"/>
      <entry key="com.tibco.tibjms.reconnect.attemptdelay" value="10-"/>
      <entry key="com.tibco.tibjms.reconnect.attempttimeout" value="1000" />  
      <entry key="com.tibco.tibjms.ssl.vendor" value="j2se"/>
      <entry key="com.tibco.tibjms.ssl.enable_verify_host" value="false"/>
      <entry key="com.tibco.tibjms.ssl.enable_verify_hostname" value="false"/>
      <entry key="com.tibco.tibjms.ssl.trace" value="true"/>
      <entry key="com.tibco.tibjms.ssl.debug_trace" value="true"/>
      <entry key="com.tibco.tibjms.ssl.identity" value="c:/cert/testCert.p12"/>
      <entry key="com.tibco.tibjms.ssl.password" value="value="*******"/>  
    <util:map>
  </constructor-arg>
</bean>

For anyone looking for the names for other properties, you can drill into the associated setter and see property name there.

Upvotes: 3

CharlesVG
CharlesVG

Reputation: 11

The problem is that TibjmsConnectionFactory overloads the setSSLIdentity(..) setter.

The available setters are:

setSSLIdentity(byte[] identity)

setSSLIdentity(java.lang.String sslIdentity)

This means that Spring doesn't know which setter to call. I haven't researched proof of this, but from a google search I found out that it's up to the JVM implementation to decide which setter will be called and, in my case, it was different with every application restart (Oracle JVM). In fact this is a known issue, see https://github.com/flyway/flyway/issues/890 .

One solution is to call the constructor with a Map containing your properties:

TibjmsConnectionFactory(java.lang.String serverUrl, java.lang.String clientId, java.util.Map properties)

See also https://docs.tibco.com/pub/enterprise_message_service/8.1.0/doc/html/tib_ems_api_reference/api/javadoc/com/tibco/tibjms/TibjmsConnectionFactory.html#setSSLIdentity(java.lang.String)

PS: Sorry for resurrecting an old question, but as there is quite a high traffic for this question, this may help others in the future.

Upvotes: 1

Chinmay
Chinmay

Reputation: 1

Enter SSLIdentity as /c:/cert/testCert.p12. Then only it will recognize your p12 file, else will treat it as byte array

Upvotes: 0

yeeep
yeeep

Reputation: 1

It seems that it's not reading .p12 correctly. It must log something like:

[TIBCO EMS]: [J] [SSL] reading client identity from file 'c:\cert\testCert.p12', format=PKCS12

note the format=...

Upvotes: 0

Related Questions