views:

2772

answers:

2

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?

+3  A: 

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.

jellomonkey
The Forms Authentication cookie is being cleared. This isn't the issue. The issue is: how to determine whether a request for the login page came via a request for the logout page? The user clicks a link on Home.aspx. This takes them to Logout.aspx. Logout.aspx clears the forms authentication cookie and session date, then redirects to Login.aspx. However the UrlReferrer property of the request to Login.aspx references Home.aspx, not Logout.aspx. I want to know if the request came via Logout.aspx so I don't do a 'soft' login via the SSO server and instead prompt the user for credentials.
pmarflee
The referring URL is in HttpContext.Current.Request.UrlReferrer but you already said that it was showing Home.aspx. The only way I could imagine this happening is if your Logout link was actually an asp HyperLink control which fired an event with a Server.Transfer to the logout page and then a Server.Transfer to the login page.That said, the only way a 'soft' login can occur is if the forms authentication cookie is not being cleared properly.
jellomonkey
The logout link is just a regular hyperlink tag; there's no code attached to it. The method by which the 'soft' login is performed isn't really relevent to the problem. The logout page performs a Response.Redirect, not a Server.Transfer.
pmarflee
Am I not reading the question correctly. You have a logout link that sends the user to a logout page which sends the user to a login page which automatically logs them in and sends them to the home page. If you want to prompt for credentials you need the user to be logged out, so the 'soft' login is the root of your problem. You can force the login page to not redirect the user when they come from the logout page but this isn't security, its a work around that looks like security. If I am not understanding you please edit your post with some code and further clarification.
jellomonkey
Question updated. Hopefully I've explained my problem more clearly.
pmarflee
+1  A: 

Response.Redirect("login.aspx?from=logout")

  • Steve Yates
  • ITS, Inc.
  • Why doesn't Tarzan have a beard?

~ Taglines by Taglinator: www.srtware.com ~

Steve