当前位置: 首页 > 面试题库 >

将Java客户端(JMS)连接到IBM MQ时出现问题

刁英朗
2023-03-14
问题内容

我正在尝试使用基本上通过以下方式构建的Java客户端使用SSL消耗IBM MQ(版本8.0.0.8):

  • Oracle JKD 8和IBM JRE 7(出于测试目的,我每个都有一个客户端)
  • com.ibm.mq.allclient-9.1.0.0.jar
  • javax.jms-api-2.0.1.jarspring-jms-4.3.7.RELEASE.jar
  • spring-jms-4.3.7.RELEASE.jar

MQ是一种请求/答复类型。

我已经设置了正确的证书和所有MQ属性,但是由于某种原因,连接“掉线了”,并且客户端没有错误,我的请求从未得到任何响应,并且一直“永远”运行,从未得到任何响应。我唯一的线索是MQ日志中的错误消息,内容为:

Process(31600.16) User(QMQM) Jobname(JOB_NAME)
                    Host(HOST_NAME)
                    VRMF(8.0.0.8) QMgr(MANAGER_NAME)
                    AMQ9638: SSL communications error for channel

‘CHANNEL_NAME’. EXPLANATION:
Cause . . . . . : An unexpected SSL communications error occurred
for a channel, as reported in the preceding messages. The
channel is ‘CHANNEL_NAME’;


奇怪的是发生了SSL握手,我的证书被MQ接受了,但是由于某些原因在此之后发生了某些事情。我正在尝试同时使用Oracle JRE 8和IBM
JRE7。也许是MQ方面的某些东西(IBM MQ v8.0.0.8)或我缺少的某些配置。

我已经安装了JCE无限策略,所以问题不是CipherSpec X CipherSuite。

我正在使用-Djavax.net.debug = all,可以看到我的证书被正确使用,并且在那里看不到任何问题…

我在MQ团队的联系点告诉我,由于某种原因,我的应用程序正在吊销证书(与CLR有关的事情),但是我不知道为什么会发生这种情况。

我的Java代码:

public Message callMQ() {

        Message message = null;

        try {

            MQConnectionFactory factory = mqQueueConnectionFactory();
            JMSContext context = factory.createContext();

            Destination requestQueue = context.createQueue("queue:///REQUEST_QUEUE");
            Destination replyQueue = context.createQueue("queue:///REPLY_QUEUE");

            JmsTemplate jmsTemplate = new JmsTemplate(factory);

            FIXMLRootInbound inbound = new FIXMLRootInbound();
            String xml = XmlUtil.xmlObjectToString(inbound);

            message = jmsTemplate.sendAndReceive(requestQueue,
                    session -> {
                        Message req = session.createTextMessage(xml);
                        req.setJMSCorrelationID(UUID.randomUUID().toString());
                        req.setJMSDestination(requestQueue);
                        req.setJMSReplyTo(replyQueue);
                        return req;
                    });

        } catch (Throwable e) {
            e.printStackTrace();
        }

        return message;
    }

    private MQConnectionFactory mqQueueConnectionFactory() throws NoSuchAlgorithmException, KeyStoreException,
            IOException, CertificateException, UnrecoverableKeyException, KeyManagementException, JmsException {

        SSLSocketFactory sslSocketFactory = sslContext().getSocketFactory();

        MQEnvironment.sslSocketFactory = sslSocketFactory;
        MQEnvironment.sslCipherSuite = "TLS_RSA_WITH_AES_256_CBC_SHA";
        MQEnvironment.sslFipsRequired = false;

        MQConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
        mqQueueConnectionFactory.setHostName(host);
        try {
            mqQueueConnectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
            mqQueueConnectionFactory.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE,
                    WMQConstants.WMQ_CM_CLIENT);
            mqQueueConnectionFactory.setQueueManager(queueManager);
            mqQueueConnectionFactory.setSSLCipherSuite("TLS_RSA_WITH_AES_256_CBC_SHA");
            mqQueueConnectionFactory.setCCSID(285);
            mqQueueConnectionFactory.setChannel(channel);
            mqQueueConnectionFactory.setPort(port);
            mqQueueConnectionFactory.setSSLSocketFactory(sslSocketFactory);
            mqQueueConnectionFactory.setSSLFipsRequired(false);
        } catch (Exception e) {
            log.error("Error creating MQQueueConnectionFactory.", e);
        }

        return mqQueueConnectionFactory;
    }

    private SSLContext sslContext() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {

        try (InputStream cert = new FileInputStream("C:\\myplace\\Dev\\Certificates\\MY_KEYSTORE.jks")) {

            final KeyStore caCertsKeyStore = KeyStore.getInstance("JKS");
            caCertsKeyStore.load(cert, "changeit".toCharArray());

            final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

            CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
            PKIXRevocationChecker rc = (PKIXRevocationChecker)cpb.getRevocationChecker();
            rc.setOptions(EnumSet.of(
                    PKIXRevocationChecker.Option.PREFER_CRLS,
                    PKIXRevocationChecker.Option.ONLY_END_ENTITY,
                    PKIXRevocationChecker.Option.SOFT_FAIL,
                    PKIXRevocationChecker.Option.NO_FALLBACK));

            PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(caCertsKeyStore, new X509CertSelector());
            pkixParams.addCertPathChecker(rc);

            kmf.init(caCertsKeyStore, "changeit".toCharArray());
            tmf.init( new CertPathTrustManagerParameters(pkixParams) );

            final SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

            return sslContext;

        } catch (Exception e) {
            throw new RuntimeException("Exception creating SSLContext", e);
        }
    }

问题答案:

由于您使用的是9.1.0.0 com.ibm.mq.allclient.jar,因此不需要与密钥库相关的所有代码,例如:

SSLSocketFactory sslSocketFactory = sslContext().getSocketFactory();

//Note that MQEnvironment is used with IBM MQ Classes for Java not IBM MQ Classes for JMS
MQEnvironment.sslSocketFactory = sslSocketFactory;
MQEnvironment.sslCipherSuite = "TLS_RSA_WITH_AES_256_CBC_SHA";
MQEnvironment.sslFipsRequired = false;

mqQueueConnectionFactory.setSSLSocketFactory(sslSocketFactory);

private SSLContext sslContext() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {

    try (InputStream cert = new FileInputStream("C:\\myplace\\Dev\\Certificates\\MY_KEYSTORE.jks")) {

        final KeyStore caCertsKeyStore = KeyStore.getInstance("JKS");
        caCertsKeyStore.load(cert, "changeit".toCharArray());

        final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

        CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
        PKIXRevocationChecker rc = (PKIXRevocationChecker)cpb.getRevocationChecker();
        rc.setOptions(EnumSet.of(
                PKIXRevocationChecker.Option.PREFER_CRLS,
                PKIXRevocationChecker.Option.ONLY_END_ENTITY,
                PKIXRevocationChecker.Option.SOFT_FAIL,
                PKIXRevocationChecker.Option.NO_FALLBACK));

        PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(caCertsKeyStore, new X509CertSelector());
        pkixParams.addCertPathChecker(rc);

        kmf.init(caCertsKeyStore, "changeit".toCharArray());
        tmf.init( new CertPathTrustManagerParameters(pkixParams) );

        final SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

        return sslContext;

    } catch (Exception e) {
        throw new RuntimeException("Exception creating SSLContext", e);
    }
}

您可以通过设置以下两个系统属性来代替它,这对Oracle和IBM Java均适用:

System.setProperty("javax.net.ssl.keyStore", "C:\\myplace\\Dev\\Certificates\\MY_KEYSTORE.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "changeit");

以上设置始终适用于IBM Java,但是对于Oracle Java,这不适用于较旧版本的MQ。在以下版本的IBM MQ中,Oracle
Java已修复该问题(Base 9.0和9.1具有相同的修复程序):

Version    Maintenance Level
v7.1       7.1.0.8
v7.5       7.5.0.7
v8.0       8.0.0.5

IBM Java和Oracle Java具有不同的CipherSuite名称,这些名称记录在IBM MQ v9.1知识中心页面“ 用于JMS的IBM
MQ类中的TLS
CipherSpecs和CipherSuite”中。

您已经TLS_RSA_WITH_AES_256_CBC_SHA在发布的代码中指定了,这将是SSLCIPHMQ队列管理器SVRCONN通道上的值,并将映射到以下CipherSuites:

  • IBM Java: SSL_RSA_WITH_AES_256_CBC_SHA
  • Oracle Java: TLS_RSA_WITH_AES_256_CBC_SHA

与上述相关,如果您使用的是Oracle Java,则需要设置以下系统属性,以便MQ JMS类将能够使用Oracle CipherSuite名称的正确映射:

System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");

您提供的错误似乎来自IBM i MQ队列管理器,但是没有提供足够的信息来诊断问题。

该错误指出以下内容:

An unexpected SSL communications error occurred for a channel, as reported in the preceding messages.

您可以编辑问题并提供“先前消息”中的详细信息吗?

你说过

由于某种原因,我的申请正在吊销证书(与CLR相关的问题)

MQ队列管理器可能正在尝试自行连接到客户端证书的AuthorityInfoAccess(AIA)证书扩展名中指定的OCSP服务器。如果MQ无法使用默认配置访问此OCSP服务器,则连接将被拒绝。如果您无法更新网络以允许连接到OCSP服务器,则可以禁用此检查,但是请注意,您将不知道证书是否被吊销。要禁用检查,可以将以下内容添加到队列管理器的qm.ini文件SSL节中:

SSL:
   OCSPAuthentication=Optional
   OCSPCheckExtensions=no

最后一个注释,您在示例代码中列出TLS_RSA_WITH_AES_256_CBC_SHA的CipherSuite是TLS1.0
CipherSuite。像之前的SSL一样,许多行业通常不推荐使用此协议和TLS1.1。我寻找发布的参考,“ tls
1.0生命终止 ”的google
提供了许多参考。

在下面引用一个“ TLS 1.0寿命终止于2018年6月30日 ”:

截止日期 PCI委员会负责确定何时淘汰较旧的协议。他们最初认为TLS
1.0将于2016年6月30日到期,后来将日期延长至2018年6月30日。最后期限已经过去,所有网络服务器,网络浏览器,网络软件和电子邮件应用程序都必须停止对TLS
1.0的支持,或违反重要的安全更新。

例如,我建议选择在我上面链接到的知识中心页面中列为TLS1.2的一个TLS_RSA_WITH_AES_256_CBC_SHA256



 类似资料:
  • Oracle JKD 8和IBM JRE 7(出于测试目的,我为它们各配置了一个客户机) com.ibm.mq.allclient-9.1.0.0.jar javax.jms-api-2.0.1.jarspring-jms-4.3.7.release.jar spring-jms-4.3.7.release.jar MQ是请求/应答类型。 我已经设置了正确的证书和所有MQ属性,但由于某种原因,连接

  • 我正在尝试使用hazelcast v3。2.4(服务器和客户端上的版本相同)。服务器(我可以安装的简单实现)正在服务器上运行。客户端尝试连接到远程服务器-服务器打印身份验证请求,但我收到以下日志输出(包括异常)-关于我可以做什么不同的想法(复制日志输出和配置文件)。我正在尝试通过TCP/IP进行连接,我检查了网络连接——我没有看到任何东西阻止连接。 堆栈中提到的代码行: 配置 日志输出 服务器输出

  • 我正在运行一个kubernetes集群,在其中按照kubernetes hazelcast github页面上的说明部署一个“云原生hazelcast”。一旦运行了许多hazelcast实例,我就会尝试将java客户端连接到其中一个实例,但由于某种原因,连接失败。 使用kubernetes外部endpoint,我可以从kubernetes集群外部连接到hazelcast。当我使用curl-kube

  • 问题内容: 我正在尝试建立与trackobot.com的连接以接收一些JSON数据。服务器仅允许通过HTTPS / SSL进行连接。这是代码: openSteam抛出javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure 我通读了与类似问题有关的几篇文章,但没有任何建议可以帮助您。适当的证书在我的信任库中。例如,当我尝试连接到goo

  • 使用java-version:1.8.0_171,我试图连接到API网关,但使用java8却得到一个SSL handshake_failure。已经运行的命令: 启用时,我得到了以下信息: 更新

  • 我正在制作一个Flask网络应用程序,我正在使用Flask Socketio。出于各种原因,我还需要使用websocket客户端包。一切正常,但当我尝试在不同网络上的不同计算机上运行应用程序时,出现以下错误: 我已经尽可能地将我的代码归结为以下内容,这些代码在我的计算机上仍然有效,但在另一台计算机上给出了相同的错误: 只是一个基本的“Hello World”html页面。 什么样的东西会让我在一台