0

I need to be able to support "auxiliary" content on a MVC (4) web site -- images, PDFs, videos, etc. Most of this content is provided by the customer using the site so it should not be accessible to unauthenticated users.

(We're using Forms Authentication to generate an authentication ticket. Note, we are not necessarily using the built-in membership/identity providers, as some of our customers want to use authenticate via other means e.g. a federated identity service.)

I've secured the static content by setting up the site to route/authorize all requests through ASP.NET (via runAllManagedModulesForAllRequests) as described here.
I found that I needed to allow anonymous access to the Content and Scripts folders (via location) ... but this configuration works for most content types.

It does not however work for video content, specifically in Internet Explorer. Media Player comes up but reports that it cannot play the file. "The player might not support the file type or coded that was used to create the file."
(Interestingly enough, there's no error in Chrome or Firefox. The video plays in a new tab.)

I'm fairly certain it's Media Player that is the issue. If I add a location element and allow anonymous access to the video, it plays just fine. And we've had similar problems in the past where the root cause ultimately turned out to be security- / authentication- related.

But obviously I can't change Media Player. And I have to support IE. So ... does anyone know of a way to work around this issue programmatically in ASP.NET MVC? Any help would be appreciated.


I seem to recall seeing an SO post about sending the authentication information not just with HTTP requests. I can't locate that post now. But according to Fiddler the request is in fact an HTTP GET. And we're not sending an authentication header, but we are sending an authentication cookie.


Update:

I thought I would be able to adapt the answer to this question.
It involves appending a flag and the authorization cookie value to the content URL, and hooking in to the Application_BeginRequest event.
In the view:

var asset       = ...;
var authToken   = Request.Cookies[FormsAuthentication.FormsCookieName].Value;
var assetUri    = string.Format("~/Media/{0}?requireAuthSync=true&token={1}", 
                                asset.ID, Url.Encode(authToken));

Then in Global.asax.cs:

protected void Application_BeginRequest()
{
    if (!string.IsNullOrEmpty(Context.Request["requireAuthSync"]))
    {
        AuthCookieSync();
    }
}

private void AuthCookieSync()
{
    var authParamName  = "token";
    var authCookieName = FormsAuthentication.FormsCookieName;

    try
    {
        if (!string.IsNullOrEmpty(Context.Request[authParamName]))
        {
            var authCookieValue = Context.Request.QueryString[authParamName];
            var authCookie      = Context.Request.Cookies.Get(authCookieName) 
                                  ?? new HttpCookie(authCookieName);

            authCookie.Value = authCookieValue;
            Context.Request.Cookies.Set(authCookie);
        }
    }
    catch
    {
    }
}

Using this approach, the video does in fact play in IE.
However, it's now possible to bookmark the video (or other content) and use the bookmark to access the content without being authenticated ... so the site security is effectively broken.

So it seems, in order to preserve site security, I shouldn't be creating the cookie if it doesn't already exist. But with Media Player, creating the cookie is the only way to get the video to play. I appear to be stuck in a Catch-22.

Any insight would be much appreciated.

Community
  • 1
  • 1
David
  • 2,226
  • 32
  • 39

1 Answers1

0

so the site security is effectively broken

First of all, the site is not broken. Although a user can tag it, the forms cookie will expire (depending on the token validity time you set when you issue the cookie) and the link will stop to work.

But then, note that you don't really have to pass the forms authentication cookie value as the token in the query string.

You could for example generate one-time GUID-like tokens and the very first time the token is used, it is marked at the server side and cannot be used again. Or even you could somehow encrypt or sign the token validitity time in the token so that the link is valid for a short period of time but the token is independent on the forms cookie but you don't need an auxiliary storage of used tokens.

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • It's just a session cookie. As I understand it, those should go away when I close down all browser (IE) tabs, or after the session timeout (30 minutes) has elapsed. That's not the behavior I'm seeing here. Even after closing out of IE completely and/or waiting over 30 minutes, I can still use the links. – David Dec 15 '14 at 21:43
  • It is **not** a session cookie, it is a forms authentication cookie. When it expires depends on how it is created. – Wiktor Zychla Dec 15 '14 at 22:08
  • I meant it's not being created as a persistent cookie. If I copy any other URL from the site to the clipboard, close and restart IE, and paste the URL in the address bar, I get redirected to the login page. Of course those links don't include the cookie. – David Dec 16 '14 at 13:00
  • But your comment did get me thinking. It turns out the timeout was set to `2880` (48 hours) in the `web.config`. I'm pretty sure I did not change that value from the default. – David Dec 16 '14 at 13:06
  • That seems to explain the behaviour you saw. Someone (you or other administrators) had to modify the value, there is no way users could do this remotely. – Wiktor Zychla Dec 16 '14 at 14:52