I need to download files from a server to a shared drive directory, creating the directory if it doesn't exist. There are a few things making this more complicated:
I attempt to impersonate, as so:
class Impersonation
{
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON_TYPE_NEW_CREDENTIALS = 9;
const int LOGON32_PROVIDER_WINNT50 = 3;
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
public static void Impersonate(string domain, string user, string password, Action act)
{
//if no user specified, don't impersonate
if (user.Trim() == "")
{
act();
return;
}
WindowsImpersonationContext impersonationContext = null;
IntPtr token = IntPtr.Zero;
try
{
//if no domain specified, default it to current machine
if (domain.Trim() == "")
{
domain = System.Environment.MachineName;
}
bool result = LogonUser(user, domain, password, LOGON_TYPE_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, ref token);
WindowsIdentity wi = new WindowsIdentity(token);
impersonationContext = WindowsIdentity.Impersonate(token);
act();
}
catch (Exception ex)
{
if (impersonationContext != null)
{
impersonationContext.Undo();
impersonationContext = null;
}
//if something went wrong, try it as the running user just in case
act();
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
impersonationContext = null;
}
if (token != IntPtr.Zero)
{
CloseHandle(token);
token = IntPtr.Zero;
}
}
}
}
And a piece of the the actual calling code is (in another class):
private static void CreateDirectoryIfNotExist(string directory, string domain, string username, string password)
{
Impersonation.Impersonate(domain, username, password, () => CreateIfNotExist(directory));
}
private static void CreateIfNotExist(string dir)
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
}
If I run it with the proper login info for the service account, I get an Exception on the Directory.CreateDirectory(string) call:
{System.IO.IOException: This user isn't allowed to sign in to this computer.}
I'm guessing this means the service account isn't allowed to log in to the executing machine, which I already knew. But really, there's no reason it needs to log in to the executing machine. Is there a way I can use impersonation to log on to a remote machine and execute the commands from there?
You cannot do it with impersonation if the account cannot log on. Impersonation requires the thread to run under the user credentials. That is why the LogonUser
fails.
You can use the WNetAddConnection2 function that is used to establish a connection to a network resource.
Here is a sample for your CreateDirectoryIfNotExist
function using this approach:
public static void CreateDirectoryIfNotExists(string directory, string sharePath, string username, string password)
{
NETRESOURCE nr = new NETRESOURCE();
nr.dwType = ResourceType.RESOURCETYPE_DISK;
nr.lpLocalName = null;
nr.lpRemoteName = sharePath;
nr.lpProvider = null;
int result = WNetAddConnection2(nr, password, username, 0);
string directoryFullPath = Path.Combine(sharePath, directory);
if (!Directory.Exists(directoryFullPath))
{
Directory.CreateDirectory(directoryFullPath);
}
}
To be able to do the system call you need also the following definitions from pinvoke.net .
[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public ResourceScope dwScope = 0;
public ResourceType dwType = 0;
public ResourceDisplayType dwDisplayType = 0;
public ResourceUsage dwUsage = 0;
[MarshalAs(UnmanagedType.LPStr)] public string lpLocalName = null;
[MarshalAs(UnmanagedType.LPStr)] public string lpRemoteName = null;
[MarshalAs(UnmanagedType.LPStr)] public string lpComment = null;
[MarshalAs(UnmanagedType.LPStr)] public string lpProvider;
};
public enum ResourceScope
{
RESOURCE_CONNECTED = 1,
RESOURCE_GLOBALNET,
RESOURCE_REMEMBERED,
RESOURCE_RECENT,
RESOURCE_CONTEXT
};
public enum ResourceType
{
RESOURCETYPE_ANY,
RESOURCETYPE_DISK,
RESOURCETYPE_PRINT,
RESOURCETYPE_RESERVED
};
public enum ResourceUsage
{
RESOURCEUSAGE_CONNECTABLE = 0x00000001,
RESOURCEUSAGE_CONTAINER = 0x00000002,
RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
RESOURCEUSAGE_SIBLING = 0x00000008,
RESOURCEUSAGE_ATTACHED = 0x00000010,
RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
};
public enum ResourceDisplayType
{
RESOURCEDISPLAYTYPE_GENERIC,
RESOURCEDISPLAYTYPE_DOMAIN,
RESOURCEDISPLAYTYPE_SERVER,
RESOURCEDISPLAYTYPE_SHARE,
RESOURCEDISPLAYTYPE_FILE,
RESOURCEDISPLAYTYPE_GROUP,
RESOURCEDISPLAYTYPE_NETWORK,
RESOURCEDISPLAYTYPE_ROOT,
RESOURCEDISPLAYTYPE_SHAREADMIN,
RESOURCEDISPLAYTYPE_DIRECTORY,
RESOURCEDISPLAYTYPE_TREE,
RESOURCEDISPLAYTYPE_NDSCONTAINER
};
public enum ResourceConnection
{
CONNECT_UPDATE_PROFILE = 1,
CONNECT_UPDATE_RECENT = 2,
CONNECT_TEMPORARY = 4,
CONNECT_INTERACTIVE = 8,
CONNECT_PROMPT = 0X10,
CONNECT_REDIRECT = 0X80,
CONNECT_CURRENT_MEDIA = 0X200,
CONNECT_COMMAND_LINE = 0X800,
CONNECT_CMD_SAVECRED = 0X1000,
CONNECT_CRED_RESET = 0X2000
};
[DllImport("mpr.dll", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
private static extern int WNetAddConnection2(NETRESOURCE lpNetResource,
[MarshalAs(UnmanagedType.LPStr)] string lpPassword,
[MarshalAs(UnmanagedType.LPStr)] string lpUserName, int dwFlags);
You can add this definitions to the same class as your function.
Here are also links to two older post which also use the same approach.
Accessing a Shared File (UNC) From a Remote, Non-Trusted Domain With Credentials
You can solve this problem like I solved it. Below are the steps:
Step 1: Open IIS. Then add a virtual directory in your web application.
Step 2: Then map your shared path with the virtual directory added in Step 1
Step 3: Now click on Connect as..
Step 4: Set the credential of your desired user by which you want to connect your shared path.
Step 5: Now the IIS configuration part is over and you need to start using src="Image/Image.png" in your html or start manipulating "SharedFolder/YourFile.ext".
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.