Articles Connecting to IBM MQ (with SSL) by Sufyan S Jabr

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,439
Credits
574
Connecting to IBM MQ (with SSL)
Sufyan S Jabr - 19 May 2020
[SHOWTOGROUPS=4,20]
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. Для просмотра ссылки Войди или Зарегистрируйся
  • 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();
}
}
}



[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,439
Credits
574
[SHOWTOGROUPS=4,20]
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 Для просмотра ссылки Войди или Зарегистрируйся. 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":
    Hide Copy Code
    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.
    Hide Copy Code
    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:
    Hide Copy Code
    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.
      Hide Copy Code
      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 Для просмотра ссылки Войди или Зарегистрируйся 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 keyat 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.
      Посмотреть вложение 1665
    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)

[/SHOWTOGROUPS]