I am researching the possibilities of using WIF to identify users on parts of a customer's site running on EPiServer. I've managed to get WIF to kick in using, amongst others, the following post:
This works nicely if you set
<authorization>
<deny users="?"/>
</authorization>
in web.config, making all requests require an authenticated user. However, we would like to use EPiServer to separate what content should be available to anonymous users and authenticated users. The problem is, I just can't get it to work.
When I enable WIF, and don't set deny users="*"
, EPiServer kicks in and outputs some text to the response stream before WIF is enable to perform the redirect:
HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Tue, 01 Nov 2011 07:51:04 GMT
Connection: close
Access denied.
</pre></table></table></table></table></table></font></font></font></font></font></i></i></i></i></i></b></b></b></b></b></u></u></u></u></u><p> </p><hr>
This results in the following error when WIF tries to redirect to the STS:
Server Error in '/' Application.
Cannot redirect after HTTP headers have been sent.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: Cannot redirect after HTTP headers have been sent.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[HttpException (0x80004005): Cannot redirect after HTTP headers have been sent.] System.Web.HttpResponse.Redirect(String url, Boolean endResponse) +8712587
Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.RedirectToIdentityProvider(String uniqueId, String returnUrl, Boolean persist) +249
Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.OnEndRequest(Object sender, EventArgs args) +438
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +68 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75
I have searched both high and low to be able to override this behavior. In EPiServer.dll, I found the following place which outputs text similar to what is output:
AccessDeniedDelegateHandler.cs
, method BrowserLogonAccessDenied(object sender)
:
internal static void BrowserLogonAccessDenied(object sender)
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Status = "401 Unauthorized";
HttpContext.Current.Response.Write("Access denied.");
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
This code is called from the following two places, as far as I can see:
EPiServer.Global
, method protected virtual void HandleAccessDenied()
EPiServer.PageBase
, method public virtual void AccessDenied()
I have tried to override HandleAccessDenied
in Global.asax
, and override AccessDenied
in my page template. However, the "Access denied" text is still output. It looks as if the override of AcccessDenied
in my page template is firing, however, the override of HandleAccessDenied
does not seem to fire.
Any hints on what could be wrong here?
Found the problem. I tried overriding the AccessDenied
method of PageBase
, however, I did the same "mistake" as the default implementation, namely to flush the response stream:
public override void AccessDenied()
{
Response.StatusCode = (int)HttpStatusCode.Unauthorized;
Response.Flush(); // <- This was the problem
Response.End();
// The rest is handled by WIF when we send a HTTP 401, think nothing more of it..
}
The solution was to simply avoid flushing the response stream. Then WIF handles the rest:
public override void AccessDenied()
{
Response.StatusCode = (int)HttpStatusCode.Unauthorized;
// Removed the flushing of the response
Response.End();
// The rest is handled by WIF when we send a HTTP 401, think nothing more of it..
}
This allows us to use the authorization of EPI to control which users had access to each page.