MQ .NET Assemblies MQC.USER_ID_PROPERTY Ignored? - c#

I'm currently working with the MQ .NET assemblies and am attempting to read queue depths of various queues for a monitoring application. We have the code working in Java, but our new application is in C# and it would be preferable to keep all this logic in the same application.
From what I've heard online, .NET assemblies ignore MQC.USER_ID_PROPERTY and instead use the user ID of whoever is running the application. Is there really no way to override this? This seems a very strange feature/bug. I know that MQC.TRANSPORT_PROPERTY is supposed to influence how the UserID is inferred, but whether I set to MQC.TRANSPORT_MQSERIES_MANAGED or MQC.TRANSPORT_MQSERIES_CLIENT, I see the same ID going up in Wireshark and get the same error back (MQRC_NOT_AUTHORIZED). Has anyone else found a workaround for this fairly large issue?
properties = new Hashtable();
properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
properties.Add(MQC.HOST_NAME_PROPERTY, hostName);
properties.Add(MQC.PORT_PROPERTY, port);
properties.Add(MQC.CHANNEL_PROPERTY, channelName);
properties.Add(MQC.USER_ID_PROPERTY, userId);
properties.Add(MQC.PASSWORD_PROPERTY, "");
// create connection
queueManager = new MQQueueManager(queueManagerName, properties);

If you are using MQ .NET client (or for that matter MQ C client also) version prior to v8, the user id set by the application is not sent to the queue manager. Instead logged in user id is passed to queue manager for authentication. This is a known behavior of MQ versions prior v8.
You can develop and use what is known as security exit to perform user authentication. A security exit performs username and password authentication against a repository, such as the local operating system on the MQ server, or an LDAP repository.
You can also use SSL/TLS if that's suitable to you. Otherwise you can move up to use MQ v8 to make use of the out of the box user id/password authentication.

Related

IBMMQDotnetClient using windows credentials instead of application specified credentials

In using IBMMQDotnetClient v9.2.0.1 in .NET Core, I attempt to connect to a client using
private MQQueueManager Connect()
{
System.Collection.Hashtable properties = new System.Collections.Hashtable();
properties.Add(MQC.USER_ID_PROPERTY, "username");
properties.Add(MQC.PASSWORD_PROPERTY, "password");
// more settings below
return new MQQueueManager(QueueManagerName, properties);
}
The issue is this still attempts to pass my personal windows credentials even after having set the userid and password when configuring the queue manager properties. How do I ensure that the credentials passed by the application replace my personal windows creds when running the application.
Edit:
For more context, the output options are configured as:
public static readonly int OUTPUT_OPTIONS = MQC.MQOO_OUTPUT;
I am not sure if there can be other options that can ensure the passed creds are used as opposed to the windows creds.
For anyone in the future that runs into a similar situation I wanted to give an update on my resolution. I ended up running the IIS server with the credentials that were authenticated with MQ as opposed to a Network Service and this fixed the issue. This allowed me to use the queue manager that had already been set up, without changing its settings in any way.

Two factor authentication with ssh.net

I am trying to connect from a Windows app to a unix server, to run some commands (automating checks on server status). I am using the ssh.net library, and have this code to connect to the server:
using (SshClient ssh = new SshClient("myserver.univ.edu", "myusername", "My!maginaryPa55wrd"))
{
ssh.Connect();
var result = ssh.RunCommand("df -h");
LogText.Text = result.Result; // puts result of command into multiline textbox
ssh.Disconnect();
}
But when I run this, it times out on the connect. I am guessing this is because the server requires two factor authentication. When I log into it with Putty, it will prompt for username and password, it then prompts for a choice of factors ... enter a passcode or "1" for Duo push to xxx-xxx-1212 or "2" for phone call to xxx-xxx-1212.
The SSH.net library says it supports two-factor authentication, but I have searched all over for a way to do it, and I am coming up empty. Any clues as to how to solve this, I'd appreciate it.
The problem is that you don't have two factor authentication, you have single factor and a bunch of interactive options, which is non-standard and not supported by ssh.net. It's not expecting to have to make choices.
To make this work, you would need to modify the ssh.Net code, or better, setup Public Key Authentication with the remote servers, in which case it won't need a password or 2FA.
Any reasonable size organization almost certainly has PKI setup. You would need to check with the admins and see about getting your Public Key added to the servers you'll be checking.
ssh.Net supports public key auth and would eliminate all the problems you're having.

IBM Webshpere MQ client connecting remote queue using SSL

I am trying to connect to the remote queues using secured SSL connection. I have all the details provided by third party regarding SSL connection and Queue Manager details. I have V8 version of MQ client installed on my windows machine.
SSL folder that thirdparty has shared contains jks,kdb,rdb and sth files.
I am using below code to initialize the properties in .net console application
const string SslKeyRepository = #"ssl folder location with key name included";
const string CipherSpec = "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
const string CipherSuite = "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
const string SslPeerName = "Peername";
const string ConnectionType = MQC.TRANSPORT_MQSERIES_CLIENT;
static Hashtable init(String connectionType)
{
Hashtable connectionProperties = new Hashtable
{
{MQC.TRANSPORT_PROPERTY, connectionType},
{MQC.PORT_PROPERTY, 1496},
{MQC.SSL_CERT_STORE_PROPERTY, SslKeyRepository},
{MQC.SSL_CIPHER_SPEC_PROPERTY, CipherSpec},
{MQC.SSL_PEER_NAME_PROPERTY, $"CN=\"{SslPeerName}\""}
};
// Add the connection type
// SSL
// 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:
case MQC.TRANSPORT_MQSERIES_XACLIENT:
case MQC.TRANSPORT_MQSERIES_MANAGED:
connectionProperties.Add(MQC.HOST_NAME_PROPERTY, HostName);
connectionProperties.Add(MQC.CHANNEL_PROPERTY, Channel);
break;
}
return connectionProperties;
}
I have tried few things but I end up getting exception "MQRC_SSL_INITIALIZATION_ERROR"
I would appreciate if you can help me with this.
There are many reasons for MQRC_SSL_INITIALIZATION_ERROR. Some of them are mechanical issues such as whether the keystore files can be accessed. Some are procedural such as whether the handshake fails. The best way to diagnose is methodically checking the configuration and then performing differential testing.
For the first part of this, perform the following checks. If you have already done so, don't cut corners. Do it again.
Verify that the certificates are accessible by issuing runmqakm -cert -list against the KDB to verify that it is structurally intact and the stash file is present with the proper password.
Verify that the kdb file is not in a world-readable directory is that the files are not marked world-readable.
Verify that the service account that runs the app is the owner of the KDB files and containing folder and has write access. (Not sure why but GSKit insists that the KDB must be writeable at run time.)
Issue runmqakm -cert -details to verify that the certificate(s) corresponding to the queue manager is/are present and the details. If the QMgr uses a self-signed cert there will be only one. If the QMgr uses a CA-signed cert there should be an intermediate and a root signer.
Find out from the 3rd party whether they have specified SSLCAUTH(OPTIONAL) or SSLCAUTH(REQUIRED). If OPTIONAL then the KDB should have no personal certs, only signers. If REQUIRED then the KDB must have a personal cert and the label must be ibmwebspheremq[serviceaccount] in lower case.
For the differential testing, try some of the following tests:
Test the app by connecting to a local QMgr using TLS (Note: MQ hasn't used SSL for years. It's TLS now. The old field names still retain SSL labels, though.) until you know that it is correctly configured. Go grab a copy of MQ Advanced for Developers and you can do integration testing on the desktop with your own QMgr, fully licensed for free.
Test using one of the sample programs. Use amqsputc or amqsgetc, depending on whether the real app is supposed to have PUT or GET on the queue. These use the same KDB, samme certs, etc. the main difference being they are known-good code.
Ask your business partner to let you test without SSL to make sure the "mechanical" parts of the configuration are correct. This includes things like the firewall routing, host, port and channel name, QMgr name, etc. If you can't connect with plaintext channels, you definitely won't succeed with TLS channels.
Once that works, test with SSL enabled and SSLCAUTH(OPTIONAL) set at the QMgr. This demonstrates that the client can validate the QMgr's cert.
Once that works, and if the objective is to use mutual authentication, test with SSLCAUTH(REQUIRED) set at the QMgr and a personal cert in the local KDB. This demonstrates that the QMgr can validate the client's cert.
Then, and only then, turn on SSLPEER locally to filter on the QMgr cert's DN.
If these don't help, please update the question with detailed results of your testing. The most common issues include cert labels and KDB permissions. If the business partner gave you the JKS and KDB, these should generally not come with a personal cert, only trusted certs.

Check if an Azure VM is running

I want to query an existing azure virtual machine to check whether it is fully deployed and able to be connected to remotely. Is there any way to do this using the Azure Rest API?
I've outlined my current process and why I desire such a call below.
I am using the Windows Azure management library to create a VM using ComputeManagementClient and the CreateDeploymentAsync function. This then returns a status of Succeeded, if I then do a get on the deployment it has a status of DeploymentStatus.Running.
After this has run I am trying to create a remote powershell connection so I can format the disk. I keep getting an error on this as it is unable to create the session.
WinRM cannot complete the operation. Verify that the specified computer name is valid, that the computer is accessible over the network, and that a firewall exception for the WinRM service is enabled and allows access from this computer. By default, the WinRM firewall exception for public profiles limits access to remote computers within the same local subnet. For more information, see the about_Remote_Troubleshooting Help topic.
If I go to the azure management portal the status is provisioning, I assume this is why i cannot create a session.
Process
CreateAzureVM()
CheckAzureVmCanBeConnectedTo() //I am unable to do this correctly
RunPowershellScriptOnVM() // this fails
You should be able to use Get Deployment to poll for the role's InstanceStatus (note that InstanceStatus != Status). When the InstanceStatus is ReadyRole, you should be able to log into your machine.
There's a distinction between a Deployment status and a Role InstanceStatus. Think of the role as an actual virtual machine, whereas a Deployment may describe multiple VMs.
SubscriptionCloudCredentials certificate = new CertificateCloudCredentials(subscriptionId, x509Certificate);
IComputeManagementClient ComputeManagementClient = new ComputeManagementClient(certificate);
var deployments = ComputeManagementClient.Deployments.GetBySlot(hostedServiceName, DeploymentSlot.YourDeploymentSlot);
var state = deployments.RoleInstances.First().PowerState;
I hope that this will help you.
Without seeing your code it's hard to say exactly what you need to do but I would recommend that you utilise the await keyword to wait for the completion of the call to the Azure API to create the VM. See the code samples under "Deploy a Virtual Machine" in this MSDN guide: http://msdn.microsoft.com/en-us/library/azure/dn722415.aspx#bk_createres

Implement a C# Client that uses WebServices over SSL?

So I've got a ServiceReference added to a C# Console Application which calls a Web Service that is exposed from Oracle.
I've got everything setup and it works like peaches when it's not using SSL (http). I'm trying to set it up using SSL now, and I'm running into issues with adding it to the Service References (or even Web References). For example, the URL (https) that the service is being exposed on, isn't returning the appropriate web methods when I try to add it into Visual Studio.
The underlying connection was closed: An unexpected error occurred on a send.
Received an unexpected EOF or 0 bytes from the transport stream.
Metadata contains a reference that cannot be resolved: 'https://srs204.mywebsite.ca:7776/SomeDirectory/MyWebService?WSDL'
Another quandary I've got is in regards to certificate management and deployment. I've got about 1000 external client sites that will need to use this little utility and they'll need the certificate installed in the appropriate cert store in order to connect to the Web Service. Not sure on the best approach to handling this. Do they need to be in the root store?
I've spent quite a few hours on the web looking over various options but can't get a good clean answer anywhere.
To summarize, I've got a couple of questions here:
1) Anybody have some good links on setting up Web Services in Visual Studio that use SSL?
2) How should I register the certificate? Which store should it exist in? Can I just use something like CertMgr to register it?
There's gotta be a good book/tutorial/whatever that will show me common good practices on setting something like this up. I just can't seem to find it!
Well, I've figured this out. It took me far longer than I care to talk about, but I wanted to share my solution since it's a HUGE pet peeve of mine to see the standard. "Oh I fixed it! Thanks!" posts that leave everyone hanging on what actually happened.
So.
The root problem was that by default Visual Studio 2008 uses TLS for the SSL handshake and the Oracle/Java based Webservice that I was trying to connect to was using SSL3.
When you use the "Add Service Reference..." in Visual Studio 2008, you have no way to specify that the security protocol for the service point manager should be SSL3.
Unless.
You take a static WSDL document and use wsdl.exe to generate a proxy class.
wsdl /l:CS /protocol:SOAP /namespace:MyNamespace MyWebService.wsdl
Then you can use the C Sharp Compiler to turn that proxy class into a library (.dll) and add it to your .Net projects "References".
csc /t:library /r:System.Web.Services.dll /r:System.Xml.dll MyWebService.cs
At this point you also need to make sure that you've included System.Web.Services in your "References" as well.
Now you should be able to call your web service without an issue in the code. To make it work you're going to need one magic line of code added before you instantiate the service.
// We're using SSL here and not TLS. Without this line, nothing workie.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
Okay, so I was feeling pretty impressed with myself as testing was great on my dev box. Then I deployed to another client box and it wouldn't connect again due to a permissions/authority issue. This smelled like certificates to me (whatever they smell like). To resolve this, I used certmgr.exe to register the certificate for the site to the Trusted Root on the Local Machine.
certmgr -add -c "c:\someDir\yourCert.cer" -s -r localMachine root
This allows me to distribute the certificate to our client sites and install it automatically for the users. I'm still not sure on how "security friendly" the different versions of windows will be in regards to automated certificate registrations like this one, but it's worked great so far.
Hope this answer helps some folks. Thanks to blowdart too for all of your help on this one and providing some insight.
It sounds like the web service is using a self signed certificate. Frankly this isn't the best approach.
Assuming you're a large organisation and it's internal you can setup your own trusted certificate authority, this is especially easy with Active Directory. From that CA the server hosting the Oracle service could request a certificate and you can use AD policy to trust your internal CA's root certificate by placing it in the trusted root of the machine store. This would remove the need to manually trust or accept the certificate on the web service.
If the client machines are external then you're going to have to get the folks exposing the service to either purchase a "real" certificate from one of the well known CAs like Verisign, Thawte, GeoTrust etc. or as part of your install bundle the public certificate and install it into Trusted Root certificate authorities at the machine level on every machine. This has problems, for example no way to revoke the certificate, but will remove the prompt.
Thanks for this great tip, took a quick look around at your stuff and you have a lot of good ideas going on. Here's my little bit to add -- I'm figuring out webMethods and (surprise!) it has the same problems as the Oracle app server you connected to (SSL3 instead of TLS). Your approach worked great, here's my addendum.
Given static class "Factory," provide these two handy-dandy items:
/// <summary>
/// Used when dispatching code from the Factory (for example, SSL3 calls)
/// </summary>
/// <param name="flag">Make this guy have values for debugging support</param>
public delegate void CodeDispatcher(ref string flag);
/// <summary>
/// Run code in SSL3 -- this is not thread safe. All connections executed while this
/// context is active are set with this flag. Need to research how to avoid this...
/// </summary>
/// <param name="flag">Debugging context on exception</param>
/// <param name="dispatcher">Dispatching code</param>
public static void DispatchInSsl3(ref string flag, CodeDispatcher dispatcher)
{
var resetServicePoint = false;
var origSecurityProtocol = System.Net.ServicePointManager.SecurityProtocol;
try
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;
resetServicePoint = true;
dispatcher(ref flag);
}
finally
{
if (resetServicePoint)
{
try { System.Net.ServicePointManager.SecurityProtocol = origSecurityProtocol; }
catch { }
}
}
}
And then to consume this stuff (as you have no doubt already guessed, but put a drum roll in here anyway):
var readings = new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading[] {
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 1, created = DateTime.Now.AddDays(-1), reading = 17.34, userID = 2
},
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 2, created = DateTime.Now.AddDays(-2), reading = 99.76, userID = 3
},
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 3, created = DateTime.Now.AddDays(-5), reading = 82.17, userID = 4
}
};
ArchG2.Portal.Utils.wmArchG201.Factory.DispatchInSsl3(ref flag, (ref string flag_inner) =>
{
// creates the binding, endpoint, etc. programatically to avoid mucking with
// SharePoint web.config.
var wsFireWmdReading = ArchG2.Portal.Utils.wmArchG201.Factory.Get_fireWmdReading(ref flag_inner, LH, Context);
wsFireWmdReading.fireWmdReading(readings);
});
That does the trick -- when I get some more time I'll solve the threading issue (or not).
Since I have no reputation to comment, I'd like to mention that Mat Nadrofsky's answer and code sample for forcing SSL3 is also the solution for an error similar to
An error occurred while making the
HTTP request to https://xxxx/whatever.
This could be due to the fact that the
server certificate is not configured
properly with HTTP.SYS in the HTTPS
case. This could also be caused by a
mismatch of the security binding
between the client and the server.
Just use
// We're using SSL here and not TLS. Without this line, nothing workie.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
as mentioned by Mat. Tested with an SAP NetWeaver PI server in HTTPS. Thanks!
Mat,
I had such issues too and I have a way to avoid using certmgr.exe to add certificates to trusted root on a remote machine.
X509Store store;
store = new X509Store("ROOT", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
The 'certificate object' can be created like this:
X509Certificate2 certificate = new X509Certificate2("Give certificate location path here");

Categories

Resources