Friday, January 18, 2013

MVC4 Authroize Attribute

Most people know about authorize attribute and to customize also, but i had a request where i need to combine below elements 1. The roles will be from an external application 2. I wont know what action or controller they can perform 3. Do not want to code If statement to check the access on each controller 4. Want to make the make the connection of Role and action in the project 5. no usage of sessions So thought of a design 1. Have the role and controller action in web.config
 

    
      
    
        
        
              
    
          
        
              
    
  
2. using cutom configuration as below
 

using System;
using System.Collections;
using System.Text;
using System.Configuration;
using System.Xml;



namespace SomethingCommon
{

    public class RolesSection : ConfigurationSection
    {
        [ConfigurationProperty("", IsDefaultCollection = true)]
        public RoleElementCollection Elements
        {
            get { return (RoleElementCollection)base[""]; }
        }
    }

    public class RoleElementCollection : ConfigurationElementCollection
    {
        const string ELEMENT_NAME = "Role";

        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }

        protected override string ElementName
        {
            get { return ELEMENT_NAME; }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new RoleElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((RoleElement)element).Name;
        }
    }

    public class RoleElement : ConfigurationElement
    {
        const string NAME = "name";

        [ConfigurationProperty(NAME, IsRequired = true)]
        public string Name
        {
            get { return (string)base[NAME]; }
        }

        [ConfigurationProperty("", IsDefaultCollection = true)]
        public ControllerActionElementCollection Elements
        {
            get { return (ControllerActionElementCollection)base[""]; }
        }
    }

    public class ControllerActionElementCollection : ConfigurationElementCollection
    {
        const string ELEMENT_NAME = "ControllerAction";

        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }

        protected override string ElementName
        {
            get { return ELEMENT_NAME; }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new ControllerActionElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ControllerActionElement)element).Id;
        }
    }

    public class ControllerActionElement : ConfigurationElement
    {
        const string ID = "id";

        [ConfigurationProperty(ID, IsRequired = true)]
        public string Id
        {
            get { return base[ID].ToString(); }
        }
    }


}
2. Have Security attributre in the controller
 
 [Security]
        public JsonResult GetSomething(string sidx, string sord, int page, int rows, string ID)
        {
3. ... Still thinking of cahing but check each controller
 


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;


namespace SomethingBLL
{
    public class SecurityAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
      
             var wccSecurityList = from external system

            var securityList = wccSecurityList as IList ?? wccSecurityList.ToList();
         
            

            //find if the role allows to access the contoller action - if yes then allow , if not then error 
            var controllerAction = filterContext.Controller.ToString() + "-" + filterContext.ActionDescriptor.ActionName;

	
		// to chek
            var isAuthorized = ControllerActionRoles.CheckControllActionForRole(securityList, controllerAction);
                  
            if (!isAuthorized && filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
            {
                filterContext.Result = new RedirectToRouteResult(new
                                                                     RouteValueDictionary(
                                                                     new {controller = "Error", action = "AccessDenied"}));
            }
        }

    }
}

 




4. Code the combines the list and do the magic of checking . please remember the code has some things which i used in my project so it it just an idea ../. RolesSecurity is a model that has 2 string items from web.conifg


 private static List GetRoles()
        {
            var roleSecurityList = new List();
            var section = ConfigurationManager.GetSection("Roles");
            var RolesSection = ConfigurationManager.GetSection("Roles") as RolesSection;

           
            if (RolesSection != null)
            {

                roleSecurityList.AddRange(
                  RolesSection.Elements.Cast()
                                 .SelectMany(Role => Role.Elements.Cast(),
                                             (Role, controllerAction) => new RolesSecurity
                                             {
                                                 RoleName = Role.Name,
                                                 ControllerAction = controllerAction.Id
                                             }));
            }
            else
            {
                throw new Exception("Error");
            }

            return roleSecurityList;
        }


  public static bool CheckControllActionForRole(IList mstRole, string controllerAction)
        {
         
            //get the list from webconfig
            List controllerActionList = GetRoles();        
            var commonList = controllerActionList.Where(x => mstRole.Any(x1 => x1.ToString() == x.RoleName)).Where(x => x.ControllerAction == controllerAction);

            //get only the list for mstRole 
            // check if the controllaction from security is in controlleraction of webconfig
            return commonList.Any();
        }

Unity , Aspect Oriented and Interceptor for C#

Example using MVC 4 , Unity, AOP , Interceptor
 













 
In C#
 
 public class Interceptor : IInterceptionBehavior
    {
        /// 
        /// Returns the interfaces required by the behavior for the objects it intercepts.
        /// 
        /// 
        /// The required interfaces.
        /// 
        public IEnumerable GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        /// 
        /// Implement this method to execute your behavior processing.
        /// 
        /// Inputs to the current call to the target.
        /// Delegate to execute to get the next delegate 
        /// in the behavior chain
        /// 
        /// Return value from the target.
        /// 
        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            /* Call the method that was intercepted */
            string className = input.MethodBase.DeclaringType.Name;
            string methodName = input.MethodBase.Name;
            string generic = input.MethodBase.DeclaringType.IsGenericType ? string.Format("<{0}>", input.MethodBase.DeclaringType.GetGenericArguments().ToStringList()) : string.Empty;
            string arguments = input.Arguments.ToStringList();
            string preMethodMessage = string.Format("{0}{1}.{2}({3})", className, generic, methodName, arguments);


            var auditLog = new AuditLog();
            auditLog.UserName = Environment.UserName;
            auditLog.ActivityType = string.Format("ClassName - {0} : MethodName - {1}", className, methodName);
            auditLog.Description = preMethodMessage;


            Task.Factory.StartNew(() => Logger.Instance.Log(auditLog));
            
            
            IMethodReturn msg = getNext()(input, getNext);            
            string postMethodMessage = string.Format("{0}{1}.{2}() -> {3}", className, generic, methodName, msg.ReturnValue);
            auditLog.Description = postMethodMessage;
            Task.Factory.StartNew(() => Logger.Instance.Log(auditLog));            
            return msg;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }