Spring JmsTemplate + Security

James picture James · Jul 7, 2010 · Viewed 10.8k times · Source

I've just refactored some code that published to a JMS topic to use Spring's JmsTemplate class and now I'm receiving an exception stating I'm not authenticated.

Previously I created the factory, made a connection, then session etc as follows:

MQTopicConnectionFactory factory = new MQTopicConnectionFactory();
factory.setQueueManager(qMgr);   
factory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
factory.setHostName(hostname);
factory.setPort(listenerPort);
factory.setChannel(channel);
// setting username and password to be empty string ==> no authentication
connection = factory.createConnection("", "");   
...
connection.start();

I don't see anywhere in the JmsTemplate to set the username and password to empty strings. My config looks like this:

<bean id="jmsFactory" class="com.ibm.mq.jms.MQTopicConnectionFactory">
    <property name="queueManager">
        <value>ACT01</value>
    </property>
    <property name="hostName">
        <value>xx.xx.xx.xx</value>
    </property>
    <property name="port">
        <value>15004</value>
    </property>
    <property name="transportType">
        <value>1</value>
    </property>
    <property name="channel">
        <value>CONDUCTOR.ACT01</value>
    </property>
</bean>

<bean id="impactJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory">
        <bean class="org.springframework.jms.connection.SingleConnectionFactory">
            <property name="targetConnectionFactory">
                <ref local="jmsFactory" />
            </property>
        </bean>
    </property>
</bean>

I have also tried wrapping the jmsFactory in a UserCredentialsConnectionFactoryAdapter object to no avail:

<bean id="jmsConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="jmsFactory"/>
    <property name="username" value=""/>
    <property name="password" value=""/>
</bean> 

Stack trace:

Caused by: com.ibm.msg.client.jms.DetailedJMSSecurityException: JMSWMQ2013: The security authentication was not valid that was supplied for QueueManager 'LOROL' with connection mode 'Client' and host name 'xx.xx.xx.xx'. Please check if the supplied username and password are correct on the QueueManager you are connecting to
at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:531)
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:219)
at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:410)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createV7ProviderConnection(WMQConnectionFactory.java:7855)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createProviderConnection(WMQConnectionFactory.java:7331)
at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl.createConnection(JmsConnectionFactoryImpl.java:276)
at com.ibm.mq.jms.MQConnectionFactory.createCommonConnection(MQConnectionFactory.java:6055)
at com.ibm.mq.jms.MQTopicConnectionFactory.createTopicConnection(MQTopicConnectionFactory.java:114)
at com.ibm.mq.jms.MQTopicConnectionFactory.createConnection(MQTopicConnectionFactory.java:197)
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.execute(JmsTemplate.java:461)
... 25 more
Caused by: com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2035' ('MQRC_NOT_AUTHORIZED').
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:206)
... 37 more

Answer

T.Rob picture T.Rob · Jul 8, 2010

A few options here...

  • The properties you were setting before resulted in the channel running as an administrator. To get the same functionality you can set the channel's MCAUSER to whatever ID the QMgr is running as (commonly mqm for UNIX and MUSR_MQADMIN on Windows). Boom. Done. Bob's yer uncle.
  • Yes, this does mean that anyone connecting to that channel is an administrator. On the other hand, this is no worse than it was before as demonstrated by your previous code working the way it did.
  • You can still use Spring and pass in the ID and password as described in this forum post. Just keep in mind the password is not actually checked. Whatever ID you pass in is accepted at face value unless you use a channel exit to validate it.

For more on WMQ security over client connections, see the Hardening WebSphere MQ presentation. If you wanted to actually secure access to the QMgr you'd want to set MCAUSER to a low-privileged user ID, perform setmqaut commands to authorize that ID's group and then lock down all the other channels like SYSTEM.AUTO.* and SYSTEM.DEF.* so they could not run.