Connect to MQ using the secure keys (public & private key) - ibm-mq

I am able to establish connection to QManager using unsecure channel and was able to do what ever I want to do.
But now I am trying to connect to the same QManage through secure channel; I have got the Security keys ( both public and private key ) generate from MQ server but I am not sure how to incorporate the key and establish MQ connection.
I googled and found some answer which suggested the below approach but it didn't work.
System.setProperty("javax.net.ssl.trustStore","path to public key");
System.setProperty("javax.net.ssl.keyStore","path to private key");
Exception I got.
com.ibm.mq.MQException : MQJE001: Completion Code '2', Reason '2537'.
I would appreciate some guidance or sample code on how to connect to QManager using security key.
#JoshMc -- please find answer to your question below
Are you using IBM MQ Classes for Java or IBM MQ Classes for JMS?
I am using IBM MQ Classes for Java
What version of IBM MQ are the jar files you are using from?
Version 7
What version of MQ is the queue manager you are attempting to connect to?
Version 8
Are you attempting to have MQ validate a client cert (Check the value of SSLCAUTH on the SVRCONN channel)
Yes. I have public and private key generated from MQ server by MQ Admin (I have no access to MQ server) and need to use it to connect to the MQ server.
Paste any errors that show up in the queue managers AMQERR01.LOG when you attempt to connect.
I don't have access to the log file.
Below is working code; I am able to connect to unsecure channel and send message
public void MQSender(){
MQQueueManager QMgr = null;
try {
MQEnvironment.hostname = "hostname";
MQEnvironment.channel = "UNSECURE";
//MQEnvironment.channel = "SECURE";
MQEnvironment.port = 8080;
QMgr = new MQQueueManager("QManager");
int openOptions = MQConstants.MQOO_OUTPUT;
MQQueue queue = QMgr.accessQueue("QNAME",openOptions);
MQPutMessageOptions pmo = new MQPutMessageOptions();
pmo.options = MQConstants.MQPMO_LOGICAL_ORDER | MQConstants.MQPMO_SYNCPOINT;
MQMessage message = new MQMessage();
message.writeString("TEST");
queue.put(message, pmo);
QMgr.commit();
} catch (Exception e) {
if(QMgr!=null){
try {
QMgr.backout();
} catch (MQException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
}
}

You are missing the option specifying the ciphersuite to use from your code:
MQEnvironment.sslCipherSuite
This knowledge center article may help: https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.dev.doc/q031220_.htm
And do you have your trusted certs and private cert/key pair in JKS stores?
These should be more like:
System.setProperty("javax.net.ssl.trustStore","path to JKS file containing certificates required to validate server certificate");
System.setProperty("javax.net.ssl.keyStore","path to JKS file containing certificate and private key of the client");

Related

How to connect to IBM MQ without using username and password If am trying to connect getting this error? I am not supplying username and password

public MQQueueConnectionFactory mqQueueConnectionFactoryB() {
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
try {
mqQueueConnectionFactory.setHostName(host2);
mqQueueConnectionFactory.setQueueManager(queueManager2);
mqQueueConnectionFactory.setPort(port2);
mqQueueConnectionFactory.setChannel(channel);
mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqQueueConnectionFactory.setSSLCipherSuite(sslCipherSuite);
} catch (JMSException e) {
log.error("Failed in connection establishment" + e.getMessage());
e.printStackTrace();
}
return mqQueueConnectionFactory;
}
Failed in connection establishmentJMSWMQ2013: The security authentication was not valid that was supplied for queue manager 'QM1' with connection mode 'Client' and host name 'xxxxxxxx'.
com.ibm.msg.client.jms.DetailedJMSSecurityException: JMSWMQ2013: The security authentication was not valid that was supplied for queue manager 'QM1' with connection mode 'Client' and host name 'xxxxxxxx'.
Please check if the supplied username and password are correct on the queue manager to which you are connecting. For further information, review the queue manager error logs and the Securing IBM MQ topic within IBM Knowledge Center.
at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:531)

How to send jms message from one server hosting an application to another server hosting another application both are hosted in Websphere servers

I understand if both the message queues (receiver and response) are present in the same server location I can use the JNDI connection factory and queue name
jms/myqueue_qcf1
jms/myqueue1, to connect to the queue and send message to jms/myqueue_qcf2, jms/myqueue2
But in case of Interserver connectivity, will this be the same
When the firewall b/w both the servers is opened.
The MQ myqueue2 is setup as remote mq in Websphere.
Any help with code reference would be appreciable.
public void myAppListener extends MessageListener{ //getting message from MQ1 -
//sent by some other application - MQ1 is Local
//in appServer1
private static final String JMS_LC_JNDI_NAME = "jms/liftcargo_lara_qcf";
private static final String JMS_LC_QUEUE_NAME = "jms/APP.OUT.REQUEST";
public void onMessage(Message msg){
try{
TextMessage requestMessage = (TextMessage) msg;
String reqMessage = requestMessage.getText();
String correlationId = requestMessage.getJMSCorrelationID();
sendXMLToNextAppMQ(reqMessage , correlationId)
}
}
public static void sendXMLToNextAppMQ(String message, String correlID) throws JMSException { //The MQ to which the message is forwarded to is a Remote MQ, in different server appServer2
try {
InitialContext context = new InitialContext();
QueueConnectionFactory queueConnectionFactory =
(QueueConnectionFactory)context.lookup(JMS_LC_JNDI_NAME);
System.out.println("Connection Factory data :: "+queueConnectionFactory.toString());
Queue queue = (Queue) context.lookup(JMS_LC_QUEUE_NAME);
System.out.println("Check Queue Name :: "+queue.toString());
QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
QueueSession session = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueSender queueSender = session.createSender(queue);
TextMessage message1 = session.createTextMessage();
message1.setText(message);
message1.setJMSType("Tunnel message from CCAM.LARA.OUT.REQUEST MQ to
LIFTCARGO.OUT.LARA.REQUEST MQ");
message1.setJMSDestination(queue);
message1.setJMSCorrelationID(correlID);
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
queueSender.send(message1);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (JMSException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
In Method sendXMLToNextAppMQ (i.e., tunnel the msg recieved in MQ1 in appServer1 to MQ2 in appServer2) is there any other jndi properties needed to mention to connect appServer1 to MQ2 in appServer2 (firewall is opened b/w appServer1 & appServer2)
If your target request queue is on a different server, your application will still have the same code, but the name you supply will not be the name of a QLOCAL on the queue manager you are connected to, but instead will be a QREMOTE. If you are using JNDI to refer to your queues, you don't even have to change the name of the queue, only the referenced real MQ queue name need be changed.
For example, if you were using the command line JMSAdmin tool, you'd change the name in the QUEUE attribute only:-
DEFINE Q(myqueue2) QUEUE(Q.FOR.REQUESTS)
Then on your two queue managers, there would be definitions that look something like these:-
Local QM (QM1)
DEFINE QREMOTE(Q.FOR.REQUESTS) RNAME(WORK.QUEUE) RQMNAME(QM2) XMITQ(QM2)
DEFINE QLOCAL(QM2) USAGE(XMITQ) DESCR('Transmission queue for messages to QM2')
DEFINE QLOCAL(MY.REPLY.Q) DESCR('My application queue for responses')
DEFINE CHANNEL(TO.QM2) CHLTYPE(SDR) CONNAME('(qm2.machine.com(1414)') XMITQ(QM2)
DEFINE CHANNEL(TO.QM1) CHLTYPE(RCVR)
Remote QM (QM2)
DEFINE QLOCAL(WORK.QUEUE)
DEFINE QLOCAL(QM1) USAGE(XMITQ) DESCR('Transmission queue for messages to QM1')
DEFINE CHANNEL(TO.QM2) CHLTYPE(RCVR)
DEFINE CHANNEL(TO.QM1) CHLTYPE(SDR) CONNAME('qm1.machine.com(1414)') XMITQ(QM1)
In addition, it is good practice in a request/reply application, to provide the name of the queue where the response should be sent as part of the request message, and to code the responding application to read those fields (ReplyTo fields) and use them to send the reply message back, thus not requiring an extra QREMOTE definition on the Remote QM (QM2 in my example).

Connection is not established between Eclipse Paho and IBM Websphere MQ

I am novice user to IBM MQ. Basically I want to establish the connection between Client(Eclipse Paho) and IBM MQ Queue Manager.
I have performed the following steps:
I have installed the IBM MQ v.9.0
Created a Queue Manager
Started a Queue Manager as a service with the port number(1414)
Create a Server channel and assigns this with created Queue Manager.
At Client side:
Downloadd Eclipse Paho, which is MQTT Java client.
try to small program to connect with started Queue Manager.
Followinig is the program.
import java.util.logging.Logger;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class MQMTTFactory {
private static Logger log = Logger.getLogger(MQMTTFactory.class.getName());
private MQMTTFactory() {
}
static final String BROKER_URL = "tcp://<<Ipaddress>>:1234";
static final String M2MIO_DOMAIN = "<Insert m2m.io domain here>";
static final String M2MIO_STUFF = "things";
static final String M2MIO_USERNAME = "Guest";
static final String M2MIO_PASSWORD_MD5 = "<m2m.io password (MD5 sum of password)>";
static MqttClient myClient = null;
public static MqttClient getMqttClient() {
MqttConnectOptions connOpt;
if (myClient == null) {
connOpt = new MqttConnectOptions();
connOpt.setCleanSession(true);
connOpt.setKeepAliveInterval(3000);
connOpt.setUserName(M2MIO_USERNAME);
// connOpt.setPassword(M2MIO_PASSWORD_MD5.toCharArray());
// Connect to Broker
try {
myClient = new MqttClient(BROKER_URL,
MqttAsyncClient.generateClientId(), new MemoryPersistence());
myClient.connect(connOpt);
} catch (MqttException e) {
log.severe("Client connection to the MQTT Broker is failed");
e.printStackTrace();
System.exit(-1);
}
}
return myClient;
}
}
But the above program is failed to establish the connection with the server.
the following is the error while running the above program.
Unable to connect to server (32103) - java.net.ConnectException: Connection refused: connect
Could any body tell me what might be the wrong? or Any suggestions.
The Eclipse Paho client only works with the MQTT Protocol. This is a topic based pub/sub protocol and does not support Message Queues.
While IBM-MQ can support MQTT it is not enabled by default.
I suggest you read the following 2 articles to get a better understanding
https://www.ibm.com/developerworks/community/blogs/aimsupport/entry/what_is_mqtt_and_how_does_it_work_with_websphere_mq?lang=en
https://www.ibm.com/support/knowledgecenter/en/SS9D84_1.0.0/com.ibm.mm.tc.doc/tc00110_.htm

Issue connecting to a remote JMS queue from standalone client

I am new to JMS and have an issue connecting to a remote JMS queue from my standalone client. Any hints on resolving this issue would be highly appreciated.
Right now I have a JavaFX standalone application that runs on multiple clients and a glassfish server 3.1.2.2 running on a remote Unix machine. I am having a hard time pushing messages from my standalone app on to the queue that is residing on the server.
Client Mc: Windows PC (No server installed)
Remote Mc: Unix (GlassFish 3.1.2.2 installed)
JMS resources on the server:
JMS Destination Resource
JNDI Name: jms/ReferralQueue
Physical Destination Name: ReferralQueue
Resource Type: javax.jms.Queue
JMS Connection Factory
Pool Name: jms/ReferralConnectionFactory
JNDI Name: jms/ReferralConnectionFactory
Resource Type: javax.jms.QueueConnectionFactory
JMS Service Type: Embedded
JMS Message Store Type: File
Client Side Code to connect to the server:
jms.properties:
org.omg.CORBA.ORBInitialHost=UNIX MC URL
org.omg.CORBA.ORBInitialPort=7676
Service Locator design to implement resource caching
public class JMSServiceLocator {
private static JMSServiceLocator singletonService = null;
private static QueueConnectionFactory qFactory;
private static Queue queue;
private InitialContext context;
private static Properties properties = new Properties();
private Map cache;
static {
try {
singletonService = new JMSServiceLocator();
} catch (Exception e) {
//error handling
}
}
private JMSServiceLocator() {
try {
loadProperties();
context = new InitialContext(properties);
cache = Collections.synchronizedMap(new HashMap());
} catch (Exception e) {
//error handling
}
}
public static JMSServiceLocator getInstance() {
return singletonService;
}
public QueueConnectionFactory getQueueConnectionFactory() {
String qConnFactoryName = "jms/ReferralConnectionFactory";
qFactory = null;
try {
System.out.println("/********************Comment after Testing*****************************/");
Hashtable env = context.getEnvironment();
System.out.println("**env.size::" + env.size());
Enumeration names = env.keys();
while (names.hasMoreElements()) {
String str = (String) names.nextElement();
System.out.println("**" + str + "=" + env.get(str));
}
System.out.println("/**********************************************************************/");
if (cache.containsKey(qConnFactoryName)) {
qFactory = (QueueConnectionFactory) cache.get(qConnFactoryName);
} else {
qFactory = (QueueConnectionFactory) context.lookup(qConnFactoryName);
cache.put(qConnFactoryName, qFactory);
}
} catch (Exception e) {
//error handling
}
return qFactory;
}
public Queue getQueue() {
String queueName = "jms/ReferralQueue";
queue = null;
try {
if (cache.containsKey(queueName)) {
queue = (Queue) cache.get(queueName);
} else {
queue = (Queue) context.lookup(queueName);
cache.put(queueName, queue);
}
} catch (Exception e) {
//error handling
}
return queue;
}
private static void loadProperties() {
//Load jms properties
}
}
Eventually sending message to the server:
JMSServiceLocator jmsLocator = JMSServiceLocator.getInstance();
QueueConnectionFactory qConnFactory = jmsLocator.getQueueConnectionFactory();
qConnection = qConnFactory.createQueueConnection();
session = qConnection.createSession(false, ession.AUTO_ACKNOWLEDGE);
queue = jmsLocator.getQueue();
// Push and publish the message
messageProducer = session.createProducer(queue);
textMessage = session.createTextMessage();
textMessage.setText(message);
messageProducer.send(textMessage);
Hmmm... Now I observe a strange behavior...
I created a new GlassFish 3.1.2.2 server instance on the client machine with no jndi, no connection factories, and no jms queues what so ever.
I have started this server instance and executed the standalone client application. Strangely, everything works fine and the message is directly being pushed to the remote queue.
Did any one come across this kind of issue? I am suspecting that probably the application is loading the dependent GlassFish jars in the classpath only when a server instance (could be any random instance, totally unrelated) is started.
I have the following jars in my standalone application classpath:
*C:\Program Files\glassfish-3.1.2.2\glassfish\lib\gf-client.jar
*C:\Program Files\glassfish-3.1.2.2\glassfish\lib\appserv-rt.jar
*C:\Program Files\glassfish-3.1.2.2\glassfish\lib\install\applications\jmsra\imqbroker.jar
*C:\Program Files\glassfish-3.1.2.2\glassfish\lib\install\applications\jmsra\imqjmsra.jar
I have also posted this on Oracle JMS and GlassFish forums and haven't got a solution. Any help on this issue would be highly appreciated.
Thanks.
I think you found out by now what the problem was:
the JMS client jars were missing on the client (Client Mc: Windows PC (No server installed)).
You don't need a full Glassfish installation on the clients but only the JMS client jars (gf-client.jar) plus all the other jars referenced by gf-client.jar.

IBM.XMS ExceptionListener not firing

I am using IBM.XMS 2.0.0.5 and MQ Client 7.0.1.5 and have created a connection, set the exception listener, started the connection and started listening for messages using a message listener. This works fine, except that the ExceptionListener does not fire when I disable the network connection. Instead I get an unhandled socket exception.
I have gone back to the example given on the IBM site and recreated the error:
If I disable the network connetion I get the unhandled socket exception and the exceptionListener does not get fired.
using System;
using System.Threading;
using IBM.XMS;
public class Sample
{
public static void Main()
{
XMSFactoryFactory factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
IConnectionFactory connectionFactory = factoryFactory.CreateConnectionFactory();
connectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, "**********");
connectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, "*****");
connectionFactory.SetIntProperty(XMSC.WMQ_PORT, 1414);
connectionFactory.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT);
connectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "*********");
//
// Create the connection and register an exception listener
//
IConnection connection = connectionFactory.CreateConnection();
connection.ExceptionListener = new ExceptionListener(OnException);
ISession session = connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
IDestination queue = session.CreateQueue("queue://***********");
//
// Create the consumer and register an async message listener
//
IMessageConsumer consumer = session.CreateConsumer(queue);
consumer.MessageListener = new MessageListener(OnMessage);
connection.Start();
while (true)
{
Console.WriteLine("Waiting for messages....");
Thread.Sleep(1000);
}
}
static void OnMessage(IMessage msg)
{
Console.WriteLine(msg);
}
static void OnException(Exception ex)
{
Console.WriteLine(ex);
}
}
I'll put the answer up in the hope that it saves someone the time it wasted for me.
You need to use an unmanaged client connection in order to connect up an exception listener to your connection.
connectionFactory.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT_UNMANAGED);
If it's just worked in Unmanaged mode, then it's a bug at XMS .NET v2.0.0.5. It should work in Managed mode also (XMSC.WMQ_CM_CLIENT_MANAGED). Please move to the latest fix pack and test again.

Resources