Software Engineer Problem Solver

Leo Reading

One Moment, Please...

Find My Articles

Share This Page

B l o g

Blog

Leo Reading

Software Engineer and Problem Solver From the USA

Download Resume

My Blog A collection of technical and non-technical mishaps, achievements and stories.

Programming

Authorization Attributes - AuthorizeCore

Today I had an interesting issue with a custom authorization attribute, something I've written at least a dozen times in the last 6 months.  I typically lock down my MVC projects using a lot of the built in frameworks, but where I'm such a fanboy of dapper, I like to extend it a little more and add an enum to help me handle the roles and authorization.

I had a custom authorization attribute where I was toying with the idea of doing AND/OR operations on the different roles (authorize all, authorize any).  Everything looked great, but the AuthorizeCore override was never being executed!  This is the code, which is 100% un-tested, and missing the ever so important caching expiration policy settings that authorization attributes should have: 

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    public class AuthorizeAny : AuthorizeAttribute
    {
        public object[] _Roles { get; set; }
        public AuthorizeAny(params object[] roles)
        {
            if (roles.Any(r => r.GetType().BaseType != typeof(Enum)))
                throw new ArgumentException("roles");
            this._Roles = roles;
            this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
        } // end constructor
 
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            bool UserIsAuthorized = false;
            BLL.Database.DatabaseMethods db = new BLL.Database.DatabaseMethods();
            String UserId = httpContext.User.Identity.GetUserId();
            foreach (var role in _Roles)
            {
                if (db.IsUserInrole(UserId, db.GetRoleId(role.ToString())))
                {
                    UserIsAuthorized = true;
                    break;
                } // end if
            } // end loop
            return UserIsAuthorized;
        } // end AuthorizeCore
 
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result = new RedirectResult("/Error/Error401");
        } // end Handle UnauthorizedRequest
Again, aside from some security holes and not having tested the logic or optimizing it, it looks like it should get the job done.  Apparently, the issue wasn't in my attribute, it was in how it was being used.  On my controller, I had an [AllowAnonymous] tag at the class level, because I believed that this would override the anonymous where it was at a method level. This is being used on an error controller so that I can have my custom errors, and also a reporting module that should only be seen by specific individuals within a role (in this case, only the index, everything else should be publicly available):
 
   [AllowAnonymous]
    public class ErrorController : Controller
    {
        [AuthorizeAll(RolesEnum.Role1, RolesEnum.Role2)]
        public ActionResult Index()
        {
            return View();
        } // end Index
} // end class ErrorController
Well, it wasn't working still.  Why is it that the constructor was being triggered for my AuthorizeAll attribute, but not the AuthorizeCore?  I'll tell you why.  

The AllowAnonymous attribute was already authorizing it, so when it hit my method, it didn't feel the need.

Only apply the allow anonymous attribute to the specific methods,  not the controller!  If you apply it to the controller, you're going to waste 3 hours figuring out why you can't lock any of the methods down.

 

Hope this helps someone!

Leo Reading

Leo Reading is a US based software engineer and problem solver. Known as a jack of all trades and master of few, Leo is constantly learning new technology and expanding his understanding of all things 'nerd'

You Might Also Like

Delay In Development

I had put a decent amount of time and effort into creating this website, but unfortunately it is still seriously lacking in the content department.  While I've been meaning to update it, I've been spending every free moment I have working on a super top-secret project that I will be announcing soon.  If you look through my othe...

New Website

Facebook and Twitter are a great place to share personal thoughts, pictures, etc with your friends and family.  A big part of who I am is my inner nerd.  I wanted a place to share this part of me with the world.  I've begun development on this site so that I can do just that.  I plan to share some of the technological str...

One Moment, Please

Close