7
votes

I have an ASP.NET MVC3 application with Windows Authentication deployed to IIS6. When an authenticated user clicks on a link that they are not authorized to view, they are prompted to enter their username and password (in a browser dialog, not a page), as expected.

However, after clicking Cancel or entering invalid credentials three times, instead of seeing the a 401 Unauthorized page, I see a blank white page.

Looking at Fiddler, there are three requests/responses after clicking Cancel. Here are the response summaries and headers:

  1. ASP.NET Access is denied message (401.2)

    HTTP/1.1 401 Unauthorized Date: Fri, 20 Jul 2012 14:34:21 GMT Server: Microsoft-IIS/6.0 WWW-Authenticate: Negotiate WWW-Authenticate: NTLM X-Powered-By: ASP.NET X-AspNet-Version: 4.0.30319 Cache-Control: private Content-Type: text/html; charset=utf-8 Content-Length: 1701 Proxy-Support: Session-Based-Authentication

  2. IIS You are not authorized to view this page (401.1)

    HTTP/1.1 401 Unauthorized Content-Length: 1539 Content-Type: text/html Server: Microsoft-IIS/6.0 WWW-Authenticate: NTLM TlRMTVNTUAACAAAADAAMADgAAAAF... (omitted for brevity) X-Powered-By: ASP.NET Date: Fri, 20 Jul 2012 14:34:21 GMT Proxy-Support: Session-Based-Authentication

  3. Empty response

    HTTP/1.1 401 Unauthorized Date: Fri, 20 Jul 2012 14:34:21 GMT Server: Microsoft-IIS/6.0 WWW-Authenticate: Negotiate WWW-Authenticate: NTLM X-Powered-By: ASP.NET X-AspNet-Version: 4.0.30319 X-AspNetMvc-Version: 3.0 Cache-Control: private Content-Length: 0 Proxy-Support: Session-Based-Authentication

How do I get this to display a 401 error page?

Update 1:

Here is my web.config errors section.

<customErrors mode="RemoteOnly" defaultRedirect="~/Error" />

I'm also using HandleErrorAttribute.

I suspect that IIS is returning the blank page rather than ASP.NET, but I'm not sure how to prove that.

Update 2:

This is interesting. If I refresh the blank page, I see the ASP.NET Access is Denied message.

2
Just a guess but is it trying to redirect them back to the Username and Password page because they still aren't authorized? And since it already thinks it handled the user the view doesn't have anything to display?Andrew Hagner
It's not a login page, its the browser login dialog.jrummell
Ah sorry didn't see that part. After the third attempt are you redirecting them to the 401 page? If not then you remain on the same page but you don't get any content displayed because the server doesn't send any.Andrew Hagner
@AndrewHagner how would I redirect them after authorization fails?jrummell
Well, for any project I've done we use a custom 'Access Denied' page and just do a standard mvc direct to that. If you really are against doing that then you will have to find a way to redirect to the 401 page itself, which I'm not even sure you can do because that page isn't hosted until that error actually occurs. Maybe try redirecting to the same page, you had mentioned that if you refresh it then it sends you there so maybe that will work.Andrew Hagner

2 Answers

1
votes

I came up with this work around after looking into 401 redirection as @AndrewHagner suggested. It's based on this answer. I implemented AuthorizeAttribute and overrode HandleUnauthorizedRequest().

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
    {
        var authenticatedUnauthorizedRouteValues =
                new RouteValueDictionary(new {controller = "Error", action = "Index"});

        filterContext.Result = new RedirectToRouteResult(authenticatedUnauthorizedRouteValues);
        filterContext.Controller.TempData["message"] = 
                "You are not authorized to view this page.";
    }
    else
    {
        base.HandleUnauthorizedRequest(filterContext);
    }
}

So as I understand, this will catch unauthorized requests in the MVC pipeline before being sent to IIS. This gives me the opportunity to redirect to a user friendly not authorized page.

0
votes

you should try setting in your web.config file a rule to redirect the user to the Unauthorized page in this way.

 <System.Web>
   //map all the erros presented in the application to the error.aspx webpage
   <customErrors mode="RemoteOnly" defaultRedirect ="~/error.aspx">
   //redirect the user to a Error401.pasx Page after the server get an 401 Error 
   <error statusCode="401" redirect="Error401.aspx" />
  </customErrors>
 <System.Web>

I hope this works for you.