I am trying to deny access to a folder or resources when not logged in (prevent leeching). In the folder I have my
Web.config: (/Media)
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<deny users="?"/>
<allow users="*" />
</authorization>
</system.web>
</configuration>
The code I am calling:
Index:
@Video.MediaPlayer(
path: "~/Media/Tree Felling2.wmv",
width: "600",
height: "400",
autoStart: false,
playCount: 1,
uiMode: "full",
stretchToFit: true,
enableContextMenu: true,
mute: false,
volume: 75)
@Video.Flash(path: "~/Media/sample.swf",
width: "80%",
//height: "600",
play: true,
loop: false,
menu: true,
bgColor: "red",
quality: "medium",
//scale: "showall",
windowMode: "transparent")
When logged out: flash is not shown. Media player wont connect to media. ( AS EXPECTED )
When logged in: flash is shown. But media player still wont connect to media.
Where am I going wrong?..
Unfortunately this is a known bug with the Windows Media Player for FF. It will work in IE.
The reason for this not working is pretty simple: the plugin doesn't send the authentication cookie along with the request so it is as if you are not authenticated.
The only way to make this work is to append the cookie value as a query string parameter to the request and then resynchronize the session on the server.
Let's put that into action, shall we?
Unfortunately we cannot use the @Video.MediaPlayer
helper because it doesn't allow you to specify query string parameters, it works only with physical files (which kinda sucks). So:
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6" height="400" width="600" >
<param name="URL" value="@Url.Content("~/media/test.wmv?requireAuthSync=true&token=" + Url.Encode(Request.Cookies[FormsAuthentication.FormsCookieName].Value))" />
<param name="autoStart" value="False" />
<param name="uiMode" value="full" />
<param name="stretchToFit" value="True" />
<param name="volume" value="75" />
<embed src="@Url.Content("~/media/test.wmv?requireAuthSync=true&token=" + Url.Encode(Request.Cookies[FormsAuthentication.FormsCookieName].Value))" width="600" height="400" type="application/x-mplayer2" autoStart="False" uiMode="full" stretchToFit="True" volume="75" />
</object>
and inside Global.asax
we subscribe to the Application_BeginRequest
method and resync up the authentication cookie from the request:
protected void Application_BeginRequest()
{
if (!string.IsNullOrEmpty(Context.Request["RequireAuthSync"]))
{
AuthCookieSync();
}
}
private void AuthCookieSync()
{
try
{
string authParamName = "token";
string authCookieName = FormsAuthentication.FormsCookieName;
if (!string.IsNullOrEmpty(Context.Request[authParamName]))
{
UpdateCookie(authCookieName, Context.Request.QueryString[authParamName]);
}
}
catch { }
}
private void UpdateCookie(string cookieName, string cookieValue)
{
var cookie = Context.Request.Cookies.Get(cookieName);
if (cookie == null)
{
cookie = new HttpCookie(cookieName);
}
cookie.Value = cookieValue;
Context.Request.Cookies.Set(cookie);
}
And that's pretty much it. The only requirement for this to work is to be running in IIS 7 Integrated Pipeline Mode in order for all requests to go through ASP.NET, even those for .wmv
files, otherwise the BeginRequest
will obviously never trigger for them.
If you are using some legacy web server (such as IIS 6.0) or running in Classic Pipeline mode and don't want to do a wildcard mapping of all requests with ASP.NET you could put all your media files in a secure location (such as ~/App_Data
) that cannot be directly accessed by users and then serve them through a controller action decorated with the [Authorize]
attribute:
[Authorize]
public ActionResult Media(string file)
{
var appData = Server.MapPath("~/App_Data");
var filename = Path.Combine(path, file);
filename = Path.GetFullPath(filename);
if (!filename.StartsWith(appData))
{
// prevent people from reading arbitrary files from your server
throw new HttpException(403, "Forbidden");
}
return File(filename, "application/octet-stream");
}
and then:
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6" height="400" width="600" >
<param name="URL" value="@Url.Action("media", "home", new { requireAuthSync = true, token = Request.Cookies[FormsAuthentication.FormsCookieName].Value })" />
<param name="autoStart" value="False" />
<param name="uiMode" value="full" />
<param name="stretchToFit" value="True" />
<param name="volume" value="75" />
<embed src="@Url.Action("media", "home", new { requireAuthSync = true, token = Request.Cookies[FormsAuthentication.FormsCookieName].Value })" width="600" height="400" type="application/x-mplayer2" autoStart="False" uiMode="full" stretchToFit="True" volume="75" />
</object>