3

I'm trying to implement custom basic authentication on specific controller of MVC 2 application. Specifically I inherited from AuthorizeAttribute and override AuthorizeCore() method:

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
    if( doAuthorization() ) {
        return true;
    }
    // send HTTP 401
    HttpContext context = HttpContext.Current;
    context.Response.StatusCode = 401;
    context.Response.AddHeader( "WWW-Authenticate",
        String.Format("Basic realm=\"{0}\"", myRealm);
    context.Response.End();
    return false;
}

and marked the controller with my inherited attribute.

The whole thing works, but whenever AuthorizeCore returns false MVC continues processing the request and Application_Error() is invoked and I retrieve the following exception there:

Server cannot set status after HTTP headers have been sent.
at System.Web.HttpResponse.set_StatusCode(Int32 value)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
at System.Web.Mvc.Controller.ExecuteCore()
at System.Web.Mvc.MvcHandler.<>c__DisplayClass8.<BeginProcessRequest>b__4()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0()
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

How do I make MVC stop processing the request and prevent that exception?

sharptooth
  • 167,383
  • 100
  • 513
  • 979

2 Answers2

6

I ran into a similar problem (where I need to redirect) and the below fixed mine

  1. I used OnAuthorization override
  2. When I had to redirect did the below

    filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.Redirect); filterContext.HttpContext.Response.Redirect(url, false);

The key was to populate filterContext.Result. If populated the MVC framework was not invoking the action method.

Ramesh
  • 13,043
  • 3
  • 52
  • 88
0

Please see answer here: Extend AuthorizeAttribute Override AuthorizeCore or OnAuthorization

You should not be setting headers and ending the response in AuthorizeCore, as its 'decision code'

Override OnAuthorization to add headers etc

EDIT: To prevent MVC continuing processing the request, FilterContext.Result in OnAuthorization needs to be set.

EDIT: You may end up getting a CustomError. If so add the following:

HttpContext.Response.TrySkipIisCustomErrors(true)
Community
  • 1
  • 1
stevenrcfox
  • 1,547
  • 1
  • 14
  • 37
  • I still can't stop request processing - it proceeds to `FormsAuthenticationModule.OnLeave()`, the latter proceeds to `HttpResponse.Redirect()` and I get the very same error as originally since I've ended the response already. – sharptooth Oct 13 '11 at 13:53
  • Ok, try context.ApplicationInstance.CompleteRequest() instead of Response.End() – stevenrcfox Oct 13 '11 at 14:02
  • Edit: Also, Meant to say Override OnAuthoirization, NOT OnAuthorize – stevenrcfox Oct 13 '11 at 14:09
  • http://cacheandquery.com/blog/2011/03/customizing-asp-net-mvc-basic-authentication/ Gives a full implementation. I have a sneaky suspicion that you also need to set filtercontext.result to stop the request processing further too. – stevenrcfox Oct 13 '11 at 14:26
  • Unbelievable - I call `CompleteRequest()` inside `OnAuthorization()` and an unauthorized request passes further. – sharptooth Oct 13 '11 at 15:01
  • As per my 2nd last comment, You do need to set FilterContext.Result. Response.End and ApplicationInstance.CompleteRequest() both work on the ASP.NET event level, Whereas setting FilterContext.Result works at the MVC level. The link I provided in the comment above has everything. – stevenrcfox Oct 14 '11 at 11:33