I need to connect to a remote queue in my application,but when security enabled in MQ farm it hits Authentication Error (RC 2035),i have been informed that when i use spring configuration its trying to access some default queue which it shouldn’t ,i came across setDirectAuth property,would it solve this issue?please advise if i miss out any property that causes the error?
Error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'connectionFactory' defined in class path resource [META-INF/spring.xml]: Invocation of init method failed; nested exception is javax.naming.ServiceUnavailableException: Unable to connect to the target queue manager XXXX.XXX.XXX.com:1415/xxx.SVRCONN [Root exception is com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2035'.]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'connectionFactory' defined in class path resource [META-INF/spring.xml]: Invocation of init method failed; nested exception is javax.naming.ServiceUnavailableException: Unable to connect to the target queue manager xxxx.xxx.xxx.com:1415/xxx.SVRCONN [Root exception is com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2035'.]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:567)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
Context.xml
<Resource
name="jms/MQConnectionFactory"
auth="Container"
type="com.ibm.mq.jms.MQQueueConnectionFactory"
factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory for sending messages"
HOST="XX.XXX.XXX.XX"
PORT="XXXX"
CHAN="MQ.CHANNEL"
TRAN="1"
QMGR="TEST01"
/>
<Resource
name="jms/QueueSU"
auth="Container"
type="com.ibm.mq.jms.MQQueue"
factory="com.ibm.mq.jms.MQQueueFactory"
description="JMS Queue for status update"
QU="Q01"
/>
<Resource
name="jms/QueueBM"
auth="Container"
type="com.ibm.mq.jms.MQQueue"
factory="com.ibm.mq.jms.MQQueueFactory"
description="JMS Queue for bond management"
QU="Q02"
/>
property file:
#JMS Provider
jms.factory.initial=com.ibm.mq.jms.context.WMQInitialContextFactory
jms.provider.url=xx.xxx.xxx.com:1415/xxx.CHANNEL
destination.factory=java:/comp/env/jms/MQConnectionFactory
bm.queue=java:/comp/env/jms/QueueBM
su.queue=java:/comp/env/jms/QueueSU
Spring.xml
<!-- JMS BEANS -->
<bean id="bmMessageReceiver" class="com.jms.BMMessageReceiver"/>
<bean id="suMessageReceiver" class="com.jms.SUMessageReceiver"/>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">${jms.factory.initial}</prop>
<prop key="java.naming.provider.url">${jms.provider.url}</prop>
</props>
</property>
</bean>
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>${destination.factory}</value>
</property>
</bean>
<bean id="bmMessageQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>${bm.queue}</value>
</property>
</bean>
<bean id="suMessageQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>${su.queue}</value>
</property>
</bean>
<bean id="bmListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="5" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="bmMessageQueue" />
<property name="messageListener" ref="bmMessageReceiver" />
<property name="sessionTransacted" value="true" />
</bean>
<bean id="suListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="5" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="suMessageQueue" />
<property name="messageListener" ref="suMessageReceiver" />
<property name="sessionTransacted" value="true" />
</bean>
<!-- JMS END -->
When your app opens a local queue, the authorization profiles match the name of the queue that was opened. In other words, if the app connected to
LOCALQMGRopensSYSTEM.DEF.LOCAL.QUEUE@LOCALQMGRthe authorization control list entry onLOCALQMGRmust grant the app access toSYSTEM.DEF.LOCAL.QUEUE.However, when the app opens
SOME.QUEUE@REMOTEQMGRthe QMgr resolvesREMOTEQMGRand finds a transmission queue leading to that QMgr. The queue it opens in this case is the transmission queue therefore it looks for an authorization profile that matches the transmission queue. Authorizing an app to the XMitQ can be OK but it allows the app to address messages to any queue on that QMgr including, for example, the command queue.Many times, administrators do not wish to grant access to transmission queues directly because it allows access to any queue on that QMgr and they’d rather restrict that. So in a point-to-point interface, it is common to set up a QRemote locally and authorize the app to that. In a cluster, it is common to set up a local QAlias over a clustered queue and attach the authorization profile to that.
The only thing that will affect this is the user ID the app uses for the connection request. If the QMgr is secure, there is NOTHING the app can do to affect this connection ID. The MQ admin will have either set the ID in the channel definition or mapped it from the IP address or the SSL certificate distinguished name. If for some reason the QMgr is not secure, the app can specify the ID to use on the connection as part of the API call:
If the MQ admin has not set or mapped
MCAUSERon the channel, the QMgr will accept the ID you provide and the password is not checked. If the MQ admin configures a channel exit, the exit can validate the password against LDDAP, AD, local OS, etc. But if not exit is installed, the password is not checked.Now that you know this, you may be able to answer your question about the effect of
setDirectAuth(because I can’t). If that parameter is inherited by the connection factory and is asserted by the channel request it would be passed to MQ and, if the channel isn’t secure, would be accepted. Similarly, if you used the Connection object constructor that takes ID and password, you can DEFINITELY assert an ID which, if the channel is not secure, will be accepted by the QMgr.You can test this using the following:
If the QMgr is on UNIX/Linux and not secure, the app will run as
mqm. I would not suggest running like this, the correct response would be to secure it. But this is one way to test and see whether it is secure or not.