using System.Collections.Generic; using System.Linq; using System.Net; using System.Security.Claims; using System.Web.Mvc; using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Mvc { /// /// A filter to check for the csrf token based on Angular's standard approach /// /// /// Code derived from http://ericpanorel.net/2013/07/28/spa-authentication-and-csrf-mvc4-antiforgery-implementation/ /// /// If the authentication type is cookie based, then this filter will execute, otherwise it will be disabled /// public sealed class ValidateMvcAngularAntiForgeryTokenAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var userIdentity = filterContext.HttpContext.User.Identity as ClaimsIdentity; if (userIdentity != null) { //if there is not CookiePath claim, then exist if (userIdentity.HasClaim(x => x.Type == ClaimTypes.CookiePath) == false) { base.OnActionExecuting(filterContext); return; } } string failedReason; var headers = new List>>(); foreach (var key in filterContext.HttpContext.Request.Headers.AllKeys) { if (headers.Any(x => x.Key == key)) { var found = headers.First(x => x.Key == key); found.Value.Add(filterContext.HttpContext.Request.Headers[key]); } else { headers.Add(new KeyValuePair>(key, new List { filterContext.HttpContext.Request.Headers[key] })); } } var cookie = filterContext.HttpContext.Request.Cookies[AngularAntiForgeryHelper.CsrfValidationCookieName]; if (AngularAntiForgeryHelper.ValidateHeaders( headers.Select(x => new KeyValuePair>(x.Key, x.Value)).ToArray(), cookie == null ? "" : cookie.Value, out failedReason) == false) { var result = new HttpStatusCodeResult(HttpStatusCode.ExpectationFailed); filterContext.Result = result; return; } base.OnActionExecuting(filterContext); } } }