Removing "X-Frame-Options" header for a specific controller only - iframe

I am trying to remove the "X-Frame-Options" header for only a specific controller's actions using:
protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Headers.Remove("X-Frame-Options");
base.OnResultExecuting(filterContext);
}
However, that doesn't seem to work at all. The only way I can get it to work at all on my site is to add this code to the global.asax below. I am pretty sure I am missing the correct step in the ASP.NET MVC / IIS pipeline that allows me to overwrite the IIS setting of that header. Is this possible?
protected void Application_EndRequest()
{
Response.Headers.Remove("X-Frame-Options");
}
As for why I want to do this, I am building a widget that user's will be able to use on their personal sites through the use of an iframe, but allow them to post back information to our site. I realize there are security implications to turning this header off, and while I welcome any suggestions on how to mitigate those risks, I just want to know if what I am asking is possible.

OnResultExecuting happens too early in the MVC lifecycle. The header has not been set yet.
What you need is the OnResultExecuted method which is run after the View is rendered.
Here's how you write a filter class for what you are looking for:
using System.Web.Mvc;
namespace Test.Filters
{
public class RemoveXFrameOptionsAttribute : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.Headers.Remove("X-Frame-Options");
base.OnResultExecuted(filterContext);
}
}
}
Then to use it, decorate whatever Controller or Action you want this filter applied.
[RemoveXFrameOptions]
public class TestController : Controller
{
public ActionResult Index()
{
return View();
}
}
or
public class TestController : Controller
{
[RemoveXFrameOptions]
public ActionResult Index()
{
return View();
}
}

Related

Is there any undesirable effect doing ModelState.Clear() before action executing?

If we are using ajax call to return partial view, then response from the action method may return cached output from partial view. The issue has been discussed on several SO post here, here, here
To resolve issue i have to do ModelState.Clear() in action method.
I have several action methods that returns partial view using Ajax call. So i thought instead of doing ModelState.Clear() in each method i can create custom ActionFilterAttribute like below
public class NoCacheAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.Controller.ViewData.ModelState.Clear();
base.OnResultExecuting(filterContext);
}
}
and then register it with global filters
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new NoCacheAttribute());
}
This seems to be working fine.
However I wanted to know if there is there any undesirable effect doing ModelState.Clear() before action executing? If not, then why that is not a default behavior in asp.net mvc

Access Viewbag property on all views

How can I access some ViewBag properties across all my views? I want to have some information like current user name, etc accessible everywhere, but without having to to specifically define the properties in each ActionResult method on my project
The best and straight forward way to accomplish your requirement is to make a Custom Base Controller and inherit your Controller from this Base Controller.
public class MyBaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
ViewBag.someThing = "someThing"; //Add whatever
base.OnActionExecuting(filterContext);
}
}
Now instead of inheriting Controller class,inherit MyBaseController in your Controller as shown :-
public class MyOtherController : MyBaseController
{
public ActionResult MyOtherAction()
{
//Your Stuff
return View();
}
//Other ActionResults
}
You can achieve what you want in a number of ways, each one with their pros and cons.
1. With a Base Class
public class BaseController : Controller
{
protected override ViewResult View(IView view, object model)
{
this.ViewBag.MyProperty = "value";
return base.View(view, model);
}
}
PROS: Quite simple to implement, few lines of code, highly reusable, can be opted-out at will (see comments below).
CONS: Being forced to derive all your controllers from a base class might have some impact, especially if you have a lot of controllers already in place and/or you need to derive them from other base classes.
2. With a Module
public class ViewBagPropertyModule: Module
{
protected override void AttachToComponentRegistration(IComponentRegistry cr,
IComponentRegistration reg)
{
Type limitType = reg.Activator.LimitType;
if (typeof(Controller).IsAssignableFrom(limitType))
{
registration.Activated += (s, e) =>
{
dynamic viewBag = ((Controller)e.Instance).ViewBag;
viewBag.MyProperty= "value";
};
}
}
}
PROS: None I’m aware of.
CONS: None I’m aware of (except being a bit counterintuitive).
3. With a RegisterController Hook
builder.RegisterControllers(asm)
.OnActivated(e => {
dynamic viewBag = ((Controller)e.Instance).ViewBag;
viewBag.MyProperty = "value";
});
PROS: Fast, secure, reusable: ideal for any IoC design pattern.
CONS: Not always suited for small project and/or simple websites: if you’re not using IoC you’re often not using RegisterController at all.
4. With an ActionFilter attribute
public class MyPropertyActionFilter : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.Controller.ViewBag.MyProperty = "value";
}
}
and then in your Global.asax.cs file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalFilters.Filters.Add(new MyPropertyActionFilter(), 0);
}
PROS: Easily the less-obtrusive method amongst those mentioned.
CONS: None I’m aware of.
I also wrote this article on my blog explaining all the above methods.
One way: Create a custom attribute, then you can apply it globally in the FilterConfig. Then you don't have to do anything in your controllers.
public class MyCustomViewActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
dynamic ViewBag = filterContext.Controller.ViewBag;
ViewBag.Id = "123";
ViewBag.Name = "Bob";
}
}
In App_Start/FilterConfig.cs:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyCustomViewActionFilter());
}
Another way if all you need is the User information. You can add the following to the top of your view:
#using Microsoft.AspNet.Identity
Then access your User Name using the following syntax:
#User.Identity.GetUserName()
You can also override the IPrincipal implementation and provide your own properties and methods to add more information you need to render.
UPDATE: looking at MVC 6 in Asp.Net vNext this is actually baked into the framework. http://www.asp.net/vnext/overview/aspnet-vnext/vc#inj
My current solution:
Create a base controller with all needed properties (very useful and advisable).
public abstract class BaseController : Controller {
public string MyProperty { get; set; }
}
Inherits all your controllers, from the base controller.
public class MyController : BaseController {
//you can read your property here
}
In your views, add this line just after the "#model" sentence:
#{ BaseController ctr = ViewContext.Controller as BaseController; }
Now, you can use the property in your view, without populate the ViewBag, without the need of check and cast the ViewBag values, etc.
In the view, you can use an simple inline expression:
#(ctr.MyProperty)
Or do some magic logic...
#{
if(ctr.MyProperty == "whatelse") {
//do ...
}
}
Easy, fast and comfortable.
For Net Core 5 Mvc app:
Create a ActionFilter class first:
public class GlobalSettingFilter : IActionFilter
{
private IConfiguration configuration;
//For example will get data from the configuration object
public GlobalSettingFilter(IConfiguration configuration)
{
this.configuration = configuration;
}
public void OnActionExecuting(ActionExecutingContext context)
{
//Populate the ViewData or ViewBag from your data source
(context.Controller as Controller).ViewData["helpUrl"] = configuration.GetValue<String>("helpUrl");
}
public void OnActionExecuted(ActionExecutedContext context){}
}
Then, on Startup add:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddControllersWithViews(options =>
{
options.Filters.Add(new GlobalSettingFilter(Configuration));
});
}
Just for the sake of completeness, to get the configuration object use:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
...
}
You can create a base controller that is inherited by all of your controllers, and in this controller (the base one) add:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Fill your global viewbag variables here
}

ASP.NET MVC - Unit Testing Override Initialize Method

I've got an abstract class shown below which gets inherited by all the other controllers. Is it possible to test this method at all? Btw, I'm trying to use MOQ but no luck. If you could help me will be much appreciated:
public abstract class ApplicationController : Controller
{
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
//do some stuff here
}
}
If you take a look at the source code of base Initialize method you will find out that what it does is that it sets up ControllerContext and url stuff. Now, download MvcContrib TestHelper and check out TestControllerBuilder . The builder sets up everything you need in order to have controller context and other stuff which you depend upon.
Ok, we are not over yet - you wanted to test your own override of Initialize right?
TestControllerBuilder doesnt call your Initialize because it does initialization in different way. I suggest you to factor out your custom Initialize() logic out into different method. Then create fake (stub) subclass with public method that calls this factored out protected Initialize. Are you with me?
something like:
public abstract class ApplicationController : Controller
{
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
MyInitialzie()
}
protected void MyInitialize()
{
ControllerContext.XXX // do whatewer you want here. Context is already setted up
}
}
class FakeController: ApplicationController
{
public void CallMyInitialize()
{
MyInitialize();
}
}
Later in test class:
[Test]
public void MyInitializeTest()
{
TestControllerBuilder builder = new TestControllerBuilder();
FakeController controller = new FakeController();
builder.InitializeController(controller);
controller.CallMyInitialize();
//TODO: verification of MyInitialize assumptions
}
Is that clear?

How to set navigation variables in MVC Masterpages

I need to have some navigation options, that require keys that are specific to the current user, that reside in a masterpage. I need some advice on best practise.
In have the following links in a left nav in a masterpage
http://www.example.com/manageShop/123
http://www.example.com/addProductToShop/123
http://www.example.com/addStaffToShop/123
Where '123' is the shop id that the current user is the manager of. I need some way of passing this to the masterpage
Currently I'm going something to this effect:
<li><%= Html.ActionLink<ShopController>(x => x.ManageShop((int)Session["ShopKey"]), "Manage")%></li>
I thought this was a good idea as I only have to set the ShopKey once in the session and its done, the down side is that iv noticed that the session gets mixed if you have the site open is two tabs.
Alternatively I tried this:
<li><%= Html.ActionLink<ShopController>(x => x.ManageShop((int)ViewData["ShopKey"]), "Manage")%></li>
But this means you have to keep setting the ViewData in every action in every controller. Which is awful.
EDIT: I have had alook at filters like eu-ge-ne suggested below, but I dont this really solves my problem as I still have the issue of setting the ShopKey everywhere?
What is the solution?
You can create custom filter for this:
public class UserKeyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData["UserKey"] = UserKey;
}
}
and use it on your controller or controller actions
[UserKey]
public class YourController : Controller
{
// or
public class YourController : Controller
{
[UserKey]
public ActionResult Index()
{
or use Controller.OnActionExecuting() (or even create base controller for this as Arnis L. said):
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData["UserKey"] = UserKey;
}
}
// and then derive your controllers from BaseController
public class YourController : BaseController
{

ASP MVC Authorize all actions except a few

I have a controller and I would like to require Authorization for all actions by default except a couple. So in the example below all actions should require authentication except the Index. I don't want to decorate every action with the Authorize, I just want to override the default authorization in certain circumstances probably with a custom filter such as NotAuthorize.
[Authorize]
public class HomeController : BaseController
{
[NotAuthorize]
public ActionResult Index()
{
// This one wont
return View();
}
public ActionResult About()
{
// This action will require authorization
return View();
}
}
Ok, this is what I did. If there is a better way let me know.
public class NotAuthorizeAttribute : FilterAttribute
{
// Does nothing, just used for decoration
}
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Check if this action has NotAuthorizeAttribute
object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
if (attributes.Any(a => a is NotAuthorizeAttribute)) return;
// Must login
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
What about [AllowAnonymous] ??
MVC4 has a new attribute exactly meant for this [AllowAnonymous] (as pointed out by Enrico)
[AllowAnonymous]
public ActionResult Register()
Read all about it here:
http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx
Here's what I would do, similar to Craig's answer with a couple of changes:
1) Create an ordinary attribute deriving from System.Attribute (no need to derive from FilterAttribute since you aren't going to be using anything FilterAttribute provides).
Maybe create a class hierarchy of attributes so you can test based on the hierarchy, e.g.
Attribute
AuthorizationAttribute
AuthorizationNotRequiredAttribute
AuthorizationAdminUserRequiredAttribute
AuthorizationSuperUserRequiredAttribute
2) In your BaseController override the OnAuthorization method rather than the OnActionExecuting method:
protected override void OnAuthorization(AuthorizationContext filterContext)
{
var authorizationAttributes = filterContext.ActionDescriptor.GetCustomAttributes(true).OfType<AuthorizationAttribute>();
bool accountRequired = !authorizationAttributes.Any(aa => aa is AuthorizationNotRequiredAttribute);
I like the approach of being secure by default: even if you forget to put an attribute on the Action it will at least require a user to be logged in.
Use a custom filter as described in Securing your ASP.NET MVC 3 Application.
Mark the controller with [Authorize]
[Authorize]
public class YourController : ApiController
Mark actions you want public with :
[AllowAnonymous]
Little late to the party, but I ended up creating a Controller-level auth attribute and an Action-level auth attribute and just skipping over the Controller auth if the Action had its own Auth attribute. See code here:
https://gist.github.com/948822

Resources