1
votes

Created a IBM MQ on IBM Cloud and tried connecting with JMS client provided by IBM . It fails in authorization.

The same program works on my local queue manager. Any insight would help me in my exploration of IBM MQ on cloud.

  • environment = JDK 1.8
  • MQ client Jar = 9

I gave the application user name/API key, not sure why its not connecting

Followed IBM documentation https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.sec.doc/q118680_.htm https://developer.ibm.com/messaging/learn-mq/mq-tutorials/develop-mq-jms/

Exception Trace

Exception in thread "main" 

com.ibm.msg.client.jms.DetailedJMSSecurityRuntimeException: JMSWMQ2007: Failed to send a message to destination 'RequestQ'.
JMS attempted to perform an MQPUT or MQPUT1; however IBM MQ reported an error.
Use the linked exception to determine the cause of this error.
    at com.ibm.msg.client.jms.DetailedJMSSecurityException.getUnchecked(DetailedJMSSecurityException.java:270)
    at com.ibm.msg.client.jms.internal.JmsErrorUtils.convertJMSException(JmsErrorUtils.java:173)
    at com.ibm.msg.client.jms.internal.JmsProducerImpl.send(JmsProducerImpl.java:633)
    at com.ibm.mq.samples.jms.JmsPutGet.main(JmsPutGet.java:122)
Caused by: com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2035' ('MQRC_NOT_AUTHORIZED').

/*
* (c) Copyright IBM Corporation 2018
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.ibm.mq.samples.jms;


import javax.jms.Destination;
import javax.jms.JMSConsumer;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.JMSProducer;
import javax.jms.TextMessage;

import com.ibm.mq.constants.MQConstants;
import com.ibm.msg.client.jms.JmsConnectionFactory;
import com.ibm.msg.client.jms.JmsConstants;
import com.ibm.msg.client.jms.JmsFactoryFactory;
import com.ibm.msg.client.wmq.WMQConstants;

/**
 * A minimal and simple application for Point-to-point messaging.
 *
 * Application makes use of fixed literals, any customisations will require
 * re-compilation of this source file. Application assumes that the named queue
 * is empty prior to a run.
 *
 * Notes:
 *
 * API type: JMS API (v2.0, simplified domain)
 *
 * Messaging domain: Point-to-point
 *
 * Provider type: IBM MQ
 *
 * Connection mode: Client connection
 *
 * JNDI in use: No
 *  ReadMe -CompatibleMode
 *  
 */

public class JmsPutGet {

	// System exit status value (assume unset value to be 1)
	private static int status = 1;
	private static final String HOST = "ibm hostname"; // Host name or IP address
	private static final int PORT = 32442; // Listener port for your queue manager
	private static final String CHANNEL = "xxx.APP.SVRCONN"; //.APP.SVRCONN"; // Channel name
	private static final String QMGR = "QMxxx"; // Queue manager name
	private static final String APP_USER = "appusername"; // User name that application uses to connect to MQ
	private static final String APP_PASSWORD = "IBM API Key"; // Password that the application uses to connect to MQ
	private static final String QUEUE_NAME = "TestRequestQ"; // Queue that the application uses to put and get messages to and from
	
	/**
	 * Main method
	 *
	 * @param args
	 */
	public static void main(String[] args) {

		// Variables
		JMSContext context = null;
		Destination destination = null;
		JMSProducer producer = null;
		JMSConsumer consumer = null;



		try {
			// Create a connection factory
			JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
			JmsConnectionFactory cf = ff.createConnectionFactory();

			// Set the properties
			cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, HOST);
			cf.setIntProperty(WMQConstants.WMQ_PORT, PORT);
			cf.setStringProperty(WMQConstants.WMQ_CHANNEL, CHANNEL);
			cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
			cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, QMGR);
			cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "JmsPutGet (JMS)");
			cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
			cf.setStringProperty(WMQConstants.USERID, APP_USER);
			cf.setStringProperty(WMQConstants.PASSWORD, APP_PASSWORD);
			/*cf.setBooleanProperty(JmsConstants.USER_AUTHENTICATION_MQCSP, false);*/
			/*cf.setBooleanProperty(MQConstants.USE_MQCSP_AUTHENTICATION_PROPERTY, false);*/
			/*cf.setBooleanProperty("WMQConstants.USER_AUTHENTICATION_MQCSP",false);*/
			

			// Create JMS objects
			context = cf.createContext();
			destination = context.createQueue("queue:///" + QUEUE_NAME);

			long uniqueNumber = System.currentTimeMillis() % 1000;
			TextMessage message = context.createTextMessage("Your lucky number today is " + uniqueNumber);

			producer = context.createProducer();
			producer.send(destination, message);
			System.out.println("Sent message:\n" + message);

			consumer = context.createConsumer(destination); // autoclosable
			String receivedMessage = consumer.receiveBody(String.class, 15000); // in ms or 15 seconds

			System.out.println("\nReceived message:\n" + receivedMessage);

			recordSuccess();
		} catch (JMSException jmsex) {
			recordFailure(jmsex);
		}

		System.exit(status);

	} // end main()

	/**
	 * Record this run as successful.
	 */
	private static void recordSuccess() {
		System.out.println("SUCCESS");
		status = 0;
		return;
	}

	/**
	 * Record this run as failure.
	 *
	 * @param ex
	 */
	private static void recordFailure(Exception ex) {
		if (ex != null) {
			if (ex instanceof JMSException) {
				processJMSException((JMSException) ex);
			} else {
				System.out.println(ex);
			}
		}
		System.out.println("FAILURE");
		status = -1;
		return;
	}

	/**
	 * Process a JMSException and any associated inner exceptions.
	 *
	 * @param jmsex
	 */
	private static void processJMSException(JMSException jmsex) {
		System.out.println(jmsex);
		Throwable innerException = jmsex.getLinkedException();
		if (innerException != null) {
			System.out.println("Inner exception(s):");
		}
		while (innerException != null) {
			System.out.println(innerException);
			innerException = innerException.getCause();
		}
		return;
	}

}
2
With security exceptions the client doesn't get much information about what blocked the connection. Have you checked the Queue Manager logs to see why the Queue Manager blocked the connection? Could you add that to the question please.Rob Parker
Checked the QManager logs it shows Ensure that a password is specified by the client application and that the password is correct for the user ID. The authentication configuration of the queue manager connection determines the user ID repository. For example, the local operating system user database or an LDAP server.sivaganti

2 Answers

0
votes

Most probably the reason could be that the User which is trying to Get/Put message in the queue via "CLOUD.APP.SVRCONN" channel does not have proper access. By default the Channel Authentication Records might be blocking this user to GET/PUT message.

Solution

  1. Try using "CLOUD.ADMIN.SVRCONN" and your application now should be able to GET/PUT message.

  2. Provide appropriate access to your user in channel authentication records for CLOUD.APP.SVRCONN.

0
votes

To extend on the responses from Rob and Paras above, the two most common reasons for that 2035 response when trying to connect to MQ on Cloud are typically as follows;

  1. Needing to enable use of MQCSP so that the full (long) password is passed to the queue manager, details available here
  2. Setting up appropriate authorization permissions to access queues whose names don't start with "DEV.", details of which are here. (access to the DEV. queues is permitted by default, but other queues must be explicitly authorized for your application

As Rob suggested, the queue manager error logs should show details to indicate which of those cases you might be in, and can be downloaded from the "Logs and diagnostics" tab inside the queue manager details tab in the IBM Cloud user interface.

Regards, Matt.