MVC 4 AuthorizeAttribute.HandleUnauthorizedRequest ViewResult - infinite loop
Asked Answered
P

2

9

i've stepped through my code a million times and can't find a problem with my implementation..

in custom AuthorizeAttribute i overwrote 2 methods

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (!httpContext.Request.IsAuthenticated)
            return false;
        var routeData = httpContext.Request.RequestContext.RouteData;
        var ctrl = routeData.Values["controller"].ToString();
        var action = routeData.Values["action"].ToString();
        var user = httpContext.User.Identity.Name;
        _logger.Info("[logging all the details]");
        return ctrl == "SomeController";
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext ctx)
    {
        ctx.Result = new ViewResult  { ViewName = "Unauthorized" };
        // base.HandleUnauthorizedRequest(ctx);
     }

the authorization logic is mocked to return false only on specific controller, and i've stepped through this to verify it's working correctly.

above code will cause infinite loop. in my log i can see that line hit 666 times (coincidence?) ..

if i do call base.HandleUnauthorizedRequest(ctx), all i get is a blank page. so i reflected what the base does, and it's this

filterContext.Result = new HttpUnauthorizedResult();

so this explains why it renders a blank page instead of redirecting to Unauthorized.cshtml. what i'm not sure about, is why does it go into an infinite loop if i don't call the base.

p.s.

i've verified that if i put the wrong Unauthorized view it will error out (but still hangs indefinitely)

 System.InvalidOperationException: The view 'Unauthorized11' or its master was not found or no view engine supports the searched locations
Paresh answered 16/11, 2013 at 0:2 Comment(0)
P
16

Here is the implementation that i ended up going with and it's working very well.

    public override void OnAuthorization(AuthorizationContext filterContext)
    {

        base.OnAuthorization(filterContext);

        // this is overriden for kendo menus to hide 
        var ctrl = filterContext.RequestContext.RouteData.GetRequiredString("controller");
        var action = filterContext.ActionDescriptor.ActionName;

        [custom authorization logic on action/ctrl]

        // useful to determine if it's authorizing current controller path or menu links
        var path = filterContext.HttpContext.Request.PhysicalPath;
        _authorizingCurrentPath = path.Contains(ctrl) || path.EndsWith("WebUI") ;


        if (userAuth < requiredAuth)
            HandleUnauthorizedRequest(filterContext);
    }


    protected override void HandleUnauthorizedRequest(AuthorizationContext ctx)
    {
        if (!ctx.HttpContext.User.Identity.IsAuthenticated)
            base.HandleUnauthorizedRequest(ctx);
        else {
            if (_authorizingCurrentPath) {
                // handle controller access
                ctx.Result = new ViewResult { ViewName = "Unauthorized" };
                ctx.HttpContext.Response.StatusCode = 403;
            }
            else {
                // handle menu links
                ctx.Result = new HttpUnauthorizedResult();
                ctx.HttpContext.Response.StatusCode = 403;
            }
        }
    }
Paresh answered 10/6, 2014 at 16:55 Comment(4)
what about the variable if (userAuth < requiredAuth) ? can you describe it?Theodor
@AbhishekB. it's an enum, with underlying int .. so read = 5, full = 10 etc.. so you can do currentAtrr > read etcParesh
does this help? #19537583Paresh
Ok. it helped. I am using with session object with role.Theodor
I
6

The default implementation of AuthorizeAttribute sets the response on the action context, by not calling into the base the response is never set which causes the filter to repeat the authorization process until a response is set (hence the infinite loop).

You can see this logic in the AuthorizationFilterAttribute class which AuthorizeAttribute derives from.

Inflationary answered 16/11, 2013 at 0:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.