I'm writing an installer wrapper for a Windows C# Service. The installer is written in C# but needs to execute Powershell commands. As part of the installation I need to either get the current user's credentials, or have the user provide credentials. I need to use a PowerShell for the service installation (using New-Service), but I need to provide the credentials as a PSCredential object.
Such an object can be returned by Get-Credentials, but I can't invoke this command without accessing the PS Host UI, which I don't seem to be able to do.
I can do this the lazy way, and throw up a custom dialog asking for a username and password, and cram those in to a new PSCredential, but that is very bad practice.
I can also get these credentials by PInvoking my way through CredUIPromptForWindowsCredentials, but again, this is extremely kludgy and eventually results in a plain text password in memory which I'd like to avoid.
Surely there is some intermediate? I'm running this interaction from a WPF form, so I can happily present the user with a credentials dialog, but I don't know how to do this in a sensible way.
It would also be nice if there was a secure way to create a service and pass through the currently logged in user as the "run as" user.
Simply put, I want to create a Windows service that runs as a specified user. How do I do this programmatically in C#?
Any advice would be appreciated.
It is a bit unclear of what you want to do.
Are you using powershell inside c# code or powershell only, to install the c# code?
Are you searching for a solution in powershell or c#?
Are you asking for a solution on password security or on secure service creation?
This (https://learn.microsoft.com/en-us/dotnet/api/system.security.securestring?view=net-7.0) c# class: "Represents text that should be kept confidential, such as by deleting it from computer memory when no longer needed. This class cannot be inherited."
I would use this (https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/convertto-securestring?view=powershell-7.3) for powershell.
Related
I'm building a software application and it was requested that a user/pass system be implemented with it for security reasons. I'm implementing it in Visual Studio and was curious to if it was possible that I prompt the windows login/pass be used instead of having to build my own structure? Thanks in advance
What you're looking for is the Windows API CredUIPromptForCredentials. Here is how you use it from C# - PInvoke
However, note that this returns the plaintext username and password to your application. This might be a security issue depending on if your user trusts your app or not.
I don't know any way to invalidate the current credentials so Windows forces a prompt for internal NTLM/Kerberos auth.
I have scoured the web looking for bits and pieces of a more comprehensive solution. I have been unsuccessful in my efforts, so I send up a call for help.
The problem:
I have a .Net/C# WebApp that uses windows integrated authentication. The application is a custom form application that allows users to submit requests. These requests are then routed to supervisors and other parties that will review and approve the requests.
For audit purposes, I must have each supervisor "Sign" the form. The easy solution - use the active browser session information. A user clicks the "approve" button and that information is logged into the database (ID and date/time). But the auditors don't like this solution. They view it as insecure. They want a separate challenge for credentials where users are forced to enter an ID and password (and very soon present a token/PIN combo in lieu of ID/password).
To satisfy this in an infopath version of this form, I used CredUIPromptForCredentials. That code (although written in C#) does not directly port to the new custom WebApplication. I did some digging and uncovered a number of resources on the newer CredUIPromptForWindowsCredentials:
How to show Windows Login Dialog?
Show Authentication dialog in C# for windows Vista/7
How to show authentication dialog in C# .Net 3.5 SP1
Windows Security Custom login validation
This is really in the spirit of what I'm trying to accomplish. With very few modifications to the code in the articles above (and borrowing from some code in my old InfoPath form), I was able to get a working system of prompting and testing.
I would be happy to share the existing code if anyone is interested, but it is VERY similar (nearly verbatim) to the existing code referenced above. The only difference is a separate isAuthenticated method that actually tests the credentials by instantiating a DirectoryEntry object and passing that object to a DirectorySearcher object to test if the credentials worked.
But no so fast. This code, as I said, works, but ONLY when I run in debug mode in Visual Studios 2012. If I visit the site by entering the address and click the button to "sign" the form, the site spins and never shows the security dialog. It's almost as if (and this is just my guess) the IIS settings that allow windows authentication are preventing the applications request to prompt for credentials. This is not the case when I run the site through the debugger.
Once I get past that barrier, I have to actually do some further testing to see if this code will support authentication with a PKI card. I am guessing it will since CredUI passes the prompting to windows to handle.
So here are the questions:
1) What could possibly be preventing the windows security window from popping up when the method is called through the IIS server VS running in Debug (localhost)?
2) Does anyone have any experience with implementing CredUIPromptForWindowsCredentials to work with PKI?
2a) If so, does CredUIPromptForWindowsCredentials actually support PKI without any additional code (assuming that the windows workstations are configured with all of the hardware, drivers, and middleware)?
Thanks in advance for any insight you can lend.
Phil S.
Looking your problem and as an old Auditor, may I recommend an detour to satisfy your auditing team? PKI is not the most safe thing around...
1) Provide a normal LOGIN/PASSWORD form, without any special instruction or Credentials (that could be frauded or stolen "on the fly"). Preferable, utilize HTTPS in this page.
2) Once the guy inform the data, pass a 2-Factor Authentication using SMS (INstant Message). The cost is really irrelevant (see Twilio to get some idea). Obviously, each guy, beyond his login/password, must have his phone within database.
3) This way you can ensure that the Supervisor is really the guy who had approved/sign the page.
It´s the safer mode and, because of it, Facebook, Google Mail and others are utilizing this method.
Sorry, I know I not answered you as you need, but it´s safer than your proposal.
Good luck!
I'm testing a small utility program. It behaves differently depending on whether it's being run with administrative rights or not. Therefore, my test framework needs to invoke the program both with and without admin rights, to check that it behaves appropriately.
The test framework is written in C#. Our CI server will run the test at midnight each day, so it's no good popping up access confirmations or similar; there won't be a human being there to press the button or type in credentials. I would prefer to avoid having to store the administrator's password if possible.
Where do I start with this? It looks like ProcessStartInfo can take a username, domain and password - but that would require the admin password to be compiled into the test framework. (Like that will work on more than one PC!) I've also seen answers that say something about WindowsIdentity and impersonation - but that seems to be to change the user ID of the current process, not the external process that I'm trying to invoke.
What about this:
Your test framework expects the username/password for the admin rights via command line parameters
your CI server calls this with the parameters - at least there you have to store the password. Any non-interactive solution demands the storage of the password somewhere
Your test framework will spawn the application then with ProcessStartInfo.
At least the password is not stored in code anymore, which makes it better to manage and not to leak it beyond Admin´s scope ;)
BR Florian
We are developing a C# .NET windows service.
Our service is running under the system account, and we are trying to impersonate the logged in user USER.
The impersonation works ok, i.e. when calling System.Security.Principal.WindowsIdentity.GetCurrent() after the impersonation we get the correct user 'USER'.
The problem is that when we try to access the user profile we do not get the expected results.
One example is accessing the registry CURRENT_USER. We get an access denied error.
When using a third party function, which we assume uses the registry in part, we get the details for the "real" (prior to impersonation) user.
Also when callingEnvironment.ExpandEnvironmentVariables("%TEMP%") we get the system profile instead of the logged-in user profile.
Is there a way to completly impersonate a different user?.
I know we can use LoadUserProfile to get a specific user profile, but this is not good for us, because we are running a third party dll that uses the current user profile.
Our impersonation code is base on this
As you have discovered, impersonation won't set up HKEY_CURRENT_USER or the environment.
This is because the impersonation token is per-thread, and HKCU and environment are per-process.
If you need to access the user's usual environment, you will need to use HKEY_USERS\SID and the impersonated user's SID e.g. HKEY_USERS\S-1-5-21-12345678-12345678-12345678-1234 for example. Call LoadUserProfile to ensure the key is loaded. (If it is supposed to be the the currently logged-on user it should be loaded already, so you should probably not do that, but check it exists and return an error if not).
You can also work out what their usual environment would be, because this is under the key "Environment" within the HKCU. You merely need to combine that with the system environment.
If the third party DLL actually requires HKCU and the environment to be set up correctly, you will need to create a process within the user's logon session to host the DLL, and send the results of whatever operation back somehow. If only the environment is required, you can create a child process and set the environment manually.
However you haven't said why you want to do this. It sounds like you have settled on this as a portion of the solution to a larger problem. If possible I'd recommend that you see if there is a way to do what you need without getting the user's environment or HKCU at all.
Why can't the DLL just run directly in the user's own session? Why is a service required at all? Can you re-architect your solution so there is a user-mode part which runs in the logon session and hosts the third-party DLL, and it communicates with the service so that the service only does what is absolutely required?
I notice that the code doesn't call LoadUserProfile, so the users profile isn't loaded.
Note in the remarks of that function, HKEY_CURRENT_USER still isn't replaced though.
I think you can solve this issue (before calling the third party DLL) by calling RegOverridePredefKey.
Note that a lot of voodoo might be involved in getting this all working right - I'd try to make sure the override happens as late as possible before the third party call, and is reverted as soon as possible afterwards (hoping that this is all a single call to the library).
As an alternative, I'd seriously try looking around for a different 3rd party offering that doesn't require all of this jumping through hoops.
We have a thick-client that needs to access resources on a share where a client may not be logged on. The client might be on a Windows domain or it could be a mixed environment without a domain, so the user would have to log on to the server locally. In the past, one work around was to create a shortcut on the user's desktop to the share, which opens Windows Explorer, which opens a password prompt that grants or denies access to the share. How can I get the user to signon to the share without relying on Windows Explorer? What does Windows Explorer do that I can have my app do to demand access to the share?
I have read Access files from network share in c# web app, but I am doing this in a WinForms app and want it to be interactive. I have also read How to prompt for a Password, but that code just prompts for strings from the user rather than invoking the UI that demands and grants access to the share. I would rather not have my app know the user's password as much as trigger the OS to demand access for the network resource.
You could take a look at the Win32 API CredUIPromptForCredentials ( or CredUIPromptForWindowsCredential if you're running on Vista/Win2k8, you should check the winver to decide which call to make).
This method actually invokes the regular credentials prompt but you get the credentials (awful, I know).
PInvoke.Net has sample code showing how to call this function from C# (in the PInvoke sample you have to pass CREDUI_FLAGS.DO_NOT_PERSIST for flags if you've specified false in save. Weird, I know).
More info (and a unmanaged sample) on the great Keith brown wikibook on security
Once you get the credentials (in a secure string) you can then impersonate the user to get to the resource (using logonuser).
And it's ugly. I understand you want Windows to show the standard prompt dialog and you don't want to know about the credentials.
I'm wondering if a ugly hack like using System.Diagnostics.Process to launch a hidden explorer.exe on the remote UNC would not do the trick. You'd have to find a way to wait for the user to have entered the credentials and then kill the spawned explorer process.