0

I have created a custom authorize attribute class for my application, to test if a user is allowed to access the API route. The user I am testing with has had all permissions that this class will test for removed, however the api is still running. What am I doing wrong?

UserActionsDictionary has tenant IDs as the keys and a list of strings for actions.

using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Application {
    public class HasActionAttribute : AuthorizeAttribute {

        public string Actions { get; set; }
        protected override bool AuthorizeCore(HttpContextBase httpContext) {
            UserCache userCache = HELPERS.GetCurrentUserCache();
            return userCache.UserActionsDictionary[userCache.CurrentTenantID.ToString()].Intersect(Actions.Split(',').ToList()).Any();
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
            filterContext.Result = new HttpUnauthorizedResult("Action not allowed for the current user");
        }
    }
}

And in the controller. I am testing what should be causing the authorize to fail within the route, it should never even make it in, but with breakpoints I am seeing that test is coming out to false.

[Authorize]
public class TestController : ApiController {

    [Route("api/Test/TestRoute")]
    [HttpGet]
    [HasAction(Actions="Test Action")]
    public dynamic Test(){
        UserCache userCache = HELPERS.GetCurrentUserCache();
        bool test = userCache.UserActionsDictionary[userCache.CurrentTenantID.ToString()].Intersect("Test Action".Split(',').ToList()).Any();
        return test;
    }
}

I see a lot of questions here on SO about similar topics, but none seem to address the issue I have here.

4
  • Seems like you're inheriting the wrong AuthorizeAttribute. You need to inherit from System.Web.Http not System.Web.Mvc (since it's a WebAPI controller). Commented Jan 3, 2017 at 21:27
  • @haim770 System.Web.Http doesn't seem to have what I need to override. if I have to inherit from System.Web.Http, that changes the question to how do I implement what I am trying to do? Commented Jan 3, 2017 at 21:30
  • They're different indeed but you can achieve the exact result when inheriting from System.Web.Http.AuthroizeAttribute as well. See msdn.microsoft.com/en-us/library/… and stackoverflow.com/questions/12629530/… Commented Jan 3, 2017 at 21:36
  • @haim770 if I understand right I should be doing this? public string Actions { get; set; } public override void OnAuthorization(HttpActionContext actionContext) { UserCache userCache = HELPERS.GetCurrentUserCache(); if (!userCache.UserActionsDictionary[userCache.CurrentTenantID.ToString()].Intersect(Actions.Split(',').ToList()).Any()) { HandleUnauthorizedRequest(actionContext); } } Commented Jan 3, 2017 at 22:08

2 Answers 2

1

haim770 answered my issue mostly in the question comments, so I'll put the full answer here for others with similar issues.

I was inheriting the wrong AuthorizeAttribute. I needed to inherit from System.Web.Http not System.Web.MVC. The final code for the attribute is below.

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;

namespace Application {
    public class HasActionAttribute : AuthorizeAttribute {

        public string Actions { get; set; }
        public override void OnAuthorization(HttpActionContext actionContext) {
            UserCache userCache = HELPERS.GetCurrentUserCache();
            List<string> actionsList = Actions.Split(',').Select(a=>a.Trim(' ')).ToList();
            if (!userCache.UserActionsDictionary[userCache.CurrentTenantID.ToString()].Intersect(actionsList).Any()) {
                HandleUnauthorizedRequest(actionContext);
            }
        }

        protected override void HandleUnauthorizedRequest(HttpActionContext filterContext) {
            filterContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden) { Content = new StringContent("Action not allowed for the current user") };
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

I think that you'd forgotten to put the:

GlobalFilters.Filters.Add(new HasActionAttribute()); 

in ~/App_Start/FilterConfig.cs.

The FilterConfig is used to manage global filters.

UPDATE:

And change you method to check for null parameter:

protected override bool AuthorizeCore(HttpContextBase httpContext) {
    if(string.IsNullOrWhiteSpace(Actions))
    {
        return true;
    }
    UserCache userCache = HELPERS.GetCurrentUserCache();
    return userCache.UserActionsDictionary[userCache.CurrentTenantID.ToString()].Intersect(Actions.Split(',').ToList()).Any();
}

5 Comments

Simply check for null and pass true if it is null @Andrew
This isn't global, it's supposed to be on individual routes.
Exactly which means that you should skip those who don't have this filter
No haim770 was correct, I was using the wrong AuthorizeAttribute
Glad you figured it out

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.