我的JMS客户端通过JNDI连接到WMQ。使用的初始上下文工厂是com.ibm.mq.jms.context.WMQInitialContextFactory
。
目前,在WMQ方面,有一个名为TestMgr
的队列管理器。在这个队列管理器下我创建了两个通道。一个是PLAIN.CHL
,它没有指定SSL密码规范,另一个是SSL.CHL
,它使用RC4_MD5_US
配置SSL密码规范,使用Optional
配置SSL身份验证。
我使用IBM Key Management工具为队列管理器创建了一个密钥库。密钥db的路径是[wmq_home]\qmgrs\TestMgr\ssl\key
。
对于频道PLAIN.CHL
,我定义了一个队列连接工厂,如:
DEF QCF(PlainQCF) QMANAGER(TestMgr) CHANNEL(PLAIN.CHL) HOST(192.168.66.23) PORT(1414) TRANSPORT(client)
在SSL频道SSL.CHL
下,我定义了一个队列连接工厂,如:
DEF QCF(SSLQCF) QMANAGER(TestMgr) CHANNEL(SSL.CHL) HOST(192.168.66.23) PORT(1414) TRANSPORT(client) SSLCIPHERSUITE(SSL_RSA_WITH_RC4_128_MD5)
现在我只能使用PlainQCF
创建连接。但未能查找SSL队列连接工厂。我的代码如下:
Hashtable environment = new Hashtable();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.mq.jms.context.WMQInitialContextFactory");
environment.put(Context.PROVIDER_URL, "192.168.66.23:1414/SSL.CHL");
Context ctx = new InitialContext( environment );
QueueConnectionFactory qcf = (QueueConnectionFactory) ctx.lookup("SSLQCF");
qcf.createConnection();
....
在查找SSL工厂时,我是否遗漏了一些上下文属性?连接然后我发现代码在new InitialContext( environment )
行上挂了很长时间,差不多5分钟,我发现CC=2;RC=2009;AMQ9208...
错误。
任何建议都将不胜感激。是不是JNDI无法连接SSL通道?
@ T.Rob,非常感谢你的回复。但我们仍然想使用WMQInitialContextFactory
,所以我担心我仍然需要为此找到解决方案。
我刚刚定义了连接工厂一次。 SSL队列连接工厂的显示信息如:
InitCtx> DISPLAY QCF(SSLQCF)
ASYNCEXCEPTION(ALL)
CCSID(819)
CHANNEL(SSL.CHL)
CLIENTRECONNECTOPTIONS(ASDEF)
CLIENTRECONNECTTIMEOUT(1800)
COMPHDR(NONE )
COMPMSG(NONE )
CONNECTIONNAMELIST(192.168.66.23(1414))
CONNOPT(STANDARD)
FAILIFQUIESCE(YES)
HOSTNAME(192.168.66.23)
LOCALADDRESS()
MAPNAMESTYLE(STANDARD)
MSGBATCHSZ(10)
MSGRETENTION(YES)
POLLINGINT(5000)
PORT(1414)
PROVIDERVERSION(UNSPECIFIED)
QMANAGER(TestMgr)
RESCANINT(5000)
SENDCHECKCOUNT(0)
SHARECONVALLOWED(YES)
SSLCIPHERSUITE(SSL_RSA_WITH_RC4_128_MD5)
SSLFIPSREQUIRED(NO)
SSLRESETCOUNT(0)
SYNCPOINTALLGETS(NO)
TARGCLIENTMATCHING(YES)
TEMPMODEL(SYSTEM.DEFAULT.MODEL.QUEUE)
TEMPQPREFIX()
TRANSPORT(CLIENT)
USECONNPOOLING(YES)
VERSION(7)
WILDCARDFORMAT(TOPIC_ONLY)
JNDI Provider应该没问题,因为我可以成功查找普通连接工厂。此外,对于我的客户端应用程序,我从为MQ服务器创建的密钥库中提取了证书,并将其导入到我的JRE的信任库(cacerts),别名为ibmwebspheremqtestmgr
。
你是对的,在2009年的错误中有一些日志条目:
=================================================================
4/20/2012 20:24:27 - Process(13768.3) User(MUSR_MQADMIN) Program(amqzmur0.exe)
Host(xxxx_host of my MQ) Installation(mqenv)
VRMF(7.1.0.0) QMgr(TestMgr)
AMQ6287: WebSphere MQ V7.1.0.0 (p000-L111019).
EXPLANATION:
WebSphere MQ system information:
Host Info :- Windows Server 2003, Build 3790: SP2 (MQ Windows 32-bit)
Installation :- C:\IBM\WebSphereMQ (mqenv)
Version :- 7.1.0.0 (p000-L111019)
ACTION:
None.
-------------------------------------------------------------------------------
4/20/2012 20:24:27 - Process(7348.116) User(MUSR_MQADMIN) Program(amqrmppa.exe)
Host(xxxx_host of my MQ) Installation(mqenv)
VRMF(7.1.0.0) QMgr(TestMgr)
AMQ9639: Remote channel 'SSL.CHL' did not specify a CipherSpec.
EXPLANATION:
Remote channel 'SSL.CHL' did not specify a CipherSpec when the local channel
expected one to be specified.
The remote host is 'xxx_host of my app (192.168.66.25)'.
The channel did not start.
ACTION:
Change the remote channel 'SSL.CHL' on host 'xxx_host of my app (192.168.66.25)' to
specify a CipherSpec so that both ends of the channel have matching
CipherSpecs.
----- amqcccxa.c : 3817 -------------------------------------------------------
4/20/2012 20:24:27 - Process(7348.116) User(MUSR_MQADMIN) Program(amqrmppa.exe)
Host(my app host) Installation(mqenv)
VRMF(7.1.0.0) QMgr(TestMgr)
AMQ9999: Channel 'SSL.CHL' to host 'xxx_host of my app (192.168.66.25)' ended
abnormally.
====================================================================
我也对错误日志感到困惑。我的应用程序在与我的MQ不同的机器上进行。但日志显示Change the remote channel 'SSL.CHL' on host 'xxx_host of my app (192.168.66.25)' to
specify a CipherSpec so that both ends of the channel have matching
CipherSpecs.
如何更改应用主机上的频道密码规范?
回复评论。
MQEnvironment.sslCipherSuite
的值为null,因此当我将它设置为env哈希表时,它会抛出NullPointerExcetpion。但我尝试了另一个environment.put(MQC.SSL_CIPHER_SUITE_PROPERTY, "SSL_RSA_WITH_RC4_128_MD5")
但仍然失败并出现2009
错误。
对于JMSAdmin
工具,我已将配置更改为使用WMQInitialContextFactory
。配置如(JMSAdmin.config
):
INITIAL_CONTEXT_FACTORY=com.ibm.mq.jms.context.WMQInitialContextFactory
PROVIDER_URL=192.168.66.23:1414/SYSTEM.DEF.SVRCONN
其余配置保留为默认值。
请注意,这里我使用默认频道SYSTEM.DEF.SVRCONN
,以便我可以登录管理控制台。如果我将频道更改为SSL SSL.CHL
,我也无法登录管理控制台。这里发生的错误就像我的客户端应用程序中的错误。
另一个澄清,在我的客户端,我使用关注代码可以通过频道TestMgr
成功连接到qmgr(SSL.CHL
)。
MQConnectionFactory factory = new MQConnectionFactory();
factory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
factory.setQueueManager("TestMgr");
factory.setSSLCipherSuite("SSL_RSA_WITH_RC4_128_MD5");
factory.setPort(1414);
factory.setHostName("192.168.66.23");
factory.setChannel("SSL.CHL");
MQConnection connection = (MQConnection) factory.createConnection();
现在问题就像你说的那样,初始上下文无法通过SSL通道连接到qmgr。您提供的选项(use plain channel for initial context and ssl channel for connection factory
)也有效。但我仍然想知道如何通过ssl通道工作获得初始上下文。非常感谢你的耐心等待。您的更新将不胜感激。
谢谢
答案 0 :(得分:1)
我从未真的非常喜欢com.ibm.mq.jms.context.WMQInitialContextFactory
。它将受管对象存储在队列中。因此,为了查找告诉JMS如何连接到QMgr的connectionFactory
,首先必须连接到QMgr 以进行JNDI调用。因此,在调试SSL连接之前,您需要知道底层JNDI提供程序是否正常工作。
如果您想跳过基于MQ的JNDI提供程序并只使用文件系统,请参阅Bobby Woolf的文章here的更新版本。如果您想继续com.ibm.mq.jms.context.WMQInitialContextFactory
,请继续阅读,但要准备好提供更多配置信息。
运行JMSAdmin工具时,是否在创建对象后显示它们?例如,这是我的JMSAdmin.bat
脚本之一:
# Connection Factory for Client mode
# Delete the Connection Factory if it exists
DELETE CF(JMSDEMOCF)
# Define the Connection Factory
DEFINE CF(JMSDEMOCF) +
SYNCPOINTALLGETS(YES) +
SSLCIPHERSUITE(NULL_SHA) +
TRAN(client) +
HOST(127.0.0.1) CHAN(SSL.SVRCONN) PORT(1414) +
QMGR( )
# Display the resulting definition
DISPLAY CF(JMSDEMOCF)
这会删除对象(因为JMSAdmin没有带有replace选项的define),然后定义对象,然后显示它。你实际上看到两个对象都被定义了吗?你能连接并以交互方式显示它们吗?你能用显示的内容更新你的问题吗?
如果是这样,那么每个示例程序的JNDI提供程序配置是什么样的? 2009年表明至少与QMgr建立了连接,因此确定遭受断开连接的是您的应用程序或JNDI提供程序是很重要的。要诊断它需要您用于JNDI提供程序的配置信息,以及它在工作和失败情况下是否相同。如果没有,它们有何不同?
一旦你知道它是导致问题的应用程序或JNDI提供程序(或切换到不需要MQ连接的另一个JNDI提供程序,例如文件系统初始上下文),那么就可以确定下一个步骤。
article linked above包含使用文件系统JNDI提供程序的代码和托管对象脚本示例。您可能会注意到我上面粘贴的脚本使用相同的QMgr名称。那是因为我写了这篇文章的一部分。当我想使用相同的样本切换到SSL时,我只需将connectionFactory
更新为指向SSL通道即可。
以下是我修改过的样本中的其他位:
java -Djavax.net.debug=ssl ^
-Djavax.net.ssl.trustStore=key2.jks ^
-Djavax.net.ssl.keyStore=key2.jks ^
-Djavax.net.ssl.keyStorePassword=???????? ^
-Djavax.net.ssl.trustStorePassword=???????? ^
-cp "%CLASSPATH%" ^
com.ibm.examples.JMSDemo -pub -topic JMSDEMOPubTopic %*
注意:^
是行版本的Windows版本。
然后如果有问题,我会按照this SO answer中描述的调试方案进行操作。请注意,即使您的频道上有SSLCAUTH(OPTIONAL)
,该应用也需要信任库。这是因为即使应用程序没有提供自己的证书,应用程序也必须始终验证QMgr的证书。在我的情况下,我使用SSLCAUTH(REQUIRED)
所以我的应用程序需要密钥库和信任库。您的问题提到QMgr有一个密钥库,但没有说明您为该应用程序做了什么。
最后,2009年通常会在QMgr错误日志中生成一个条目。如果您仍然遇到问题,请使用这些日志条目更新您的问题。
<强>更新强>
响应评论, JMSAdmin工具是WMQ包的一部分。但是,WMQ它带有用于文件系统上下文和LDAP上下文的jar。 WMQInitialContextFactory
是可选的,并以SupportPac ME01的形式发送。将WMQInitialContextFactory
与JMSAdmin工具(或JMSAdmin GUI或WMQ Explorer)一起使用时,必须使用主机,端口和通道配置PROVIDER_URL。例如:
PROVIDER_URL: <Hostname>:<port>/<SVRCONN Channel Name>
192.168.66.23:1414/SSL.SVRCONN
因此,在再次审核您的帖子后,我意识到您 提供了WMQInitialContextFactory
的配置信息。我正在寻找一个JMSADmin.config文件,但你在环境哈希表中有它。这就是问题所在。您正尝试将SSL通道用于WMQInitialContextFactory
和连接工厂。这是导致查找失败的原因。 WMQInitialContextFactory
首先与QMgre建立Java连接,以便查看队列以获取受管对象(如QCF)。为了做到这一点,它需要知道通道设置的密码套件以便协商握手。现在,记录密码套件的* only *位置在QCF定义中。
尝试添加以下行:
environment.put(MQEnvironment.sslCipherSuite, "SSL_RSA_WITH_RC4_128_MD5");
根据this Infocenter page,这应该告诉上下文工厂类使用什么密码套件。当然,他们还需要知道信任存储的位置(如果通道设置了SSLCAUTH(RQUIRED)
,可能还需要密钥库),因此您仍需要在环境中获取这些值。您可以使用命令行变量或尝试使用代码将它们加载到环境中。您需要-Djavax.net.ssl.trustStore=key2.jks
和-Djavax.net.ssl.trustStorePassword=????????
。
另一种选择是继续使用WMQInitialContextFactory
的明文通道和应用程序的SSL通道。如果明文通道具有用于非特权用户ID的MCAUSER,则可以将其限制为仅连接到QMgr并访问包含受管对象的队列。有了这些限制,任何人都可以使用该通道读取管理对象,但不能读取应用程序队列或管理队列。