My goal is to write a cookie when the user authenticates. We are using a crappy framework that hides its source code and event model so when I use their login control I can't set a session timeout on it!
Anyhow, I am trying to write a cookie when the user is logged in, and then refresh the cookie expire time on subsequent page views (sliding expiration).
So I figured I could initially create the cookie during Application_AuthenticateRequest in teh global.asax but that seems to be firing even when the user hasn't signed in yet.
Is that suppose to be the case?
The Application_AuthenticateRequest fires on each request, but if you are using forms authentication and the user haven't logged in yet, you will find that the User property of the HttpContext (accessed through this.User in the global application class file) evaluates to null, while it will evaluate to an IPrincipal object if the user is logged in.
So you can do something like this:
Private Sub Application_AuthenticateRequest(ByVal pObjSender As Object, ByVal pEaDummy As EventArgs)
If Me.User IsNot Nothing AndAlso Me.User.Identity.IsAuthenticated Then
If Me.Request.Cookies("authCookieName") Is Nothing Then
' Create cookie
Else
' Update cookie
End If
End If
End Sub
where authCookieName is the cookie name.
Yes. The Application_AuthenticateRequest will occur everytime a request hits the website. The AuthenticateRequest as well as doing the authentication will also check and return if Authorisation is to happen for the page. Some pages need to be excluded from authentication and authorisation checks, such as the login page.
For your situation you should also check the page and exclude those that are involved in the login sequence.
Related
I have a website using ASP.net ... I use the ASP.net website administration tool accessed from Visual Web Developer to add/modify user access to the site. I've noticed that if the user has checked the "remember me" box to auto log in, then disabling or deleting the account has no effect until the cookie is removed. Why is this? Can there be some type of logic put in the code behind that will deny access or redirect them to an error message for disabled or deleted accounts?
This is currently what I have in my code behind...
Protected Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init
If User.Identity.IsAuthenticated Then
Response.Redirect("~/homepage")
End If
End Sub
Also this is below the Page_Init section...
Protected Sub LoginUser_LoginError(sender As Object, e As System.EventArgs) Handles LoginUser.LoginError
LoginUser.FailureText = "Invalid Username or Password - Please Try Again"
Dim usrInfo As MembershipUser = Membership.GetUser(LoginUser.UserName)
If usrInfo IsNot Nothing Then
If usrInfo.IsLockedOut Then
LoginUser.FailureText = "Your account has been locked - Contact the system administrator"
ElseIf Not usrInfo.IsApproved Then
LoginUser.FailureText = "Your account is disabled - Contact the system administrator"
End If
End If
End Sub
Thanks for the help!
As you've noticed, IsAuthenticated will return true for a user even after they've been removed. This is because the call only checks the contents of the authentication cookie, which still resides on their system.
One solution to this is to enable role-based security for the site. Using roles means that you can protect sections of your site from certain categories of users, e.g. making the administration pages visible only to a subset of accounts.
This role information is saved in the backing store, not the cookie, so it has to be properly checked every time. It's also deleted when the user is deleted, so your protected pages will be inaccessible to the user as soon as they're removed.
You should still be able to manage all this through the web-based tools, too.
More here:
http://msdn.microsoft.com/en-us/library/5k850zwb.aspx
The solution is simple: in global.asax.cs, implement session_start and sign out the user if it does not exist in the database:
protected void Session_Start()
{
if (User.Identity.IsAuthenticated
&& // !(user exists in the database)
)
{
// Remove this forms-authentication cookie, and redirect to sign in without processing this request any further.
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
}
}
When the user uses the "remember Me" option in the login control, it obviously stores a cookie somewhere and the log in gets automated.
Unfortunately I use the login controls "Logged In" event to set up other objects. When the user goes in with the Remember Me function they can bypass this event.
Is there another event i cat catch?
Failing that, is there a safe way to query the membership system to see who is logged in at any time? then i can test myself.
Thanks
You can work with User.Identity.Name
if (Request.Cookies["myCookie"] != null)
{
HttpCookie cookie = Request.Cookies.Get("myCookie");
String UserName = cookie.Values["username"];
this.Login1.RememberMeSet = !(String.IsNullOrEmpty(UserName));
}
I think you can create an HTTP Handler or use Application Events to check if user is authenticated and set up other objects
I don't think you can find any other membership event after LoggedIn , however you can get events from Page Life Cycle.
I suppose you must be redirecting to some default page after successful log in. You can try following code to get the loggedin user name if login was success.
User.Identity.Name
I have a web application using cookieless forms authentication. Every day my event log has a ton of 4005 error codes (Forms authentication failed for the request). I believe this is happening because users are bookmarking pages while they are logged in so when they revisit the forms ticket in the url has expired, atleast this is the only scenario I can trigger in testing.
My question is it possible to disable logging for this 4005 code ? its filling up my event log
You can handle the error so it does not appear in the log
'in global.asax
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when an unhandled error occurs
Dim lastError As Exception = Server.GetLastError()
' Must be a better way, just can remember how, you will get the idea.
If lastError.Message.Contains("Forms authentication failed for the request") Then
'do nothing
Server.ClearError()
End If
End Sub
If you can use cookies, its a much better solution than cookieless mode because your users will get to use bookmarks, which they'd surely expect to be able to do, and your error log will not be filled with errors. Its also less vulnerable to session hijacking.
Not an answer to your question, and I'm not even familiar with ASP. But if, just like for example PHPSESSID and jsessionid, this "forms ticket in the url" is actually a session id that is also added to the URL for anonymous visitors, then maybe search engines can cause this error as well? And if so: doesn't that break your search scores?
which event is the most suitable to check for Session expired? i'm trying to trap each server request, and if Session is null, redirect to a different page.
You can determine if a new session is being created by hooking Session_OnStart - http://msdn.microsoft.com/en-us/library/ms178583(VS.80).aspx
You can handle the Session_OnStart
event by adding a subroutine named
Session_OnStart to the Global.asax
file. The Session_OnStart subroutine
is run at the beginning of a request
if the request begins a new session. A
new session will be started if a
request is made that does not contain
a SessionID value or if the SessionID
property contained in the request
references a session that has expired.
This will tell you effectively when a new session is being created, regardless of if the user just arrived or the session had expired.
It would be hard to reliably differentiate between both scenarios. I guess you could try to get a hold a the session id in the either the session cookie or embedded in the url (cookieless), but you would need to check it before getting to the above event, and later check whether the request had a session id originally. Check if you can get to the session id in the cookieless version, because it is stripped out of the urls asp.net gives you (not sure if early in the lifecycle you get to see it).
This is often best achieved by using a base Page class for all otehr classes, and implementing this in the Page_Load method.
Use BasePage class, which inherits from Page class. Let every aspx page inherits that BasePage class. In BasePage class, override OnInit event, in which you can check for Session or Cookie, and redirect user to login page (for example).
I use this approach for all mine webforms apps, because it's easy to implement and use.
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:
User clicks HTML hyperlink from Home.aspx which takes them to Logout.aspx
Page_Load event handler of Logout.aspx clears Forms Authentication ticket and Session data and redirects the user to Login.aspx
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?
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 here.</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.
Response.Redirect("login.aspx?from=logout")
Steve Yates
ITS, Inc.
Why doesn't Tarzan have a beard?
~ Taglines by Taglinator: www.srtware.com ~