IBMMQDotnetClient using windows credentials instead of application specified credentials - c#

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.

Related

Using WindowsIdentity to connect to ManagementScope(WMI)

I have a .net core application that is hosted on IIS. This application utilizes System.Management to connect to other machines to gather information.
I am noticing that some of my calls are getting an access denied response. The application pool is running as a user that is an admin on the remote machines. However the ManagementScope does not appear to be using the Application pool's identity.
I was wondering if there is a way to use the WindowsIdentity while connecting to the remote machine?
I am looking for something like the following.
private ManagementScope GetManagementScope(string machineName)
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
ConnectionOptions options = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Username = identity.Name
// Something here to pass along the password?
};
ManagementPath path = new ManagementPath
{
Server = machineName,
NamespacePath = "\\root\\MicrosoftIISv2"
};
return new ManagementScope(path, options);
}
I have tried hard coding the User name and password and that works fine but I would really like to use the Application pools identity.
I think, and hope, there is no way to retrieve the password.
The only way is to pass it as external parameter and possibly stored in a secure application.
Maybe you can consider to store this secret in Azure Key Vault and retrieve that setting.

DotNet HttpClient.DefaultProxy Property not reading system settings on Win10

The docs indicate, that the default Proxy-Setup for the HttpClient will be determined through the presence of environmental variables and/or the system wide proxy settings.
I set the proxy-auth credentials like this:
setx http_proxy http://user:password#proxyIP:proxyPort/, and to be sure rebootet the system.
Since the Windows proxy-settings dialog does not allow to set username and password, i included there the proxy address and port.
Now i try to read them back though the CredentialCache with my C# app.
However the CredentialCache.DefaultCredentials are still empty and the proxy blocks and responds with 407 exceptions. Which is correct, since i cannot pass the credentials.
How do i have to setup the username and password to be able to read them from the CredentialCache?
I would like to be able to go this way, since very old code, long time ago shipped to customers, using a WebRequest object together with this settings is able to go through.:
UseDefaultCredentials = true;
Proxy = WebRequest.GetSystemWebProxy();
Proxy.Credentials = CredentialCache.DefaultCredentials;
Thats why i would like to also be able to write somethin to Windows that in turn gets read out of the Cache.

How to specify AWS credentials in C# .NET core console program

I am trying to test a .NET core console program to publish a message to SNS. As I had issues trying to get it to work in Lambda, I want to try it in a non-Lambda environment. In Lambda, security is covered by the role, but in a console program, I presume that I have to specify my access key and secret somehow.
I've read this page: http://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#net-dg-config-creds-sdk-store, but still totally confused.
I'm running on my local development computer, not an EC2 instance. No intent to go to production with this, just trying to test some code.
I'm on Visual Studio 2015, .NET Core 1.0. I've used Nuget to get the following:
"AWSSDK.Extensions.NETCore.Setup": "3.3.3",
"AWSSDK.SimpleNotificationService": "3.3.0.23",
Based on the answer to How to set credentials on AWS SDK on NET Core? I created the /user/.aws/credentials file (assuming credentials was the file name and not the directory name).
But that question/answer doesn't address how to actually use this file. The code I'm running is below.
public static void Main(string[] args)
{
Console.WriteLine("Started");
//var awsCredentials = new Amazon.Runtime.AWSCredentials()
var client = new Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.EUWest2);
//var client = new Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient(awsCredentials, Amazon.RegionEndpoint.EUWest2);
//Amazon.SimpleNotificationService.Model.PublishResponse publishResp = null;
SendMessage(client).Wait();
Console.WriteLine("Completed call to SendMessage: Press enter to end:");
Console.ReadLine();
}
The error I'm getting on the new client is:
An unhandled exception of type 'Amazon.Runtime.AmazonServiceException' occurred in AWSSDK.Core.dll
Additional information: Unable to find credentials
I see there is a way to pass an AWSCredentials object to that constructor, but I don't understand how to build it. Amazon.Runtime.AWSCredentials is an abstract class, so I can't use it in a "new" statement.
Based on Dan Pantry's answer, here is a simple short answer with code highlighted (note the region enum in the second line):
var awsCredentials = new Amazon.Runtime.BasicAWSCredentials("myaccesskey", "mysecretkey");
var client = new Amazon.SimpleNotificationService.AmazonSimpleNotificationSer‌​viceClient(
awsCreden‌​tials, Amazon.RegionEndpoint.EUWest2);
Use a role if possible, but above works when needed. Then the question is where to store the access key/secret key; could be environment variable, config file, prompt the user, or any of the usual suspects.
AWS-CLI and Python use credentials from here: c:\Users\username\.aws\credentials, so the C# could just read that file so as not to put the codes in the C# program itself. But then each user/developer that runs the program would need to set their credentials there.
There is also now a concept of running Lambda on your local machine, but I haven't tried it yet:
https://dzone.com/articles/run-aws-lambda-functions-locally-on-windows-machin#:~:text=Step%201%3A%20Download%20SAM%20local,version%20with%20the%20command%20below.&text=Step%203%3A%20Write%20your%20lambda,yaml%20on%20the%20root%20level.
So the point is that if you are going to do Lambda, but you need to test locally first, this would probably be worth trying.
You'll want to construct one of its child classes instead of the abstract one. You can take a look at the class hierarchy here.
For posterity, the options are:
AnonymousAWSCredentials - Authenticates as an anonymous user.
BasicAWSCredentials - You provide your credentials to the class constructor directly.
EnvironmentAWSCredentials - Credentials are pulled from the environment variables of the running executable.
InstanceProfileAWSCredentials - Pulls credentials from the Instance Profile of the EC2 instance running the executable. This, obviously, only works on EC2.
SessionAWSCredentials - Similar to BasicAWSCredentials, except utilises an AWS Session using a temporary session token from AWS STS.
RefreshingSessionAWSCredentials - Similar to SessionAWSCredentials, but refreshes when the STS token expires.
Note that the default strategy in the absence of a credentials object involves checking the Environment Variables and then the instance profile.
If you want to have the program pull credentials from ~/.aws/credentials, you'll need to do some legwork. There used to be a StoredProfileAWSCredentials class, but that appears to have been removed - you can find more information by looking at this github issue. This is only useful, really, in development as you won't be using ~/.aws/credentials in production but probably instance profiles - I'd suggest instead using the default strategy and using Environment AWS credentials in test or development environments.
I take this approach at work since we use a command line tool to grab us limited time tokens from AWS STS and plunk them into the current shell for use for the next hour.
EDIT: It appears you're using AWS Lambda. These have federated access to AWS resources based on the roles assigned to them, so this should work using the default credential strategy in the aws-sdk library which uses instance profiles. So this is only really necessary for development/testing, in which case I would again recommend just using environment variables.
This is a really old question, and the existing answers work, but I really don't like hard-coding my Access Key Id and Secret Key values directly into source code, even for throw-away projects I'm doing on my local machine. For one thing, I might revoke those keys in the future, so I want to leverage the credentials in my .aws\credentials file.
To do that for my .NET core apps (including console apps, etc), I first add two NuGet packages:
Microsoft.Extensions.Configuration.Json
AWSSDK.Extensions.NETCore.Setup
Then, I add an applications.json file to my project, which contains the following (note - you need to right-click the file, and set "Copy to output" as either "copy if newer" or "always"):
{
"AWS": {
"Profile": "default",
"ProfilesLocation": "C:\\Users\\my-user-profile-folder\\.aws\\credentials",
"Region": "us-west-2"
}
}
Finally, I create an instance of the AWS SDK client using the following:
var builder = new ConfigurationBuilder().AddJsonFile("appsettings.Development.json", optional: false, reloadOnChange: true);
var options = builder.Build().GetAWSOptions();
var s3client = options.CreateServiceClient<IAmazonS3>();
This way, if I update my credentials file, I'm fine. Or if my code gets zipped up and emailed to a friend or co-worker, I don't accidentally send them my credentials also.
There is another way to do this, without needing to add the NuGet packages also, which many people might prefer. You can use the new SharedCredentialsFile class and AWSCredentialsFactory, like this (using the "default" profile here, and assumes your credential file is in the default location, same as the other method):
var sharedFile = new SharedCredentialsFile();
sharedFile.TryGetProfile("default", out var profile);
AWSCredentialsFactory.TryGetAWSCredentials(profile, sharedFile, out var credentials);
var s3Client = new AmazonS3Client(credentials);
Note - I'm not checking that the two Try* methods are succeeding here, which you probably should do. Details on using these classes are here: https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#how-to-create-an-amazons3client-using-the-sharedcredentialsfile-class
While keeping your credentials in the shared "credentials" file, you can redefine the ProfilesLocation when creating the CredentialProfileStoreChain
//define your file location here:
var chain = new CredentialProfileStoreChain(#"C:\aws\credentials");
// input the name of your credentials here:
if (chain.TryGetAWSCredentials("nameofprofile", out AWSCredentials awsCredentials))
{
//executes if the credentials were found and inserted into awsCredentials
}
else
{
// executes if the credentials were not found
}
Taken from here: https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/creds-locate.html
For those struggling with profile names, here is where you can find it.
Contents of your ~/.aws/credentials:
[YOUR_PROFILE_NAME]
aws_access_key_id = ***
aws_secret_access_key = ***
aws_security_token = ***
aws_session_expiration = ***
aws_session_token = ***
So then in your application you access the credentials like this:
var chain = new CredentialProfileStoreChain();
var result = chain.TryGetAWSCredentials("YOUR_PROFILE_NAME", out var credentials);
Resources:
accessing credentials and profiles: https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#creds-locate
named profiles: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html

MQ .NET Assemblies MQC.USER_ID_PROPERTY Ignored?

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.

TFS 2010 - Why am I getting "TF30063 You are not authorized to access.." error when impersonating?

I am attempting to create a bug in TFS2010 by impersonating a user but always get
"TF30063 You are not authorized to access.."
I first authenticate using a service account and then attempt to impersonate a separate user account. I can successfully create Work Items using either account both programmatically and in the web UI. However, when I try to create the Work Item used an impersonated account (either way around) I always get this error. My code is:
public int Save(List<KeyValuePair<string, string>> values, ticketType type,string user)
{
// get the Uri to the project collection to use
Uri tfsuri = new Uri("http://94.23.12.119:8085/tfs");
// get a reference to the team project collection (authenticate as generic service account)
using (var tfs = new TfsTeamProjectCollection(tfsuri, new System.Net.NetworkCredential("username", "password", "servername")))
{
tfs.EnsureAuthenticated();
//Now get the details of the user we want to impersonate
TeamFoundationIdentity identity = GetImpersonatedIdentity(tfsuri,tfs,user);
//Now connect as the impersonated user
using (TfsTeamProjectCollection ImpersonatedTFS = new TfsTeamProjectCollection(tfsuri, identity.Descriptor))
{
ImpersonatedTFS.EnsureAuthenticated();
var workItemStore = GetWorkItemStore(ImpersonatedTFS);
// create a new work item
WorkItem wi = new WorkItem(GetWorkItemType(type, workItemStore));
{
//Values are supplied as a KVP - Field Name/Value
foreach (KeyValuePair<string,string> kvp in values)
{
if (wi.Fields.Contains(kvp.Key))
{
wi.Fields[kvp.Key].Value = kvp.Value;
}
}
ValidationResult = wi.Validate();
}
if (ValidationResult.Count == 0)
{
wi.Save();
return wi.Id;
}
else
{
return 0;
}
}
}
}
It successfully gets the impersonated identity but falls over on
ImpersonatedTFS.EnsureAuthenticated();
Both accounts have the 'Make requests on behalf of others' permission set.
First let me clarify one thing first. It seems your application is a server application, in which case there is no value in using EnsureAuthenticated(). It is just a performance tuning trick to help UI/desktop clients.
Now back to your main issue:
- If your application works as expected when you access locally but fails when you access remotely, then please read on, otherwise this is not the solution for you.
The reason it is failing is because the SPN needs to be added to the service account on the active directory. It is necessary for Kerberos authentication to take place.
This is something that TFS team needs to explain because many developers will forget about it while focusing at the job it hand. Hope this helps.
To learn more about SPN's and Kerberos fundamentals, check out these resources:
Kerberos for the busy admin.
Introduction to Kerberos SPN
I hope this helps.
Thanks!
Where do your users have the Make requests on behalf of others permission set? Is it at the Project Collection level (accessed via Team > Team Project Collection Settings > Security..) or at the TFS server level (accessed via Team Foundation Administration Console > Application Tier > Security..) ?
I think your problem is that you only have permission to impersonate at the 'Server' level, but you're trying to impersonate in a collection.
This is what Taylor has to say in his Introducing TFS Impersonation blog post:
This permission is encapsulated within each Team Project Collection
and within the Configuration Server. This means that if User A has
this permission on TPC1 he will not be allowed to impersonate users
when talking to TPC2 or the Configuration Server. Similarly, if User
B has this permission on the Configuration Server she will not be able
impersonate users when talking to any of the Team Project Collections.

Categories

Resources