I have the following code in ASP.Net Generic handler to download the file.
// generate you file
// set FilePath and FileName variables
string stFile = FilePath + FileName;
try {
response.Clear();
response.ContentType = "application/pdf";
response.AppendHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
response.TransmitFile(stFile);
} catch (Exception ex) {
// any error handling mechanism
} finally {
response.End();
}
it works fine with local path - like "D:\Files\Sample.pdf" or "\localserver\Files\Sample.pdf".
but it throws and access denied error while trying to access the Network file share like "\anotherServer\Files\Sample.pdf".
Does it related to double hopping? If can I use spsecurity.runwithelevatedprivileges to fix this issue? or what are the other options?
As per this article https://weblogs.asp.net/owscott/iis-windows-authentication-and-the-double-hop-issue it seems to be a double hopping issue. How do I address this? All I want is that end user should be able to download remote resources by using asp.net generic handler.
Right-click the file or folder, and then click Properties. Click the Security tab. Under Group or user names, click your name to see the permissions that you have. Click Edit, click your name, select the check boxes for the permissions that you must have, and then click OK.
Access denied is an error message displayed when you do not have appropriate access rights. If you are being denied access to a network share, Intranet, or the Internet, and are receiving the access denied message, you need permission to gain access.
I have to deal with something similar once and to get this to work by mapping network share to specific drive.
Solution to add credentials to your network share before trying to access it didn't work (but you can try it as a first attempt)
NetworkCredential nc = new NetworkCredential("<login>", "<pass>");
CredentialCache cache = new CredentialCache();
cache.Add(new Uri("<your network share>"), "Basic", nc);
If this doesn't work use the combined solution with mapping network share to drive. Use class NetworkDrive
to make WinApi calls to WNetAddConnection2
and WNetCancelConnection2
:
public class NetworkDrive
{
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
}
[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public ResourceScope dwScope = 0;
public ResourceType dwType = 0;
public ResourceDisplayType dwDisplayType = 0;
public ResourceUsage dwUsage = 0;
public string lpLocalName = null;
public string lpRemoteName = null;
public string lpComment = null;
public string lpProvider = null;
}
[DllImport("mpr.dll")]
private static extern int WNetAddConnection2(NETRESOURCE lpNetResource, string lpPassword, string lpUsername, int dwFlags);
[DllImport("mpr.dll")]
static extern int WNetCancelConnection2(string lpName, Int32 dwFlags, bool bForce);
private const int CONNECT_UPDATE_PROFILE = 0x1;
private const int NO_ERROR = 0;
public int MapNetworkDrive(string unc, string drive, string user, string password)
{
NETRESOURCE myNetResource = new NETRESOURCE();
myNetResource.lpLocalName = drive;
myNetResource.lpRemoteName = unc;
myNetResource.lpProvider = null;
int result = WNetAddConnection2(myNetResource, password, user, 0);
if (result == 0)
return result;
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
public int UnmapNetworkDrive(string drive)
{
int result = WNetCancelConnection2(drive, CONNECT_UPDATE_PROFILE, true);
if (result != NO_ERROR)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return result;
}
}
And use it like this:
NetworkDrive nd = new NetworkDrive();
try
{
if (nd.MapNetworkDrive("<your network share>", "Z:", "<login>", "<pass>") == 0)
{
NetworkCredential nc = new NetworkCredential("<login>", "<pass>");
CredentialCache cache = new CredentialCache();
cache.Add(new Uri("<your network share>"), "Basic", nc);
// access network share using UNC path (not your drive letter)
}
}
finally
{
nd.UnmapNetworkDrive("Z:");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With