Search code examples
asp.net-mvcasp.net-mvc-2uploadifyantiforgerytoken

Uploadify problem with Authentication Token and Html.AntiforgeryToken (plugin does not send cookies)


Some time ago I had a problem with Uploadify plugin for which I did found a solution described in this answer.

The problem in that question was substantially due to the fact that Uploadify uses a flash plugin and the flash plugin does not share the authentication cookie with the server-side code.

The solution was to use a custom version of the Authorize attribute (the code was published within that answer).

The attribute [TokenizedAuthorize] was placed on the controller class as follow

[TokenizedAuthorize]
[CheckForActiveService]
public partial class DocumentController : BaseController
{
}

Some days ago I have added the <%: Html.AntiForgeryToken() %> inside the form and the [ValidateAntiForgeryToken] to the action method as in the following sample:

[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult Upload( HttpPostedFileBase fileData ) {
}

Anyway I am not anymore able to upload files to the server. Using the debugger I have been able to check that after the last line in the TokenizedAuthorize code

return base.AuthorizeCore( httpContext );

I get an exception handled by Elmah that says

System.Web.Mvc.HttpAntiForgeryException: invalid or not specified anti forgery token

in System.Web.Mvc.ValidateAntiForgeryTokenAttribute.OnAuthorization(AuthorizationContext filterContext)
in System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor)
in System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)

This exception seems to confirm that the [ValidateAntiForgeryToken] attribute is being called... but I cant understand where is the issue with my code.

Any help?

EDIT:

Using the debugger I have checked the value of the __RequestVerificationToken form parameter and, as you can see, it is correctly populated with the value from <%: Html.AntiForgeryToken() %>

alt text

EDIT 2:

I can also confirm that if I comment the [ValidateAntiForgeryToken] on the Post Action everything works as expected

EDIT 3:

As the post function is an ajax call done by the uploadify plugin the AntiForgeryToken is added to the post parameters using a small js function as in the following code

$('#fileInput').uploadify({
    //other uploadify parameters removed for brevity
    scriptData: AddAntiForgeryToken({ AuthenticationToken: auth }),
});

where AddAntiForgeryToken() is a javascript function defined in my master page to support all the ajax post to the server

<%-- used for ajax in AddAntiForgeryToken() --%>
<form id="__AjaxAntiForgeryForm" action="#" method="post">
    <%: Html.AntiForgeryToken() %>
</form>

// Encapsulate the Anti Forgery Token fetching
AddAntiForgeryToken = function (data) {
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
    return data;
};

EDIT 4:

Darin intuition is correct. The Uploadify script is not sending any cookie to the server and so the server cannot validate the AntiForgeryToken. How can I add the cookie inside the Uploadify scriptData section?


Solution

  • You must ensure that a cookie with the same value as the __RequestVerificationToken field is sent in the request. Normally this cookie is emitted by the Html.AntiforgeryToken() and it must be done on the server because its value is encrypted with the server machine keys. If the request is performed by a Flash client I don't know whether it sends cookies. If this is not the case you will need to manually send it.

    There's also something else that you should be aware of and which would throw the same exception although I don't think that it is applicable in your case but worth checking. When you use the Html.AntiforgeryToken() helper if there's a logged in user his username is part if the emitted cookie. If you then try to POST to a controller action decorated with the [ValidateAntiForgeryToken] it will verify that the currently logged in user is the same as the one when the cookie was emitted and if it isn't it will throw this exception. So what I have seen is people using the Html.AntiforgeryToken() to generate some html forms as an anonymous user and then using AJAX to log-in a user and once logged in the user submits the form - it will fail.