Reputation: 3757
Machine A and Machine B are in different domains. Machine A uses a VPN to gain access to Machine B's network.
I am trying to impersonate a user for the purpose of using Microsoft.Web.Adminstration
to do some administrationy things in IIS on Machine B.
I have tried the solution here: https://forums.iis.net/t/1162205.aspx?Using+Microsoft+Web+Administration+on+a+remote+machine+not+in+the+domain. The returnValue from LogonUser is false for me. When I started writing this I thought maybe the difference was that the poster was working with machines in two different but trusted domains though now I see one of his machines was just in a workgroup. I'm honestly not sure how that scenario compares to mine... whether it should be effectively the same or not.
I also tried another solution that used different values for the logon type (NewCredential instead of Interactive) and different logon provider (WinNt50 instead of Default) because it claimed it addressed my issue of the domains being untrusted.
Also tried combining the two solutions, but so far nothing has worked.
I started out doing this in an asp.net mvc project, but switched to a console application when the 1st solution required me to call CoInitializeSecurity
which, apparently, requires that it has not been called beforehand and I didn't know how to prevent it in an mvc project (in a console application I just had to disable the Visual Studio Hosting Process).
And I should mention that I am able to use the NetworkCredential
class with the NetworkConnection
class (https://gist.github.com/AlanBarber/92db36339a129b94b7dd) to connect to the target machine and write files. So I absolutely know that the user/pass work and I am able to use them from the client machine for file access. I just can't figure out how to impersonate with them.
I don't think I can put a bounty on this right away, but if someone is able to provide a solution I will add a bounty as soon as I can and give it to you.
Upvotes: 6
Views: 2536
Reputation: 4421
I am not sure what you're trying to do, I guess you would like to execute some code "as the user" that you use in the VPN tunel and not the user that you used to login, am I correct?
if so you would need to "impersonate", can you try to execute you application using "Run As" and then execute your code, should execute at the user on the VPN domain (if authorised on your pc)
You can then keep using the "Run As" method or have a look at:
[DllImport("advapi32.DLL")]
public static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
[DllImport("advapi32.DLL")]
public static extern bool RevertToSelf();
void SomeMethod()
{
IntPtr phToken = IntPtr.Zero;
ImpersonateLoggedOnUser(phToken);
//... some code
RevertToSelf();
}
The bummer about hardcoded usernames is that
Passwords provided to developers in the source code was a bit of an issue with Uber sometime ago
Run As is "as safe" as providing VPN credentials to some one... you can provide a "reminder" if the user starts the application in his own credentials by comparing the user with the reverted one.
An other option is to use the windows credentials manager (type credential manger or open it from your control panel) and you will see something like this. go ahead and try and see if your target can be configured with this credentials provider. You'd add something like this, do not forget the port if you need a port, the sample shows a trusted connection on a remote server to SQL server.
If you find that this works then you can manage user's via the credentials manager API as answered here. I'd prompt the user for user name and password and store those when a connection fails.
Upvotes: 2
Reputation: 672
Perhaps this will help, I have a solution working using a similar approach.
Imports
using System.Security.Principal;
using System.Runtime.InteropServices;
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
static WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
public static extern int LogonUserA(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
Methods:
static private bool impersonateValidUser(string userName, string domain, string password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
static private void undoImpersonation()
{
impersonationContext.Undo();
}
I hope this gets you there!
Upvotes: 1