Click here to Skip to main content
11,570,352 members (57,210 online)
Click here to Skip to main content

Redirecting to custom 401 page when "Access denied" occures within an ASP.NET application with Windows authentication

, 3 Aug 2005 201.3K 1.7K 44
Rate this:
Please Sign up or sign in to vote.
This article answers a simple question: What to do when custom error page for error 401 in web.config is not working? How to replace the default ASP.NET "Access denied" page?

Introduction

If you have an ASP.NET application with authentication mode set to Windows:

 <authentication mode="Windows"/> 
 <authorization>
         <deny users="?" />
 </authorization>

Then all Windows users can access your pages but those without Windows login (from internet) will receive an ASP.NET "Access Denied 401" page. I have decided to replace this default message with some custom page. After couple of hours Googling, I found out that this is a very common problem and all the workarounds which seem to be reasonable does not work. Here are some of them:

  1. Use a custom error page in Web.config:
    <customErrors defaultRedirect="ErrorPage.asp&shy;x" mode="On"> 
        <error statusCode="401" redirect="AccessDenied.aspx" />       
    </customErrors>

    This works fine with statusCode="404" but not with 401.

  2. Try to catch an unauthorized request in one of the application events in Global.asax.cs:
    protected void Application_AuthenticateRequest(Object sender, 
                                                        EventArgs e)
    {
     if (!Request.IsAuthenticated) Response.Redirect(
                                                "AccessDenied.aspx"); 
    }

    It is also useless, because even the browsers with valid credentials make two posts, one without credentials and having Request.IsAuthenticated=false and the other one with credentials and having Request.IsAuthenticated=true. Browsers without credentials make only one post. It means you are not able to determine if the first post having Request.IsAuthenticated=false comes from an unauthorized browser or not.

The problem

Then I found an answer from a Guru at microsoft.public.dotnet.framework.aspnet.security newsgroup.

That's correct. There's no way around that. The way wininet authentication works is that if the resource you are requesting does not allow anonymous access, a 401 is sent back to the browser. If the resource is using Windows Integrated authentication and the browser is configured to automatically send credentials, the token is sent back and the user is authenticated. In the case of Basic authentication, a login prompt is displayed and the user must log in.

If you intercept the 401 and redirect somewhere, you hijack the browser's ability to challenge. There is no way around that.

Jxx Cxxxxxx, MCSE, MCSD [MSFT], Developer Support, ASP.NET.

Resolution

That was also the result of my research. The whole thing works like this:

  1. The browser sends request without credentials to the server.
  2. Server rejects this request and answers with "401 Access Denied".
  3. Browser recognizes 401 and if it has appropriate credentials does not show this message. The second request with credentials will be posted. The requested page will be sent to the browser.
  4. If the browser has no credentials the second post will not take place. The received "401 Access Denied" will be shown.

The workaround is to manipulate the content of "401 Access Denied" response. The browser uses the header of this response to determine 401 case. It means we can manipulate the HTML content without influencing the whole challenge. For instance we can add the following code in the Application_EndRequest event of Global.asax.cs.

  protected void Application_EndRequest(Object sender, 
                                             EventArgs e)
  { 
     HttpContext context = HttpContext.Current;
     if (context.Response.Status.Substring(0,3).Equals("401"))
     {
        context.Response.ClearContent();
        context.Response.Write("<script language="javascript">" + 
                     "self.location='../login.aspx';</script>");
     } 
  }

Now, the whole thing works like this:

  1. The browser sends request without credentials to the server.
  2. Server rejects this request and answers with "401 Access Denied" Header + our JavaScript.
  3. Browser recognizes 401 and if it has appropriate credentials does not show this message. Our HTML will not be rendered and JavaScript will not be executed. The second request with credentials will be posted. The requested page will be sent to the browser.
  4. If the browser has no credentials, the second post will not take place. The received "401 Access Denied" will be shown. Our HTML will be rendered and JavaScript will be executed. The client side redirection will take place. The browser will show a custom 401 page.

Sample project

The sample project has only a few relevant lines of code in the Application_EndRequest event of Global.asax.cs. The page default.aspx is accessible only to authorized Windows users. If access is denied the page PublicArea/AccessDenied.aspx will be called. The folder PublicArea is according to local Web.config also accessible for anonymous users.

Attention: The IIS website must be configured to allow anonymous access.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

George Mamaladze
Software Developer
Germany Germany
Tweeter: @gmamaladze
Google+: gmamaladze
Blog: gmamaladze.wordpress.com

You may also be interested in...

Comments and Discussions

 
QuestionProblem with your sample Pin
Member 35072898-Dec-10 2:36
memberMember 35072898-Dec-10 2:36 
AnswerRe: Problem with your sample Pin
Member 233208914-Mar-12 9:05
memberMember 233208914-Mar-12 9:05 
While this response is horrendously UN-timely, but included for others....

I just encountered the same issue with IIS 7.5 on Win 2008 R2... Everything worked great in development and locally (read: http://localhost) on the deployment server. However when hitting the site remotely, the system would return the IIS 401 Unauthorized error message...

Here's what I discovered (purely by dumb luck)...

From: IIS.Net - HTTP Errors Configuration, I was reading the attribute definitions and came across the errorMode attribute with the possible settings of DetailedLocalOnly, Custom and Detailed (Default value being: DetailedLocalOnly). To me this sounded suspiciously like CustomErrors of (RemoteOnly, On, and Off respectively)... I updated my web.config by adding inside the system.webServer node the following:
	  <httpErrors errorMode="Detailed">
	  </httpErrors>

Note that i am NOT changing the handlers, just the default errorMode. By changing the value to 'Detailed', my overridden error message was displayed -- SUCCESS!

Therefore it appears that we are able to override the detailed error message by the approach above, but a custom error handler trumps this...

Also Note, that I did try the approach by umbyersw, but I seemed to get the custom message always and was not challenged for my credentials (might be an issue with my authorization block)...
GeneralRe: Problem with your sample Pin
mjl1237-May-13 0:12
membermjl1237-May-13 0:12 
GeneralRe automatic redirection to Login.aspx Pin
Ajay Kale New9-Sep-10 2:35
memberAjay Kale New9-Sep-10 2:35 
GeneralProcesses running in IIS7+ Integrated Pipeline Mode don't need this... Pin
umbyersw10-Feb-10 15:18
memberumbyersw10-Feb-10 15:18 
GeneralRe: Processes running in IIS7+ Integrated Pipeline Mode don't need this... Pin
Member 38565896-Nov-11 19:48
memberMember 38565896-Nov-11 19:48 
GeneralCall an Application_Error Pin
student-uni14-Apr-09 1:09
memberstudent-uni14-Apr-09 1:09 
QuestionWhy is anonymous authentication needed? Pin
Berend Engelbrecht6-May-08 9:13
memberBerend Engelbrecht6-May-08 9:13 
AnswerRe: Why is anonymous authentication needed? Pin
adaptor11-Jun-09 2:11
memberadaptor11-Jun-09 2:11 
AnswerRe: Why is anonymous authentication needed? Pin
Berend Engelbrecht11-Jun-09 6:54
memberBerend Engelbrecht11-Jun-09 6:54 
QuestionCannot deny some role to access Pin
BMWABCD17-May-07 10:05
memberBMWABCD17-May-07 10:05 
QuestionRe: Cannot deny some role to access Pin
George Mamaladze17-May-07 21:49
memberGeorge Mamaladze17-May-07 21:49 
QuestionRe: Cannot deny some role to access Pin
BMWABCD18-May-07 8:11
memberBMWABCD18-May-07 8:11 
AnswerRe: Cannot deny some role to access Pin
BMWABCD18-May-07 8:13
memberBMWABCD18-May-07 8:13 
QuestionRe: Cannot deny some role to access Pin
BMWABCD18-May-07 8:18
memberBMWABCD18-May-07 8:18 
AnswerRe: Cannot deny some role to access Pin
George Mamaladze18-May-07 8:53
memberGeorge Mamaladze18-May-07 8:53 
JokeRe: Cannot deny some role to access Pin
George Mamaladze18-May-07 8:56
memberGeorge Mamaladze18-May-07 8:56 
Generalprocessing custom error page 401 Pin
ernest_elias9-Feb-06 22:05
memberernest_elias9-Feb-06 22:05 
Questionlogin popup Pin
jpberset3-Feb-06 1:31
memberjpberset3-Feb-06 1:31 
AnswerRe: login popup Pin
George Mamaladze3-Feb-06 5:50
memberGeorge Mamaladze3-Feb-06 5:50 
GeneralRe: login popup Pin
golden child16-Oct-06 10:54
membergolden child16-Oct-06 10:54 
GeneralReally Good One... Pin
prapro17-Oct-05 2:43
memberprapro17-Oct-05 2:43 
GeneralServer-side redirect Pin
Leonid Fofanov16-Aug-05 7:49
sussLeonid Fofanov16-Aug-05 7:49 
GeneralRe: Server-side redirect Pin
George Mamaladze16-Aug-05 8:40
memberGeorge Mamaladze16-Aug-05 8:40 
GeneralThanks for the effort Pin
eleung10-Aug-05 9:55
membereleung10-Aug-05 9:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150624.2 | Last Updated 3 Aug 2005
Article Copyright 2005 by George Mamaladze
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid