views:

655

answers:

2

I have the server side of IBM's WebSphere MQ version 6 on a virtual machine running Windows Server 2003, sitting on a Vista desktop. The desktop has the client installed.

I've got a little test program (from their code samples) that puts a message on a queue and takes it off again. This program worked when run on the server directly with the server binding. However, I can't get it to work from the client side with the client binding.

The error I get is CompCode 2, Reason 2035, which is an authorization failure.

I suspect this has to do with the fact that the program runs under my user by default, which is on a domain that the virtual machine doesn't know about (and can't access).

I have set up a local user on the vm that I'd like to connect as (user: websphere, password: websphere), but I'm not clear on how to get this all to work. I have the code that I'm using below, and I've tried various combinations of security exit settings on the channel and endpoints, but I can't get away from 2035.

Anyone have experience with this? Help would be much appreciated!

Code:

using System;
using System.Collections;

using IBM.WMQ;

class MQSample
{
    // The type of connection to use, this can be:-
    // MQC.TRANSPORT_MQSERIES_BINDINGS for a server connection.
    // MQC.TRANSPORT_MQSERIES_CLIENT for a non-XA client connection
    // MQC.TRANSPORT_MQSERIES_XACLIENT for an XA client connection
    // MQC.TRANSPORT_MQSERIES_MANAGED for a managed client connection
    const String connectionType = MQC.TRANSPORT_MQSERIES_CLIENT;

    // Define the name of the queue manager to use (applies to all connections)
    const String qManager = "QM_vm_win2003";

    // Define the name of your host connection (applies to client connections only)
    const String hostName = "vm-win2003";

    // Define the name of the channel to use (applies to client connections only)
    const String channel = "S_vm_win2003";

    /// <summary>
    /// Initialise the connection properties for the connection type requested
    /// </summary>
    /// <param name="connectionType">One of the MQC.TRANSPORT_MQSERIES_ values</param>
    static Hashtable init(String connectionType)
    {
        Hashtable connectionProperties = new Hashtable();

        // Add the connection type
        connectionProperties.Add(MQC.TRANSPORT_PROPERTY, connectionType);

        // Set up the rest of the connection properties, based on the
        // connection type requested
        switch (connectionType)
        {
            case MQC.TRANSPORT_MQSERIES_BINDINGS:
                break;
            case MQC.TRANSPORT_MQSERIES_CLIENT:
                connectionProperties.Add(MQC.HOST_NAME_PROPERTY, hostName);
                connectionProperties.Add(MQC.CHANNEL_PROPERTY, channel);
                connectionProperties.Add(MQC.USER_ID_PROPERTY, "websphere");
                connectionProperties.Add(MQC.PASSWORD_PROPERTY, "websphere");
                break;
        }

        return connectionProperties;
    }

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static int Main(string[] args)
    {
        try
        {
            Hashtable connectionProperties = init(connectionType);

            // Create a connection to the queue manager using the connection
            // properties just defined
            MQQueueManager qMgr = new MQQueueManager(qManager, connectionProperties);

            // Set up the options on the queue we wish to open
            int openOptions = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_OUTPUT;

            // Now specify the queue that we wish to open,and the open options
            MQQueue system_default_local_queue =
              qMgr.AccessQueue("clq_default_vm_sql2000", openOptions);

            // Define a WebSphere MQ message, writing some text in UTF format
            MQMessage hello_world = new MQMessage();
            hello_world.WriteUTF("Hello World!");

            // Specify the message options
            MQPutMessageOptions pmo = new MQPutMessageOptions(); 
            // accept the defaults,
            // same as MQPMO_DEFAULT

            // Put the message on the queue
            system_default_local_queue.Put(hello_world, pmo);

            // Get the message back again

            // First define a WebSphere MQ message buffer to receive the message
            MQMessage retrievedMessage = new MQMessage();
            retrievedMessage.MessageId = hello_world.MessageId;

            // Set the get message options
            MQGetMessageOptions gmo = new MQGetMessageOptions(); //accept the defaults
            //same as MQGMO_DEFAULT

            // Get the message off the queue
            system_default_local_queue.Get(retrievedMessage, gmo);

            // Prove we have the message by displaying the UTF message text
            String msgText = retrievedMessage.ReadUTF();
            Console.WriteLine("The message is: {0}", msgText);

            // Close the queue
            system_default_local_queue.Close();

            // Disconnect from the queue manager
            qMgr.Disconnect();
        }

        //If an error has occurred in the above,try to identify what went wrong.

        //Was it a WebSphere MQ error?
        catch (MQException ex)
        {
            Console.WriteLine("A WebSphere MQ error occurred: {0}", ex.ToString());
        }

        catch (System.Exception ex)
        {
            Console.WriteLine("A System error occurred: {0}", ex.ToString());
        }

        Console.ReadLine();
        return 0;
    }//end of start
}//end of sample
+1  A: 

With Windows-to-Windows connections, WMQ will pass the SID as well as the "short ID" which in this case would be "websphere". This is a little better authorization than you get with non-Windows WMQ which only uses the short ID. The problem is that someone on a non-windows server can connect using the short ID "websphere" and since there is no SID WMQ will accept the connection as thought it were the Windows account.

Two ways to address this. On the QMgr host you can run setmqaut commands to authorize the SID you are actually using to connect. The VM must be able to inquire on the domain where the Windows account lives and the setmqaut command must use -p user@domain syntax.

Alternatively, you can just use the locally defined ID in the MCAUSER of the channel like

ALTER CHL(channel name) CHLTYPE(SVRCONN) MCAUSER('webaphere@vm')

...where 'vm' is the name of the virtual machine and you've authorized the account with setmqaut commands or by putting it into the mqm or administrators group.

Keep in mind this is only for testing! Any channel with a blank or administrative MCAUSER can not only administer WMQ but also execute arbitrary commands on the underlying host server. In the real world you would create accounts with access to queues and the QMgr but not access to administer and you'd put those into all MCAUSER values, then set MCAUSER('nobody') for all the SYSTEM.DEF and SYSTEM.AUTO channels.

Lots more on this available on my web site t-rob.net in the MQ and Links pages. Also, check out:

Comment lines: T.Rob Wyatt: What you didn't know you didn’t know about WebSphere MQ security http://bit.ly/1YYIcV

Comment lines: T.Rob Wyatt: WebSphere MQ security heats up http://bit.ly/17oKEc

T.Rob
A: 

I used to have the same problem. the solution, we need to assign user window account to MQA group or administrator group. Then, add user name of the window account to MCA user in the channel.

Hope this helps