Returning File in a site with Authentication

Topics: Customizing Orchard, Troubleshooting, Writing modules
Nov 28, 2013 at 8:37 AM
crosspost: http://stackoverflow.com/questions/20261131/returning-file-in-a-site-with-authentication

I'm using Orchard 1.7 and we locked the entire site from anonymous users (admin -> users -> roles -> untick site front-end). Now, each page or file requires folks to be authenticated before getting access to them.

Now, we're trying to provide the option of having some files available for download, depending on a field from a specific Content Type.

The ISSUE

When I download the file while I am authenticated, I get the it without issues. If I'm anonymous, I get the file (correct filename and type) but it has no contents and size (0 bytes). I'm pretty sure this is an auth issue since it all works well when I enable anonymous access to site front end.

This is the actual code of returning the file (redirectLink is the filepath):
                        var cd = new System.Net.Mime.ContentDisposition
                        {
                            FileName = fileName,
                            Inline = false
                        };

                        Response.AppendHeader("Content-Disposition", cd.ToString());
                        return File(HttpUtility.UrlDecode(redirectLink), mimeType);
Here is my complete code (Controller Action):
            [AlwaysAccessible]
            public ActionResult Download(int resourceId)
            {
                //set default unsecure value to false
                bool isUnsecured = false;
    
                var resourceItem = ContentManager.Get(resourceId);
                if (resourceItem == null || resourceItem.ContentType != "Resource")
                {
                    // TODO: log that ID not found??
                    return new HttpStatusCodeResult(HttpStatusCode.NotFound);
                }
    
                var resourcePart = resourceItem.Parts.FirstOrDefault(p => p.PartDefinition.Name == resourceItem.ContentType);
    
                //retrieve unsecure boolean
                if (resourcePart != null)
                {
                    var unsecuredField = resourcePart.Fields.FirstOrDefault(f => f.Name == "Unsecured");
                    if (unsecuredField != null)
                    {
                        isUnsecured = unsecuredField.Storage.Get<bool>();
                    }
                }
    
                //check if unsecured resource / allow anonymous downloads
                //see Orchard.Security.SecurityFilter - I'm not sure where this is actually used in Orchard though...
                if (!isUnsecured && !Services.Authorizer.Authorize(StandardPermissions.AccessFrontEnd, T("Unauthenticated")))
                {
                    return new HttpUnauthorizedResult(); 
                }                                     
                
                if (resourcePart != null)
                {
                    // TODO: Potential concurrency issues?
                    var downloadCountPart = resourcePart.As<DownloadCountPart>();
                    if (downloadCountPart != null)
                    {
                        downloadCountPart.Total++;
                        ContentManager.Publish(resourceItem);
                    }
    
                    // Do the redirection/serving of item!
                    // Prioritize link field over resource field, according to the UI
                    var linkedField = resourcePart.Fields.FirstOrDefault(f => f.Name == "LinkedFile");
                    if (linkedField != null)
                    {
                        var redirectLink = linkedField.Storage.Get<string>();
                        if (redirectLink != null)
                        {
                            return Redirect(redirectLink);
                        }
                    }
    
                    var resourceField = resourcePart.Fields.First(f => f.Name == "ResourceFile");
                    if (resourceField != null)
                    {
                        var resourceMPF = (resourceField as MediaLibraryPickerField);     
    
                        if (resourceMPF != null && resourceMPF.MediaParts != null && resourceMPF.MediaParts.Count() > 0)
                        {
                            var fileName = resourceMPF.MediaParts.First().FileName;
                            var mimeType = resourceMPF.MediaParts.First().MimeType;
                            var redirectLink = resourceMPF.MediaParts.First().MediaUrl;       //to check: first? when are there multiple?
                            if(!string.IsNullOrWhiteSpace(redirectLink))
                            {
    
                                var cd = new System.Net.Mime.ContentDisposition
                                {
                                    FileName = fileName,
                                    Inline = false
                                };
    
                                Response.AppendHeader("Content-Disposition", cd.ToString());
                                return File(HttpUtility.UrlDecode(redirectLink), mimeType);
                            }
    
                        }                   
                    }
                }
    
                return new HttpStatusCodeResult(HttpStatusCode.NotFound);
            }
Which leads me to these questions:
  1. Event with return File, it still takes into account the current user
    and whether that person is authenticated?
  2. Can I use impersonation to bypass this issue?
Any piece of advise or information would be highly appreciated. Thanks!
Developer
Nov 28, 2013 at 11:43 AM
Answered there.