using System; using System.Web; using System.Web.Mvc; using log4net; using Sleis.Models; using Sleis.ViewModels; using Sleis.Utility; namespace Sleis.Validation.Attribute { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class AppFacilityRoleValidationAttribute : AuthorizeAttribute { private readonly ILog _log = LogManager.GetLogger(typeof(AppRoleValidationAttribute)); public AppUserRoleType[] FacilityRoles { get; set; } public AppFacilityRoleValidationAttribute(params AppUserRoleType[] roles) { FacilityRoles = roles; } private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus) { validationStatus = OnCacheAuthorization(new HttpContextWrapper(context)); } public override void OnAuthorization(AuthorizationContext filterContext) { ArgumentValidationUtility.ThrowOnNull(filterContext, "filterContext"); var routeData = filterContext.RouteData; var controllerName = routeData.Values["controller"]; var actionName = routeData.Values["action"]; if (AuthorizeCore(filterContext.HttpContext)) { UserView AppUser = filterContext.HttpContext.Session[UserModel.SESSION_USER_KEY] as UserView; _log.DebugFormat("Controller:{0} Action:{1} User:{2}", controllerName, actionName, AppUser); // ** MS Reasoning for why we need to override the cache ** // Since we're performing authorization at the action level, the authorization code runs // after the output caching module. In the worst case this could allow an authorized user // to cause the page to be cached, then an unauthorized user would later be served the // cached page. We work around this by telling proxies not to cache the sensitive page, // then we hook our custom authorization code into the caching mechanism so that we have // the final say on whether a page should be served from the cache. HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; cachePolicy.SetProxyMaxAge(new TimeSpan(0)); cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); } else { // auth failed, redirect to login page _log.ErrorFormat("Controller:{0} Action:{1} From:{2}", controllerName, actionName, filterContext.RequestContext.HttpContext.Request.UserHostAddress); HandleUnauthorizedRequest(filterContext); } } protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext) { if (filterContext.HttpContext.Request.IsAuthenticated) { //filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult(403); filterContext.Result = new RedirectResult("~/Errors/AccessDenied"); } else { base.HandleUnauthorizedRequest(filterContext); } } protected override bool AuthorizeCore(HttpContextBase httpContext) { bool isAuthed = false; if (FacilityRoles != null && FacilityRoles.Length > 0 && httpContext.User != null && httpContext.User.Identity != null && httpContext.User.Identity.IsAuthenticated) { UserView user = httpContext.Session[UserModel.SESSION_USER_KEY] as UserView; if (user != null && user.User != null && user.User.Status == SleisUserStatusType.Active && user.SelectedFacility != null && ((user.SelectedFacility.Roles != null && user.SelectedFacility.Roles.Count > 0) || (user.SelectedFacility.AgencyRoles != null && user.SelectedFacility.AgencyRoles.Count > 0)) ) { if (user.User.IsAppAdmin) { isAuthed = true; } else { foreach (AppUserRoleType role in FacilityRoles) { if (user.SelectedFacility.Roles.Contains(role) || user.SelectedFacility.AgencyRoles.Contains(role)) { isAuthed = true; break; } } } } } return isAuthed; } } }