impersonate multiple users at the same time - c#

I'm making a service in .net that copy files from one domain (Domain A) to other domain (Domain B)
both domain need credentials in order to connect to them so i'm using impersonation.
using (new Impersonator(usr_name_source, domain_source, password_source))
the impersonation is working only for one domain each time, so actually i cannot work how to impersonate both domains at the same time in order to copy the files
so i'm trying this:
using (new Impersonator(usr_name_source, domain_source, password_source))//server authentication
{
using (new Impersonator(usr_name_target, domain_target, password_target))//server authentication
{
DeleteOldFiles(targetPath);
Copy(sourcePath, targetPath);
}
}
but its not working as when i impersonate the inside new Impersonator(usr_name_target, domain_target, password_target)
it forget the outer impersonation.
does anyone has any idea how to do that without mapping drives etc...?

You can only impersonate one user at a time, so your current solution will not work. Basically you are trying to connect to two different network resources. You can P/Invoke WNetAddConnection2 function to connect to network resource of different domain and perform operation as needed. See here for details on WNetAddConnection2: https://msdn.microsoft.com/en-us/library/windows/desktop/aa385413(v=vs.85).aspx
Go through this post to see how you P/Invoke WNetAddConnection2: How to provide user name and password when connecting to a network share

Related

Impersonation works with local shared file, but does not work with remote one

I have a .net/c# web app (web api) with windows authentication. The service is hosted on my local computer, IIS 10. Application pool identity set to me, currently logged in windows user. Computer is in active directory domain.
I want to access shared file using account, currently logged in to the app. File has appropriate permissions. For this purposes I use impersonation like this:
if (HttpContext.Current.User.Identity is WindowsIdentity windowsIdentity)
{
using (windowsIdentity.Impersonate())
{
FileStream stream = new FileStream(#"\\server\share\file.ext", FileMode.Open, FileAccess.Read);
}
}
I logging in with current windows account, the same as set in app pool identity. This works fine with a shared file on a local computer, where the app is hosted. But does not work with a remote shared file, located on another computer. The other computer is in active directory domain too.
From a hosting computer I can access shared file using windows explorer or my browser. Also if I do not impersonate user, .net trying to access shared file with application pool identity account(set to the same user, me) and it succeeded for both, local and remote files.
It also works with impersonated identity got from LogonUser method from advapi32.dll. But it requires user password and I do not want to request password from user, already logged in to app.
What am i doing wrong?
Update: If a shared file located on hosting machine, then logon event generated by windows (security tab in event viewer) shows the right user. If a shared file located on another machine, then logon event generated by windows on this machine shows the anonymous user. So, account somehow lost.
Update 2: Impersonation works if I run site on IIS like localhost(localhost in url). But if I run it using ip or site name it stops working.
Update 3: Wireshark shows the request for getting ticket(to access shared file server) for delegation fails with error "KRB5KDC_ERR_BADOPTION NT Status: STATUS_NOT_FOUND". Delegation for application pool user allowed in AD.
The same ticket(for cifs/fileshareservername) without delegation can be successfully retrieved(wireshark shows) when doing Dir command in cmd. Seems like problem in AD.
Can't for sure if what you're doing is wrong, but I can tell you what I've done to do a very similar thing. My .Net site doesn't have WindowsLogin normally, so I had to make an extra jump that I think you could do to facilitate the same thing, just perhaps not the best answer.
At login ( in my membershipProvider ) I run this code:
try
{
if (LogonUser(user,domain,password, [AD_LOGIN],
LOGON32_PROVIDER_DEFAULT, ref handle))
{
IntPtr tokenDuplicate = IntPtr.Zero;
if (DuplicateToken(handle, SecurityImpersonation,
ref tokenDuplicate) != 0)
{
// store off duplicate token here
}
}
}
finally
{
if (handle != IntPtr.Zero)
{
CloseHandle(handle);
}
}
then when you need to impersonate, do this:
var context = WindowsIdentity.Impersonate(tokenDuplicate);
try
{
// do your file access here
}
finally
{
context.Dispose();
}
I had to do some funny conversion of that tokenDuplicate variable. It's an integer value but pointing at a specific memory address where the token information is stored. It stays good as long as your logged in.
Why you can't do the impersonate directly on your identity, don't know. I just know it worked for me with a token, and that was my method to get a token I could use for impersonation.
It started working for me with the following settings.
IIS:
Application pool identity set to a specific user(let's say IISUser).
Windows authentication enabled for IIS site. Kernel mode enabled (important!).
All other magic is happening in Active directory:
Computer with shared files has an SPN: cifs/%computer_name%.
Hosting computer(where IIS installed) is trusted for delegation. Delegation tab -> Trust this computer for delegation to specified services only -> Use any authentication protocol. Then select SPN from item 1. Important: you should select computer SPN, not IISUser SPN.
IISUser is trusted for delegation for SPN from item 1.

c# check if a windows account is locked out in a specific domain

I'm trying to do something that I don't even know if it is possible.
I have a web application based on C# that runs on a specific server. I want to build a code where the user introduces the domain where the app runs (this server depends on the client, for each client it runs on different servers obviously) and the app returns the local windows user accounts of that domain and information saying if the users are locked out or not.
I've tried to use Win32_UserAccount but it seems to get the users of the network I'm currently using.
Is this possible to do?
Thank you so much
Regards,
Flávio Justino
Try
using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domain"))
{
using(UserPrincipal usr = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "username"))
{
usr.IsAccountLockedOut(); //Gets if account is locked out
}
}
You need to add dpendency System.DirectoryServices.AccountManagement.dll for the above code to work.

C# Impersonation technique

I wanted to remove a config file from a remote machine having IP as : sj1slm612. Now the problem is i do not have full modification rights to that remote machine, so I'm using impersonation technique to do this. Normally when I'm connected to this remote machine via putty, I use 'sudo'. So my question is will the following code be able to solve my problem ? Thanks.
My Code :
AppDomain.CurrentDomain.SetPrincipalPolicy(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);
using (WindowsIdentity Authorized_user = new WindowsIdentity("sj1slm612\\wtsnqa", "password"))
{
using (WindowsImpersonationContext context = Authorized_user.Impersonate())
{
File.Delete(#"/apps/instances/express_13000/configuration/standalone-full.xml");
File.Delete(#"/apps/instances/query_13100/configuration/standalone-full.xml");
File.Delete(#"/apps/instances/wppapi_13200/configuration/standalone-full.xml");
File.Delete(#"/apps/instances/wppgui_13300/configuration/standalone-full.xml");
Console.WriteLine("All config files removed from sj1slm612");
Console.ReadLine();
There are 2 problems with your approach:
You are trying to impersonate a remote machine account on a local machine; this won't work. The credentials of a machine account can only be validated by that machine. In addition, that account has no rights on the local machine, so it doesn't really make sense to impersonate it. You need to impersonate a domain account. When you use a tool like putty, the credentials are sent to the remote machine and not validated by the local machine. This is why you can use a machine account of the remote machine.
You need to give proper paths for the files. Nowhere do you indicate that these files are on the remote machine. Use something like "\\machine\c$\path\to\file".
The details on what are going to work or not will depend on your network and OS, which you didn't specify, though it sounds Linux-ish. There may be a different syntax for referring to remote files that you need to use.

Monitoring Windows service status remotely as non-administrator?

Background: I have an application that, among other parts of its back-end, uses a server-side Windows service to do some of the computation.
What I'm trying to do is display the status of the service (Running vs. Stopped, essentially) on the client, such that the users can know (a) if the background computation is happening, or (b) if they need to go poke their IT guy to check the server. (It's written for an SME customer that doesn't have a full-time IT department or a budget that wants to be spent on fancy service-monitoring-and-alerting software.)
In itself, that's easy enough to do with ServiceController - if you're an administrator on the server, which the users, of course, aren't. Is there a way to read service status from a remote server in .NET as a non-administrative user? (All I need is to read the status; I don't need, and actually specifically don't want, to give the users the rights to stop/restart/alter the service in any way.)
If the user under which your application works doesn't have sufficient permissions for accessing services, you're likely to get an error like this:
service.Status threw an exception of type 'System.InvalidOperationException'
Cannot open MyService service on computer '192.168.0.7'. Access is denied.
You need to switch to another user context to be able to monitor it. If you don't want to do it for entire application (which is rather obvious), try impersonation for the actual piece of code which does the status checking. What should be the user? Actually for the safety reasons, it definitely shouldn't be the user who has an access for entire machine. It should has access just for controlling the services. Ask the administrator to create such a user for you. The status monitoring can be then executed like this:
public string GetServiceStatus(string machine, string service)
{
return Impersonate(
() =>
{
var service = new ServiceController(machine, service);
service.Refresh();
return service.Status;
}, USER, DOMAIN, PASSWORD
);
}
The entire thread with detailed solution can be found here.
Edit:
Let me explain the topic further. The solution I've provided gives the opportunity to change the user context, for some particular piece of code. It can be whatever you want e.g. service status checking. User, under context such an operation is going to be executed, can have granted the access to perform it, or not. It's completely different story though. It's the computer administrator responsibility to grant such an access. In the simplest case he can just add such a user to the Administrators group, which will be reckless, but he can also grant granular access using Group Policy. More detailed information regarding such an administration issues can be found here and here.

Login with Admin user to some domain and copy files client machines with C#

I have got a project that can copy files to another client's desktops in my domain.There is 300+ client machine.But there is a problem.When i run this project in a non admin user account in my domain.It cant copy files getting error about Access Denied , user restrictions.I wanna do this program like this , in non admin user account when user start to copy files ;
first my program will get admin access by loggin in my admin user accoun to domain than will copy files.Than logout.How can i do this ? I wanna do this with C#.
I had a similar problem: Production needed to run one of my programs that processes files on a location on the network where they don't have any access.
I ended up using Impersonation, which allowed me to run the file processing thread under a set of credentials set at runtime by my program.
In AD I created a special user account with all required permissions for exclusive use by this program.
I know it’s not at all secure, but it works and the odds that it would even occur to someone to hack my program to get these credentials is remote.
Anyway, look into Impersonation I found these resources helpful:
Safely Impersonating Another User
Brian Low's ImpersonationHelper class
-Jay
You can switch privileges when starting the program from itself or from another program. You can do this with two programs, one that runs as the user account and then launches your privileged application. (or launch itself with a different command line to indicate the different run-mode.)
To launch a program in C# as a different user, do this,
// Create a secure version of the password
SecureString pass = new SecureString();
foreach ( char c in _pass.Text )
{
pass.AppendChar( c );
}
Process process = Process.Start( "PrivilegedProgram.exe", _arguments, _user.Text, pass, _domain.Text );
you need to change the thread to the context of an admin user. How you do that in a secure way is the challenge. This sounds like a quick utility program where the security may not be a big deal, however. Just change the admin's password once the utility has been run.

Categories

Resources