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

Web API Bearer Token And Claims

I'm working on a project that has an MVC Web API that lives on a different server from an MVC5 application that needs to consume the API.  Because the user information is stored in the same database as the rest of the information that the API is responsbile for, I decided to keep 100% of the data layer in the Web API. In the near future, I'll...

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