How to get referrer URL in ASP.NET when there are multiple redirects

asp.netforms-authenticationsingle-sign-on

I'm developing a web application that uses an in-house SSO server for authentication. I have a link on my home page to a page called Logout.aspx. Logout.aspx clears the Forms Authentication cookie, all session data, then performs a redirect to the LoginUrl specified in the forms authentication configuration which is currently set to a page called Login.aspx.

However when Login.aspx loads, an attempt is made to implicitly reauthenticate the user against the SSO server using the SSO authentication ticket which was previously issued. If this ticket still exists, the previous user will be logged back in and sent back to the home page. I want to determine, when the Login page loads, whether the request has come via the Logout page. The UrlReferrer property of the request still references Home.aspx, presumably because this was the last url the client requested.

Currently I have a workaround in place whereby I append a querystring variable to the request from the logout page that instructs the Login page not to perform an implicit login and instead prompt the user for credentials. How can I determine programmatically whether the request came via a redirect from the Logout page?

Edit 29/04/2009:

Following the conversation with jellomonkey, I should point out that the interaction between the SSO server and the local forms authentication of the consuming website isn't directly relevant to the problem at hand. Expressed succinctly, my problem is:

  1. User clicks HTML hyperlink from Home.aspx which takes them to Logout.aspx
  2. Page_Load event handler of Logout.aspx clears Forms Authentication ticket and Session data and redirects the user to Login.aspx
  3. Page_Load event of Login.aspx checks the UrlReferrer property of the Request object to determine whether the request came via the Logout page. However, in requests which have come via a redirect from Logout.aspx, the UrlReferrer property of the Request object is Home.aspx.

Why is this? Why is the UrlReferrer Home.aspx and not Logout.aspx?

Best Answer

The scenario you are describing should be working correctly unless the logout page is not actually deleting the forms authentication cookie. There are several ways to end the forms authentication session:

//I have seen instances where this does not work.
FormsAuthentication.SignOut()  


//I have not seen this code fail before.
Dim cookie As HttpCookie = FormsAuthentication.GetAuthCookie( _
    HttpContext.Current.User.Identity.Name, False)
cookie.Expires = Date.Now.AddDays(-1)


Response.Clear()
Response.AppendCookie(cookie)
Response.Redirect(FormsAuthentication.LoginUrl)

Also if you are using a role manager which stores in a cookie remember to call Roles.DeleteCookie().

Edit: In response to the updated question.

The Response.Redirect method does not return a header with a new URL referrer because the spec says that only client initiated requests should contain a referrer header. Here is the Response.Redirect code which you can see does not change the referrer header:

Public Sub Redirect(ByVal url As String, ByVal endResponse As Boolean)
If (url Is Nothing) Then
    Throw New ArgumentNullException("url")
End If
If (url.IndexOf(ChrW(10)) >= 0) Then
    Throw New ArgumentException(SR.GetString("Cannot_redirect_to_newline"))
End If
If Me._headersWritten Then
    Throw New HttpException(SR.GetString("Cannot_redirect_after_headers_sent"))
End If
Dim handler As Page = TryCast(Me._context.Handler,Page)
If ((Not handler Is Nothing) AndAlso handler.IsCallback) Then
    Throw New ApplicationException(SR.GetString("Redirect_not_allowed_in_callback"))
End If
url = Me.ApplyRedirectQueryStringIfRequired(url)
url = Me.ApplyAppPathModifier(url)
url = Me.ConvertToFullyQualifiedRedirectUrlIfRequired(url)
url = Me.UrlEncodeRedirect(url)
Me.Clear
If (((Not handler Is Nothing) AndAlso handler.IsPostBack) AndAlso (handler.SmartNavigation AndAlso (Me.Request.Item("__smartNavPostBack") = "true"))) Then
    Me.Write("<BODY><ASP_SMARTNAV_RDIR url=""")
    Me.Write(HttpUtility.HtmlEncode(url))
    Me.Write("""></ASP_SMARTNAV_RDIR>")
    Me.Write("</BODY>")
Else
    Me.StatusCode = &H12E
    Me.RedirectLocation = url
    If ((url.StartsWith("http:", StringComparison.OrdinalIgnoreCase) OrElse url.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) OrElse ((url.StartsWith("ftp:", StringComparison.OrdinalIgnoreCase) OrElse url.StartsWith("file:", StringComparison.OrdinalIgnoreCase)) OrElse url.StartsWith("news:", StringComparison.OrdinalIgnoreCase))) Then
        url = HttpUtility.HtmlAttributeEncode(url)
    Else
        url = HttpUtility.HtmlAttributeEncode(HttpUtility.UrlEncode(url))
    End If
    Me.Write("<html><head><title>Object moved</title></head><body>" & ChrW(13) & ChrW(10))
    Me.Write(("<h2>Object moved to <a href=""" & url & """>here</a>.</h2>" & ChrW(13) & ChrW(10)))
    Me.Write("</body></html>" & ChrW(13) & ChrW(10))
End If
Me._isRequestBeingRedirected = True
If endResponse Then
    Me.End
End If
End Sub

You can use reflector to follow the other methods but I don't see one which changes any header.