diff --git a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs index d22ef9ac4..81215669c 100644 --- a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs +++ b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs @@ -350,7 +350,38 @@ namespace Orchard.Mvc.Html { public static MvcHtmlString AntiForgeryTokenOrchard(this HtmlHelper htmlHelper) { var siteSalt = htmlHelper.Resolve().GetSiteSettings().SiteSalt; - return htmlHelper.AntiForgeryToken(siteSalt); + try { + return htmlHelper.AntiForgeryToken(siteSalt); + } + catch(System.Web.Mvc.HttpAntiForgeryException e) { + // Work-around an issue in MVC 2: If the browser sends a cookie that is not + // coming from this server (this can happen if the user didn't close their browser + // while the application server configuration changed), clear it up + // so that a new one is generated and sent to the browser. This is harmless + // from a security point of view, since we are _issuing_ an anti-forgery token, + // not validating input. + + // Remove the token so that MVC will create a new one. + var antiForgeryTokenName = htmlHelper.GetAntiForgeryTokenName(); + htmlHelper.ViewContext.HttpContext.Request.Cookies.Remove(antiForgeryTokenName); + + // Try again + return htmlHelper.AntiForgeryToken(siteSalt); + } + } + + private static string GetAntiForgeryTokenName(this HtmlHelper htmlHelper) { + // Generate the same cookie name as MVC + var appPath = htmlHelper.ViewContext.HttpContext.Request.ApplicationPath; + const string antiForgeryTokenName = "__RequestVerificationToken"; + if (string.IsNullOrEmpty(appPath)) { + return antiForgeryTokenName; + } + return antiForgeryTokenName + '_' + Base64EncodeForCookieName(appPath); + } + + private static string Base64EncodeForCookieName(string s) { + return Convert.ToBase64String(Encoding.UTF8.GetBytes(s)).Replace('+', '.').Replace('/', '-').Replace('=', '_'); } #endregion diff --git a/src/Orchard/Mvc/Html/MvcFormAntiForgeryPost.cs b/src/Orchard/Mvc/Html/MvcFormAntiForgeryPost.cs index 1c99c4bda..0ffb90da7 100644 --- a/src/Orchard/Mvc/Html/MvcFormAntiForgeryPost.cs +++ b/src/Orchard/Mvc/Html/MvcFormAntiForgeryPost.cs @@ -10,7 +10,9 @@ namespace Orchard.Mvc.Html { } protected override void Dispose(bool disposing) { - _htmlHelper.ViewContext.Writer.Write(_htmlHelper.AntiForgeryTokenOrchard()); + if (disposing) { + _htmlHelper.ViewContext.Writer.Write(_htmlHelper.AntiForgeryTokenOrchard()); + } base.Dispose(disposing); }