Access restrictions on media files? Options
acullen
Posted: Thursday, October 18, 2007 7:46:23 PM
Rank: Devotee

Joined: 4/13/2007
Posts: 55
Location: Arlington, VA
Is there any way to set a media file so that it can only beaccessed by members in a specific member group? I need to create adownload section for registered users, and would love to use the Media section so that the site admins don't need to learn another system, but am way since ayone who knows the URL for afile can get to it.

Any ideas? Thanks!
mortenbock
Posted: Thursday, October 18, 2007 8:58:49 PM

Rank: Addict

Joined: 7/19/2006
Posts: 706
Location: Århus, Denmark
This is not something umbraco supports out of the box, so you have to make some sort of custom solution for it.

The way to do it would probably be to place the actual files in a folder protected by IIS, and then stream the files to the user through an .aspx page that verifies user rights.

The reason umbraco does not support file permissions is that when you are downloading a .jpg file, .net is not handling the request, thus umbraco has no way of preventing the download.

Morten Bock - Level 2 certified - My danish blog with a few english posts | CodeGarden on Facebook
acullen
Posted: Thursday, October 18, 2007 11:28:58 PM
Rank: Devotee

Joined: 4/13/2007
Posts: 55
Location: Arlington, VA
Hmm. That makes sense. Would it be possible to create a new datatype to handle "secure" media files that get uploaded to a space outside of IIS (thus, no URL access)? If so, how do I handle letting editors include links to the mediacontent in the WYSIWYG? (I'd obviously want the final url to be the page that checks security first, but how do I get that to happen?
mortenbock
Posted: Friday, October 19, 2007 8:50:07 AM

Rank: Addict

Joined: 7/19/2006
Posts: 706
Location: Århus, Denmark
Here is an example of an upload datatype that stores the file on a remote FTP server:

http://codegarden.umbraco.org/blog/2007/5/11/we-just-build-an-ftp-datatype-in-45-minutes

Maybe you can use that as a sort of startingpoint?

Morten Bock - Level 2 certified - My danish blog with a few english posts | CodeGarden on Facebook
imayat12
Posted: Friday, October 19, 2007 8:53:58 AM

Rank: Addict

Joined: 7/19/2006
Posts: 542
Location: Preston, UK
Andy,

Create a http module to do it. So even if editors add secure file to content even then before the restricted file is served up the module checks the permissions and either serves it up or redirects to login page.

I have some old code you could hack. You will need to do some fiddling in iis so that the handler for secure file types is handled by the handler in my case it was pdf's only.

Ignore the logging function also im sure there is better way of getting media id than getMediaIdFromUrl function but i did knock this up almost 2 yrs ago when i was an umbraco newbie.

Code:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web;
using System.Configuration;
using System.IO;
using System.Web.Security;
using DownLoadTracker;
using Microsoft.ApplicationBlocks.Data;
using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
namespace UmbracoDocumentSecurity
{

      /// <summary>
      /// To intercept requests for file types and check for an authenticated user
      /// </summary>
      public class SecuringHandler : System.Web.IHttpHandler
      {

            #region IHttpHandler Members

            public void ProcessRequest(HttpContext context)
            {
                  if(context.Request.Cookies["umbracoMemberGuid"] != null)
                  {
                        //log into tracker that we are downloading
                        logDownload(context);
                        TransmitDocument(context);
                  }
                  else
                  {
                        RedirectToLogin(context);
                  }
            }

            /// <summary>
            /// There *has* to be a better way than this, possibly using the metabase API.
            /// </summary>
            /// <param name="extension"></param>
            /// <returns></returns>
            private string GetMime(string extension)
            {
                  switch(extension)
                  {
                        case "doc":
                        {
                              return "application/ms-word";
                        }
                        case "pdf":
                        {
                              return "application/pdf";
                        }
                        case "mpeg":
                        {
                              return "application/mpeg";
                        }
                        default:
                        {
                              return "application/unknown";
                        }
                  }
            }

            /// <summary>
            /// writes into the database the download and who is downloading
            /// </summary>
            private void logDownload(HttpContext context){
                  string memberId = "un known";
                  //umbracoMemberId
                  if(context.Request.Cookies["umbracoMemberId"] != null)
                  {
                        memberId = context.Request.Cookies["umbracoMemberId"].Value;
                  }
                  
                  //context.Request.Url.ToString() need to get item id
                  Tracker.AddTrackingEntry(memberId ,getMediaIdFromUrl(context.Request.Url.ToString(),context),DateTime.Now);
            }

            private int getMediaIdFromUrl(string url, HttpContext context){

                  Regex reg = new Regex("/media.*");
                  int id;
                  try
                  {
                        SqlParameter[] sqParams = {new SqlParameter("@url", reg.Match(url).Value)};
                        string sql = "select contentNodeId from cmsPropertyData where dataNvarchar = @url";                                    
                        id= (int)SqlHelper.ExecuteScalar(umbraco.GlobalSettings.DbDSN,CommandType.Text,sql,sqParams);
                        return id;
                  }
                  catch(Exception ex){
                         umbraco.BusinessLogic.Log.Add(umbraco.BusinessLogic.LogTypes.Error,new umbraco.BusinessLogic.User(0),0,"Error from download security handler ->" + ex.Message.ToString());
                  }
                  return 0;
                  
                  
            }

            private void TransmitDocument(HttpContext context)
            {
                  string path      = HttpUtility.UrlDecode(context.Request.Url.LocalPath);
                  string fileName  = System.IO.Path.GetFileName(path);
                  string extension = System.IO.Path.GetExtension(path);
                  
                  context.Response.Clear();
                  context.Response.AddHeader("content-disposition","attachment");
                  context.Response.ContentType = GetMime(extension);
                  context.Response.WriteFile(path);
            }

            private void RedirectToLogin(HttpContext context)
            {
                  context.Response.Redirect(ConfigurationSettings.AppSettings["LoginPage"]);
            }

            public bool IsReusable
            {
                  get
                  {
                        return true;
                  }
            }



            #endregion
      }


}


Regards

Ismail

Level 2 certified. If it aint broke dont fix.
mortenbock
Posted: Friday, October 19, 2007 9:06:47 AM

Rank: Addict

Joined: 7/19/2006
Posts: 706
Location: Århus, Denmark
Ismail Mayat wrote:

Create a http module to do it. So even if editors add secure file to content even then before the restricted file is served up the module checks the permissions and either serves it up or redirects to login page.


I think he will also have to set up the IIS to send all requests to the .NET framework right? Otherwise i'm guessing that the httpmodule will have no effect?

Morten Bock - Level 2 certified - My danish blog with a few english posts | CodeGarden on Facebook
imayat12
Posted: Friday, October 19, 2007 9:46:54 AM

Rank: Addict

Joined: 7/19/2006
Posts: 542
Location: Preston, UK
Bock,

Yup thats what i mean by

wrote:
You will need to do some fiddling in iis so that the handler for secure file types is handled by the handler in my case it was pdf's only


Not very clear :blush:

Regards

Ismail

Level 2 certified. If it aint broke dont fix.
Petr Snobelt
Posted: Friday, April 18, 2008 2:59:00 PM
Rank: Aficionado

Joined: 10/2/2007
Posts: 123
Location: Czech Republic
Hi, thanks for useful info.

I need to build something similar and I think it can be done with pages only (without changing iis settings)

You only need redirect package (not necessary if using redirect in page meta parameter) and for example cln.xsltext.database to write download into DB.

Simply create thank you page (like ms or sourceforge) which count download and redirect to file (passed by querystring)

Miss I something ?
imayat12
Posted: Friday, April 18, 2008 4:09:08 PM

Rank: Addict

Joined: 7/19/2006
Posts: 542
Location: Preston, UK
Petr,

You can do this with downloads listed via usercontrol / xslt. However if people were adding download links into rich text edit field you would need to update the link manually to your redirect page.

Regards

Ismail

Level 2 certified. If it aint broke dont fix.
Petr Snobelt
Posted: Friday, April 18, 2008 4:33:29 PM
Rank: Aficionado

Joined: 10/2/2007
Posts: 123
Location: Czech Republic
It's not my case, I need it for files repository.
But thank you for pointing me at this.

Petr
neehouse
Posted: Friday, April 18, 2008 9:31:37 PM

Rank: Umbracoholic

Joined: 7/20/2006
Posts: 1,038
Location: Charleston, West Virginia, United States
Petr,

When needing to secure files, I tend to do a combination of the above methods. First, I use the content tree for these files, versus the media tree. This allows the links to generate the node path, rather than the file path. I then assign a template that will stream the files using a user control. This way, you can use the built in page security to lock down the groups that have access.

One thing to note here is that the file is still in the media section. If the direct file link was exposed, it would comprimise the security (thus, it is not truly secure).

A custom upload that saved the file to a secured folder is the best method, with the download coming from an aspx page.


• 2007/2008 MVP • 2008/2009 MVP • Core Developer • Certified Professional Level I & II •
Petr Snobelt
Posted: Monday, April 21, 2008 9:26:11 AM
Rank: Aficionado

Joined: 10/2/2007
Posts: 123
Location: Czech Republic
Hi,

If I would like create perfect solution:
1. Create page with upload to secure location, not visible from web
2. Create DataType. which allow me to select file from secure folder
3. Create httphandler similar to Ismail's handler, which streams file to client. But it log download at end, not at beginning of download (maybe it can allow resumable download http://jlchereau.blogspot.com/2006/11/resumable-file-downloads-in-aspnet.html). Because if user lost connection in Ismail's handler download is counted.
4. Macro for RTE editor if needed

This way everything is perfectly secure, but it is lot of work :-) my first solution require minimal work and knowledge and has acceptable level of security.

Miss I something again ?
Ig_p118
Posted: Friday, April 25, 2008 3:05:02 PM
Rank: Aficionado

Joined: 7/21/2006
Posts: 174
Location: Salerno - Italy
I'm interested, too...

Red Consulting s.a.s - Umbraco from v1.0
Users browsing this topic
Guest


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.