ASP.NET MVC Controller And Action Role Authentication

Today, I was playing around with ASP.NET MVC Framework when I came to an interesting situation. I was displaying Categories from the Northwind database as ActionLinks. When clicked on the link it will popup a confirmation box asking whether you want to delete the item or not. Here is the code to display the link and the confirmation box:

 <% foreach (var category in ViewData)        { %>         <%= Html.ActionLink(c => c.Delete(category.id), category.CategoryName, new { onclick = "return confirmDelete(" + category.id +")" })%>        
        <% } %>

function confirmDelete(id) {     return confirm("Are you sure you want to delete?");        }

You don't need to define a separate function for confirmDelete but anyways!

The HTML code generated for this particular page (The Category List Page) is shown below:

Beverages Edite        
        Condiments

       
        Confections        
        Dairy Products        
        Grains/Cereals        

The above generated HTML code shows that Category/Delete/1 will delete the item with the id = 1. This means if I browse to the http://localhost:[portnumber]/Category/Delete/1 then the Item with the id = 1 will be deleted. But this opens a security hole since now anyone can type the URL with the id and delete the items. One way to solve this problem is by using the attribute based security as shown on post. But then you will have to decorate your actions with the security attribute which is not a good idea.

Another way is to override the OnPreAction attribute which is fired before the action is fired. I created a BaseController and inherited all my controllers from the BaseController. This way the OnPreAction is fired for each controller.

public class BaseController: Controller     {         public BaseController         {

        }

        protected override bool OnPreAction(string actionName, System.Reflection.MethodInfo methodInfo)         {             string controllerName =  methodInfo.DeclaringType.Name;                         if(!IsAuthenticated(controllerName,actionName)) throw new SecurityException("not authenticated");

            return base.OnPreAction(actionName, methodInfo);         }

        private bool IsAuthenticated(string controllerName, string actionName)         {             System.Web.HttpContext context = System.Web.HttpContext.Current;

            XDocument xDoc = null;

            if (context.Cache["ControllerActionsSecurity"] == null)             {                 xDoc =  XDocument.Load(context.Server.MapPath("~/ControllerActionsSecurity.xml"));                 context.Cache.Insert("ControllerActionsSecurity",xDoc);             }

            xDoc = (XDocument) context.Cache["ControllerActionsSecurity"];             IEnumerable elements = xDoc.Element("ControllerSecurity").Elements;

            var role = (from e in elements                         where ((string)e.Attribute("controllerName")) == controllerName                         && ((string)e.Attribute("actionName")) == actionName                         select new { RoleName = e.Attribute("Roles").Value }).SingleOrDefault;

            if (role == null) return true;

            if (!User.IsInRole(role.RoleName))                     return false;

            return true;         }

    }

I have created a ControllerActionsSecurity.XML file which stores the controllers, actions and roles allowed to fire the action.

 

Now, when you request for the /Category/Delete/1 your request will be denied if you are not of the Admin role. This way you will protect the controllers from firing restricted actions.

This article is part of the GWB Archives. Original Author: Mohammad Azam

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.