Click here to Skip to main content
14,549,626 members

Connecting to IBM MQ (with SSL)

Rate this:
5.00 (2 votes)
Please Sign up or sign in to vote.
5.00 (2 votes)
19 May 2020CPOL
All items needed to successfully connect to IBM MQ
Connecting to IBM MQ is really an annoying task, whether for the configuration side or programming side. In this post, I will go through all the items needed to successfully connect to IBM MQ.

Introduction

Supporting IBM MQ in your code is not an easy task. I can say the main reason for that is the lack of samples, very complicated configurations, lack of proper and easy documentation and last but not the least, a very bad user experience by IBM itself.

Background

To be able to understand this tip, you need the following:

  • Basic programming knowledge
  • IBM MQ installed (information in this post has been tested on versions 7.5, 8.0 and 9.0).
  • This code was tested using .NET Framework 4.7.2. but I am sure the code will work fine with 4.5 and 3.5.
  • This code was tested using IBM MQ DLL's version 8.0.0.5 amqmdnet.dll, amqmdxcs.dll.

Using the Code

Configuration - Normal Mode

Before we start our code, we need to start the proper configuration of our IBM MQ, the best and easiest way is through command. There are many ways to configure it, so if you prefer another way, that's Ok, as long as you know it’s working fine. Also, many of the below commands might not seem necessary.

*** Please note that the below configurations are not suitable for production servers. ***

Before we start with IBM MQ configuration, let's create a new windows user and call it "MQUser". This user must be a member of the group "mqm". This group will be available after installing IBM MQ.

Create a New Queue Manager with name QM:

crtmqm QM

Start Queue Manager:

strmqm QM

Start MQSC to execute commands for our Queue Manager:

runmqsc QM

// Expected Output: 
// 5724-H72 (C) Copyright IBM Corp. 1994, 2011.  ALL RIGHTS RESERVED.
// Starting MQSC for queue manager QM.

Create a new Local Queue with name (Queue1):

DEFINE QLOCAL (QUEUE1)

// Expected Output:      
// 1 : DEFINE QLOCAL (QUEUE1)
// AMQ8006: WebSphere MQ queue created.

Disable CHLAUTH rules:

ALTER QMGR CHLAUTH (DISABLED)

// Expected Output: 
// 2 : ALTER QMGR CHLAUTH (DISABLED)
// AMQ8005: WebSphere MQ queue manager changed.

Create a new Channel with name CHANNEL1 and set the value of MCAUSER to our user MQUser:

DEFINE CHANNEL (CHANNEL1) CHLTYPE (SVRCONN) TRPTYPE (TCP) MCAUSER('MQUser')

// Expected Output: 
// 3 : DEFINE CHANNEL (CHANNEL1) CHLTYPE (SVRCONN) TRPTYPE (TCP)
// AMQ8014: WebSphere MQ channel created.

Create a listener:

DEFINE LISTENER (LISTENER1) TRPTYPE (TCP) CONTROL (QMGR) PORT (1414)

// Expected Output: 
// 4 : DEFINE LISTENER (LISTENER1) TRPTYPE (TCP) CONTROL (QMGR) PORT (1414)
// AMQ8626: WebSphere MQ listener created.

Start our listener:

START LISTENER (LISTENER1)

// Expected Output: 
// 5 : START LISTENER (LISTENER1)
// AMQ8021: Request to start WebSphere MQ listener accepted.

Last command, close command:

end

// Expected Output: 
// 6 : end
// 6 MQSC commands read.
// No commands have a syntax error.
// All valid MQSC commands were processed.

Quick Connect Test

Using the below, you can easily connect to IBM MQ, noting the following:

  • UTF-8 is not a must, you can use UTF-16.
  • Many optional params not mentioned (below sample) are properties of object queueMessage if needed:
    • CorrelationId
    • MessageId
    • ReplyToQueueName
  • The code will type IBM MQ error code. A full list of the error codes can be found on the IBM website.
  • Username and Password in our configuration is not needed, uncomment the username / password assignment if needed.
using IBM.WMQ;
using System;
using System.Collections;
using System.Text;

namespace MQTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string strQueueManagerName = "QM";
            string strChannelName = "CHANNEL1";
            string strQueueName = "QUEUE1";
            string strServerName = "127.0.0.1";
            int intPort = 1414;
            string strMsg = "Hello IBM, this is a message";

            Hashtable queueProperties = new Hashtable
            {
                { MQC.HOST_NAME_PROPERTY, strServerName },
                { MQC.CHANNEL_PROPERTY, strChannelName },
                { MQC.PORT_PROPERTY, intPort },
                { MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED }
            };

            //Set Username
            //MQEnvironment.UserId = "User";

            //Set Passowrd
            //MQEnvironment.Password = "123";

            //Define a Queue Manager
            try
            {
                MQQueueManager myQM = new MQQueueManager(strQueueManagerName, queueProperties);

                //Define a Message
                MQMessage queueMessage = new MQMessage();
                queueMessage.Format = MQC.MQFMT_STRING;
                queueMessage.CharacterSet = Encoding.UTF8.CodePage;
                queueMessage.Write(Encoding.UTF8.GetBytes(strMsg));

                //Define a Queue
                var queue = myQM.AccessQueue
                    (strQueueName, MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING);
                MQPutMessageOptions queuePutMessageOptions = new MQPutMessageOptions();
                queue.Put(queueMessage, queuePutMessageOptions);
                queue.Close();
                Console.WriteLine("Success");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine();
        }
    }
}

Configuration - SSL

Now let’s start the complicated part. Configuring a secure connection between IBM MQ and your client code. Before we start, there are many important notes that you need to know:

  • There are two ways to connect to IBM MQ with SSL, the first one which the client shares is its certificate. And the other way is without client sharing the certificate.
  • This code connects to IBM MQ over SSL using what is called "anonymous IBM MQ connection". More details can be found here. In this mode, the client doesn’t send its certificate.
  • During my work with IBM, I found that many of the parameters defined inside IBM MQ assemblies are not used and even useless. I might be mistaken but all evidences show otherwise. Through this post, I will add the word (useless) next to each of these parameters, maybe someone will explain this to me and to everyone else in the comments of this article.

To start SSL configuration with SSL, let's go back to the command prompt:

  1. Navigate to SSL folder under your Queue Manager folder, this can be found under your installation location which by default is: "C:\Program Files (x86)\IBM\WebSphere MQ\Qmgrs\QM\ssl":
    pushd "C:\Program Files (x86)\IBM\WebSphere MQ\Qmgrs\QM\ssl"
  2. Execute command to create the ssl repository with a name matching your Queue manager name and password of 12345.
    runmqckm -keydb -create -db QM.kdb -pw 12345 -type cms -stash 
  3. Let's create a self signed certifcate so we can use it for our testing:
    runmqckm -cert -create -db QM.kdb -dn "CN=QM,OU=QM,O=SunJ,L=Amman,S=Amman,C=JO" 
    -pw 12345 -label ibmwebspheremqqm -size 2048 -expire 365 -sig_alg SHA256_WITH_RSA 
    Its very important to notice the following:
    1. QM.kdb is the repository that we created in Step 2 which matches the Queue Manager name.
    2. -label in the command must be "ibmwebspheremq" followed by "QM" our Queue Manager name in lower case.
    3. All certificate params like 'L=, S=, C=' can be changed as you wish.
    4. The remaining param must be left as it is, unless you know what exactly you are doing.
  4. Extract the certificate?

    We are not going to extract the certificate here as we mentioned above, we will be connecting without sending a certificate from the client side. A very important note in case you want to use the other way for connecting is:

    1. IBM MQ client assemblies go to the trusted store and only load a certificate with the name "ibmwebspheremq" following by your local machine user that is running the code in lower case. This takes me to the first (useless) parameter in IBM MQ assemblies which is "MQEnvironment.CertificateLabel" or "MQC.label".

      This was very strange to me... I even decomipled IBM assembly to see if it’s actually used or not and below is the only code that is used to load the certificate. It might be there for future use, but for sure it’s very confusing and misleading.

      RemoteCertificateValidationCallback(true),
      new LocalCertificateSelectionCallback(this.FixClientCertificate));
      var storeLocation = StoreLocation.LocalMachine;
      X509Store x509Store = new X509Store(StoreName.My, storeLocation);
      x509Store.Open(OpenFlags.OpenExistingOnly);
      X509Certificate2Collection x509Certificate2Collection =
                                      new X509Certificate2Collection();
      X509Certificate2Enumerator enumerator = x509Store.Certificates.GetEnumerator();
      var clientCertName =
          string.Concat("ibmwebspheremq", Environment.UserName.ToLower());
      while (enumerator.MoveNext())
      {
          X509Certificate2 current = enumerator.Current;
          if (current.FriendlyName.ToLower() != clientCertName)
          {
               continue;
          }
          x509Certificate2Collection.Add(current);
      }
      

      More details about this from IBM website under "IBM WebSphere MQ client".

    2. As you can see in IBM code, it’s looking for the Friendly name to find the certificate, which will be empty if you use the "runmqckm -cert -extract" command. My recommendation is to use PowerShell to verify your license friendly name and change it. Otherwise, your code won’t pick it up.
  5. Configure your Queue Manager to use SSL:
    1. Right click your queue manager and choose "Properties".
    2. From the left menu, choose "SSL".
    3. In the SSL repository, set the location and the name of the repository that we created in the first step "QM.kdb" but do not add the extension with it. The final path will be "C:\Program Files (x86)\IBM\WebSphere MQ\qmgrs\QM\ssl\QM". A very common mistake is either to add the extension or forget the name of repository, unfortunately IBM WebSphere will not notify that you have put invalid key at all.

      Image 1

    4. Now Click "OK", then "Yes" to the confirmation dialog.
  6. The final step is configuring your Channel:
    1. Right click your channel and click "Properties".
    2. Again, from the right menu choose "SSL".
    3. We need to set the SSL Cipher Specs value to "TLS_RSA_WITH_AES_128_CBC_SHA256", but before we do this brings our 2nd (useless) parameter "MQEnvironment.SSLCipherSpec" or "MQC.SSL_CIPHER_SPEC_PROPERTY".

      You can set this parameter in your code to whatever you want, it won't make any difference. In fact, the client will use windows default cipher specs which is set in your group policy which usually defaults to "TLS_RSA_WITH_AES_128_CBC_SHA256".

      This is even more strange the certificate label, you can see many of the samples on IBM Website show that you need to set the value in your code as you configured it inside your channel. But what it actually does is it just tells the client to use SSL code. So imagine this is a flag that is called "Use SSL" or not.

      You can try to change it to "TLS_RSA_WITH_AES_256_CBC_SHA256" in both your code and Channel SSL configuration and you will get the below error inside the event viewer.

      Image 2

    4. Final step and as we mentioned before, our client code will not send a certificate from its side, so we need to set "SSL Authentication" value to "Optional".
    5. Click Ok.

Modify Code to Support SSL

Our code won't work anymore, so let's add few more lines to modify our code with the SSL, all that we need to add is:

MQEnvironment.SSLCipherSpec = "TLS_RSA_WITH_AES_256_CBC_SHA256";

As I mentioned before, although the SSLCipherSpec is useless to set Cipher Specs, it works as a flag to switch on SSL mode.

Full Final Code

using IBM.WMQ;
using System;
using System.Collections;
using System.Text;

namespace MQTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string strQueueManagerName = "QM";
            string strChannelName = "CHANNEL1";
            string strQueueName = "QUEUE1";
            string strServerName = "127.0.0.1";
            int intPort = 1414;
            string strMsg = "Hello IBM, this is a message";

            //Enable SSL
            MQEnvironment.SSLCipherSpec = "TLS_RSA_WITH_AES_256_CBC_SHA256";

            Hashtable queueProperties = new Hashtable
            {
                { MQC.HOST_NAME_PROPERTY, strServerName },
                { MQC.CHANNEL_PROPERTY, strChannelName },
                { MQC.PORT_PROPERTY, intPort },
                { MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED }
            };

            //Set Username
            //MQEnvironment.UserId = "User";

            //Set Passowrd
            //MQEnvironment.Password = "123";

            //Define a Queue Manager
            try
            {
                MQQueueManager myQM = 
                       new MQQueueManager(strQueueManagerName, queueProperties);

                //Define a Message
                MQMessage queueMessage = new MQMessage();
                queueMessage.Format = MQC.MQFMT_STRING;
                queueMessage.CharacterSet = Encoding.UTF8.CodePage;
                queueMessage.Write(Encoding.UTF8.GetBytes(strMsg));

                //Define a Queue
                var queue = myQM.AccessQueue
                (strQueueName, MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING);
                MQPutMessageOptions queuePutMessageOptions = new MQPutMessageOptions();
                queue.Put(queueMessage, queuePutMessageOptions);
                queue.Close();
                Console.WriteLine("Success");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine();
        }
    }
}

Points of Interest

IBM MQ is one of the leading queuing systems that is created and maybe the most commonly used. However, IBM fails badly by making what's supposed to be a very easy job a really a long and hard process of trial and error.

Between the lack of proper validation on IBM MQ WebSphere, hidden properties and rules that can be seen by special command lines "Such as main block rule" to the unused misleading variables and configurations inside the published assemblies.

Based on my findings while working with IBM, I am sure there are many other params that can be considered as unused as well. Although on the other hand, all of these might be a mistake on my side.

History

  • 19th May, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sufyan S Jabr
Technical Lead
United Arab Emirates United Arab Emirates
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pin
mohammed barqawi24-May-20 9:26
Membermohammed barqawi24-May-20 9:26 
QuestionBetter do an article about IBM MQ on Cloud Pin
Издислав Издиславов20-May-20 20:15
MemberИздислав Издиславов20-May-20 20:15 
SuggestionA few extra hints Pin
Morag Hughson18-May-20 23:39
MemberMorag Hughson18-May-20 23:39 
AnswerRe: A few extra hints Pin
Sufyan S Jabr19-May-20 9:09
MemberSufyan S Jabr19-May-20 9:09 
AnswerRe: A few extra hints Pin
Morag Hughson19-May-20 23:37
MemberMorag Hughson19-May-20 23:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Tip/Trick
Posted 18 May 2020

Tagged as

Stats

2.1K views
2 bookmarked