如何使用SSL连接从Camel路由连接到IBM MQ?

时间:2017-01-20 21:20:26

标签: apache-camel ibm-mq

我可以从camel路由成功连接到IBM MQ并初始化连接工厂bean,但现在我想连接SSL。

  1. 我在服务器端为队列管理器创建密钥库,并创建证书并将其添加到其中。
  2. 我在客户端创建一个信任存储区并将证书添加到它。
  3. 现在我希望MQ连接工厂在连接服务器时引用信任存储。
  4. 以下是我的尝试:

    <bean id="MyConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
            <property name="transportType" value="${queue.transportType}" />
            <property name="channel" value="${queue.channel}" />
            <property name="hostName" value="${queue.hostName}" />
            <property name="port" value="${queue.port}" />
            <property name="queueManager" value="${queue.manager}" />
            <property name="sSLCipherSuite" value="SSL_RSA_WITH_NULL_MD5" />
            <property name="sSLCertStores" value="file:C:/Servers/TrustStore/truststore.jks" />
        </bean>
    

    但这不起作用。返回以下异常:

    JMSWMQ0018: Failed to connect to queue manager 'QM_TEST_SSL' 
           with connection mode 'Client' and host name '10.3.13.161(1415)'.; 
           nested exception is com.ibm.mq.MQException: JMSCMQ0001: 
           WebSphere MQ call failed with compcode '2' ('MQCC_FAILED')
           reason '2397' ('MQRC_JSSE_ERROR').
    

    任何人都可以帮忙指导我如何做到这一点吗?

2 个答案:

答案 0 :(得分:2)

从安全角度来看,客户端应该只接收可能与许多问题相关的通用错误消息。查找客户端被拒绝原因的最佳位置是队列管理器日志。我建议在那里查看是否有任何错误可以帮助您进一步确定问题。 根据给出的信息,我可以想到3个问题:

  1. 队列管理器频道设置的属性为SSLCAUTH(必填)但是根据您在此处提供的说明,客户似乎没有使用它自己的证书连接。 SSLCAUTH(REQUIRED)意味着队列管理器仅接受客户端与其信任的证书连接的特定通道上的连接。检查频道定义并设置 SSLCAUTH(可选)

  2. 根据您的IBM MQ版本,您使用的CipherSpec(SSL_RSA_WITH_NULL_MD5)被视为弱,默认情况下不会被接受。您可以重新启用这些已弃用的CipherSpecs,有关如何执行此操作的说明,请参阅following Knowledge Center page

  3. 信任库&#34; C:/Servers/TrustStore/truststore.jks"没有被客户端接收,因此客户端无法信任Queue Manager的证书。仔细检查您提供的路径并删除&#34;文件:&#34;您已添加到路径中(除非您被明确指示包含它)。

答案 1 :(得分:1)

您没有说明您使用的是哪个版本的IBM MQ或哪个JRE,如果它不是最新版本的IBM MQ并且正在与Oracle JRE一起使用,那么APAR IT10837可能会对此有所帮助

在IBM developerWorks blog&#34; MQ Java, TLS Ciphers, Non-IBM JREs & APARs IT06775, IV66840, IT09423, IT10837 -- HELP ME PLEASE!&#34;的最后,有一篇很好的上述APAR的文章。由Tom Leend发布。他包含了针对没有此修复程序的Java客户端的解决方法。

  

<强> APAR IT10837

     

我有一个最后提到的APAR,那就是IT10837(针对V7.1.0.8和V7.5.0.7并在V8.0.0.5中提供)。此APAR影响在Oracle JRE中运行的应用程序,这些应用程序使用TLS CipherSuite连接到队列管理器,其中正在使用的服务器连接通道将SSLCAUTH属性设置为&#34; REQUIRED&#34; (默认值)。这意味着客户端应将证书传递给队列管理器,以便MQ服务器可以对连接客户端进行身份验证。

     

当应用程序在Oracle JRE中运行时,SunJSSE提供程序没有为TLS套接字连接创建默认的内部密钥管理器对象,这意味着客户端的签名个人证书在握手期间无法用于客户端身份验证。 IBM JSSE提供程序基于通过Java系统属性传递的信息执行此操作:

     
      
  • javax.net.ssl.keyStore

         

  •   
  • javax.net.ssl.keyStorePassword

  •   
     

由于默认情况下未创建KeyManager对象,因此未将客户端证书传递给队列管理器(GSKit)进行身份验证。因此,来自应用程序的连接将失败。在这种情况下,队列管理器会将以下错误消息写入其错误日志文件中:

     

AMQ9637(频道缺少证书)

     

此APAR的修复程序是针对JMS的MQ类和Java的类根据上面提到的两个Java系统属性中的信息读取证书密钥库,并在以下情况下基于该信息创建KeyManager。 com.ibm.mq.cfg.useIBMCipherMappings在JVM中设置为false。然后可以在创建SSLContext时使用它(随后用于创建SSLSocketFactory并最终创建安全套接字对象)。

     

有一个本地解决方法,供应用程序本身创建   TrustManagerFactory和KeyManagerFactory工厂对象用于相应的证书存储,并初始化SSLContext对象这些对象。从这个SSLContext对象和SSLSocketFactory可以创建并传递给JMS的MQ类(通过在JMS连接工厂上设置)或Java类(通过在MQEnvironment上设置它或在传递给MQQueueManager构造函数的Hashtable中) 。例如:

     

---- Code Snippet Start ----

KeyStore keyStore = KeyStore.getInstance("JKS");
java.io.FileInputStream keyStoreInputStream = new java.io.FileInputStream("/home/tom/myKeyStore.jks");
keyStore.load (keyStoreInputStream, password_char_array);

KeyStore trustStore trustStore = KeyStore.getInstance ("JKS");
java.io.FileInputStream trustStoreInputStream = new java.io.FileInputStream("/home/tom/myTrustStore.jks");
trustStore.load (trustStoreInputStream, password_char_array);

keyStoreInputStream.close();
trustStoreInputStream.close();

KeyManagerFactory keyManagerFactory = 
  KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
TrustManagerFactory trustManagerFactory = 
  TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore,password);
trustManagerFactory.init(trustStore);

SSLContext sslContext = SSLContext.getInstance("TLSv1"); 
sslContext.init(keyManagerFactory.getKeyManagers(), 
  trustManagerFactory.getTrustManagers(), 
  null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); 

// classes for JMS
myJmsConnectionFactory.setObjectProperty(
  WMQConstants.WMQ_SSL_SOCKET_FACTORY, sslSocketFactory);

// classes for Java
MQEnvironment.sslSocketFactory = sslSocketFactory;
     

---- Code Snippet End ----