Question

I have a web part in which I am listing files from a library using RunWithElevatedPrivileges as user doesn't have any rights on that library (not even READ rights). But when user tries to download a file then of course it doesn't work.

Is it possible to somehow let user download file using RunWithElevatedPrivileges?

EDIT

Code

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    using (SPSite site = new SPSite("http://siteURL"))
    {
         using (SPWeb web = site.OpenWeb())
         {
            list = web.Lists["MyLibrary"];
            //Run a loop to display all files in library
         }
    }
});
Was it helpful?

Solution

If users don't have access to the file, they don't have access to the file, no matter what.
So, if you display real links to the file, as far as SharePoint is concerned, they cannot get the files content; when they click the link, they get an "access denied" message.

Your only option here is to build an applicative (_layouts) page; that page would take the file URL/Id+ListId/what-so-ever as a parameter.
The links to the files you inject from your Web part would be replaced by links to that _layouts page, including the file-identification parameter.
In that page, you would:

  1. Manually check if the incoming user is allowed to download the file, as per your business rules.
  2. Open an elevated section (RunWithElevatedPrivileges)
  3. Get the file content
  4. Inject the file content into the output stream

    // TODO: check if user is allowed to get the file content, as per business rules (since we're by-passing SP permissions)
    
    SPSecurity.RunWithElevatedPrivileges(() =>
    {
        using (SPSite elevatedSite = new SPSite(Request.Url.ToString()))
        {
            using (SPWeb elevatedWeb = elevatedSite.OpenWeb())
            {
                // TODO: Get the SPDocumentLibrary (myDocLib) object + file Id (fileId)
    
                SPListItem item = myDocLib.GetItemById(fileId);
                SPFile file = item.File;
    
                // Open the file content
                using (Stream fileStream = file.OpenBinaryStream())
                {
                    // Prepare to send the file to the output
                    Response.Clear();
                    Response.ContentType = "application/octet-stream";
                    Response.AddHeader("Content-Disposition", "attachment; filename=\"" + file.Name + "\""); // TODO: escape the file name, if needed
                    Response.AddHeader("Content-Length", file.TotalLength.ToString());
    
                    // Send the file by chunks
                    int bytesToRead = 4092;
                    byte[] buffer = new Byte[bytesToRead];
                    int length;
                    do
                    {
                        if (Response.IsClientConnected)
                        {
                            length = fileStream.Read(buffer, 0, bytesToRead);
                            Response.OutputStream.Write(buffer, 0, length);
                            Response.Flush();
                            buffer = new Byte[bytesToRead];
                        }
                        else
                            length = -1;
                    } while (length > 0);
    
                    Response.End();
                }
            }
        }
    });
    
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top