awj
awj

Reputation: 7949

Custom AuthorizeAttribute not being implemented

In our MVC solution we have two custom implementations of AuthorizeAttribute - one is named BasicHttpAuthorizeAttribute and has been used in production for years, and the other RoleAuthorizeAttribute, which was recently added.

When creating RoleAuthorizeAttribute I simply copied BasicHttpAuthorizeAttribute and modified some of the already-overridden methods.

Both attributes serve the purpose of authenticating the user, and the RoleAuthorizeAttribute of verifying that the user has the required role.

However, RoleAuthorizeAttribute never authenticates the user. It is simply not being called and instead our MVC controllers throw an exception when a non-logged-in user reaches the controller action and the code requests the context user.

Below is the outline for this custom AuthorizeAttribute. If I put breakpoints on all of those methods I find that none of them are hit when a request is made.

Can anyone explain why this class is not being used to authenticate users? Why is it that an unauthenticated user is not being redirected to the login page, but if I swap RoleAuthorize for BasicHttpAuthorize or simply the base Authorize then they are redirected?

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]    
public class RoleAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
    /// <summary>
    /// Gets or sets the <see cref="Role"/> enumerations required for authorization.
    /// </summary>
    public Role[] RequiredRoles
    {
        get {...}
        set {...}
    }

    public bool RequireSsl { get; set; };

    public bool RequireAuthentication { get; set; }

    public RoleAuthorizeAttribute(params Role[] requiredRoles)
    {
        // ...
    }

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        // ...
    }

    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        // ...
    }

    private bool Authenticate(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        // ...
    }

    public static bool TryGetPrincipal(string authHeader, out IPrincipal principal)
    {
        // ...
    }

    public static bool TryGetAuthCookie(out IPrincipal principal)
    {
        // ...
    }

    private static string[] ParseAuthHeader(string authHeader)
    {
        // ...
    }

    private static bool TryGetPrincipal(string username, string password, out IPrincipal principal)
    {
        // ...
    }
}

And here is an example of its usage:

namespace MyProject.Areas.Customer.Controllers
{
    [RoleAuthorize(Role.Customer, Role.CompanyAdmin)]
    public partial class OrderController : MyCustomController
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof (OrderController));

        public ActionResult Index(int id)
        {
            // ...
        }
    }
}

We use Basic Authentication so there's a header set thus:

enter image description here

I've seen older questions asking about the same problem, but in those cases, they also override an AuthorizeCore method which no longer seems to be present on the AuthorizeAttribute class.

Upvotes: 3

Views: 683

Answers (1)

awj
awj

Reputation: 7949

I figured out myself why this was happening.

There are two AuthorizeAttributes - one in the System.Web.Http namespace and the other in System.Web.Mvc. I wasn't aware of this and was trying to build a one-size-fits-all attribute, so my attribute was working for WebAPI requests but not for MVC controller requests.

The difference in these two attributes is in the OnAuthorize method where they each take a different context argument.

Once I had built two separate attributes (which are almost identical), each deriving from a different AuthorizeAttribute, everything worked as expected.

Upvotes: 5

Related Questions