We have an internal system where users can authenticate using Windows authentication but we want to include some custom content in the 401 repsonse that takes the user to a custom username/password authentication page if the cancel off the Windows authentication dialog.
When an unauthenticated user accesses a page, Windows authentication responds with a 401 Unauthorized response, with the headers
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
This prompts the browser to show a dialog asking for Windows credentials. If the user enters their credentials, there is another handshake request-response, and then the user is authenticated and the requested page is shown.
If the user cancels the dialog, the browser displays the content of the original 401 Unauthorized reponse. We use Application_EndRequest in the Global.asax to return some custom content here which takes the user to our custom login system.
/// <summary>
/// If we are about to send the NTLM authenticate headers, include this content. Then, if the user cancels off the
/// windows auth dialog, they will be presented with this page and redirected to the username / password login screen
/// </summary>
void Application_EndRequest(object sender, EventArgs e)
{
Logger.DebugFormat("in Application_EndRequest. Response.StatusCode: {0}", Response.StatusCode);
if (Response.StatusCode == 401)
{
Response.ContentType = "text/html";
var redirectUrl = string.Format("https://mycompany.com/SSO/Login?encryptedSessionRequestId={1}",
HttpUtility.UrlEncode(Request.QueryString["encryptedSessionRequestId"]));
var text = File.ReadAllText(Server.MapPath("~/UnauthorizedError.html"));
text = text.Replace("[USERNAME_PASSWORD_LOGON_REDIRECT]", redirectUrl);
Response.Write(text);
Logger.Debug("Done writing response");
Response.End();
}
}
UnauthorizedError.html contains the following script which forwards the user on
<script language="javascript" type="text/javascript">
window.location = "[USERNAME_PASSWORD_LOGON_REDIRECT]";
</script>
When running locally in (Win7/IIS7.5), this works great, we use Response.Write() to send our content and the user is able to see it when they cancel the dialog.
But when accessing the site remotely, e.g. when it running in our development environment, although we can see from the logs that Application_EndRequest is being called and our content written to the response, it is overridden at some point and all that reaches the browser is the authentication headers and the text You do not have permission to view this directory or page.
1) How can we prevent this content being overwritten?
2) Where in the pipeline might this be happening?
3) Does anyone have any suggestions of another way to implement this behaviour, e.g. with an HTTP module?
Thanks!
I know this is an old post but I would like to share a solution to this problem.
When altering the response message for remote requests (read: non-localhost) you will need to add the following to your config file:
If you do not allow the response to "pass through" remote clients will get the default
"You do not have permission to view this directory or page"
.I got this info from: https://stackoverflow.com/a/17324195/3310441
I wasted a lot to solve this problem but there isn't direct solution. It because win auth works on iis not site level and you can't control how to auth current request. There is several hacky ways to use redirection on different login pages depending on ip.