Dealing with expired authentication for a partially filled form? - asp.net

I have a large webform, and would like to prompt the user to login if their session expires, or have them login when they submit the form. It seems that having them login when they submit the form creates alot of challenges because they get redirected to the login page and then the postback data for the original form submission is lost.
So I'm thinking about how to prompt them to login asynchrounsly when the session expires. So that they stay on the original form page, have a panel appear telling them the session has expired and they need to login, it submits the login asynchronously, the login panel disapears, and the user is still on the original partially filled form and can submit it. Is this easily doable using the existing ASP.NET Membership controls? When they submit the form will I need to worry about the session key? I mean, I am wondering if the session key the form submits will be the original one from before the session expired which won't match the new one generated after logging in again asynchrounously(I still do not understand the details of how ASP.NET tracks authentication/session IDs).
Edit: Yes I am actually concerned about authentication expiration. The user must be authenticated for the submitted data to be considered valid.

Session expiration is different than authentication expiration - you probably need to determine which you are concerned about.
Sessions expire after 20 minutes of inactivity (by default), and will clear the Session object. When it expires, anything you stashed into Session will be gone.
[Forms] Authentication expires after 30 minutes of inactivity (by default) - though it's only updated every half-life. So, in reality - it can expire after 15 minutes of inactivity (by default). When it expires, the next request will be redirected to your login page.
Session and Authentication aren't really related - you can be an anonymous (non-authenticated) user, and still have a Session - or you can be logged-in (authenticated) but not have a Session. Your Session could expire before your authentication does, or vice-versa.
You could simply crank up the values for expiration for Session and/or Authentication. The problem with Session is that it chews server resources, and keeping Authentication is a security problem.
If you're just concerned about keeping them both alive for the duration of your form, a small bit of JavaScript that hits a server page with XmlHttpRequest or an iframe will reset the expiration for both (because of slidingExpiration).
There's other techniques as well, but it'd be helpful to better define the issue first.

Very nice response #Mark Brackett reading the OP's comment below I believe this is his end goal.
On the button / submit element you want to write a javascript method that via ajax will poll the server to see if they are still authenticated.
If they are auth'd still you want to return true and let the form do it's regular submission, if it returns false you want to not allow the form to submit. At this point you will want to use javascript to display either a "window" inside the browser (think floating div) or to pop up a true new window for them to log in (I'd recommend the first method) that this new window will allow them to login via ajax and then hide/close itself.
Then with that window gone when they click the submit button again they will be able to successfully post the form.

There are many ways of doing this: you may store a cookie on the user's computer, or you can also split the form into smaller forms (i.e.: step 1 - enter your personal information, step 2 - enter billing info, etc.).
Splitting your form makes it faster for a user to enter the data, thus reducing the chances for their session to expire.
Adding a cookie to this makes it so that the person's information is still there, even if you log in afterwards. Just make sure to unset these said cookies at the end.

Related

How to stop direct access to Form B unless Form A is completed in ASP.NET MVC?

This question applies to both ASP.NET webforms and MVC apps. I have a checkout process where there are two forms Form A (address page) and Form B (shopping cart page). The normal happy path works where the customer completes the Form A and then click submit button which takes him to the Form B.
The customer can accidently visit the Form B without ever visiting the Form A or completing the information. How can I find out whether the customer has completed the Form A if he access the Form B directly? If he has not completed the Form A, I want to redirect him to Form A. Is there a ASP.NET framework object that I can use for this purpose?
The only foolproof way is to save something to a database that indicates that the particular user has completed Form A. This could be actually storing some entity that is created by Form A or just some sort of log. The key is that you'll need to associate with the user, which means the "user" must actually have an account and be logged in. If it's anonymous, there won't be any real way to track them.
With this set up, then, you'd simply check in your database that the user has a record indicating they've completed Form A in the controller action for Form B. If nothing exists, you redirect the user to Form A. Otherwise, you allow them to view Form B.
And alternate approach is to use Session or set a cookie to indicate that Form A has been completed. There's pros and cons to both of these, and neither is foolproof. With both Session and a cookie you can track anonymous users, so you don't have to force a login. However, Session is not a permanent data store. By default, it will expire after 20 minutes of no activity, and even if you bump that timeout up significantly, it's always going to be finite.
Additionally, depending on the session store you use, it can also be very volatile. In Proc is the default, as it requires no configuration. Everything is stored in memory, but if the server restarts, App Pool recycles, etc. then all the session data is lost. It is possible to configure it to use something like SQL Server, though, and that would be very stable. Either way, you'd still have the timeout issue to deal with.
With cookies, you can set a far-future expires cookie that would effectively be permanent. However, cookies are stored client-side and can be removed by the user. They can also be manipulated (either created manually or modified). This means if a malicious user figured out how you were tracking whether Form A had been completed, they could basically fake that, and make your site think they had completed Form A, when they had actually not. Now, whether any one would care enough to do that is an entirely different matter. Still, it's something to consider.
Finally, both Session and cookies can effectively be disabled by the user. Session actually uses a cookie to store the session id, so if the user disables cookies in their browser, neither approach will then work.
Your best bet is still forcing a login and storing something in a database to indicate that Form A has been completed by that authenticated user. However, if you can deal with or mitigate the downsides of using Session or cookies, then those might be viable options.

log out a user on session expiration

What is the best way to force a user to login again if the session expires. I am using forms authentication. Also the solution needs to work even if user has multiple tabs opened in the browser.
This happens automatically. Once the session is expired, the next page the user requests that requires authentication should redirect to the login page. If you mean that you want the page no longer displayed if left sitting for too long, there are a couple of approaches.
Add a META REFRESH tag to every page header. The refresh time
should be close or equal to the session timeout. Note that if you
make AJAX calls, the refresh tag does not reset the timer to zero.
Use the Javascript setTimeout function to redirect just before the
session timeout.

Kill Asp.Net session when the browser or tab is closed

I am using forms authentication with Asp.Net 4. At the moment when the users click on logout link, I clear the session and call FormsAuthentication.SignOut() and this prevents the users from going back to the site without a logging in again.
Now I want to kill the session when the browser or tab is closed. I tried doing this by handling onbeforeunload event, but I ended up killing the session after clicking any internal links.
Any ideas how I can do this?
You can't, but you can come close to.
The authentication cookies are session only, that means that delete by browser when the browser close. Maybe you do not close all browsers tabs, but if you close them all the authentication cookies are lost.
About closing a tab, you do not know if the user have other tab opens.
A possible solution maybe is a call every 10 seconds back to the server to keep this authentication active or not, and set the authentication to end up after 20 seconds. So if not any signal come back, the user have gone. This can be done using javascript. From the other hand this can not let the user logout after some minutes of inactivity, so you may need a combination of this logic with something else.
The best you can do is when your user explicitly logs out to also call Session.Abandon() to remove that user's session. But like others have said there is no way of knowing if the tab/window just closes without doing a logout in this fashion. The session will just hang around on the server until it expires.
I answered another question that had a problem with session being killed when the user edited the web.config on a live site. They were tracking users still being logged in with Session variables (dangerous). But came up with a solution (untested solution) that could help people here.
FormsAuthentication allows you to maintain a person being active and logged in indefinitely. But if they become inactive for e.g. 20 mins they will be logged out which is nice. But to have them logged out at the time the close their browser is not possible (wait for it...) as setting the timeout value to 0 would cause them to be constantly logged in then out again.
So solution : at the time you log a person in using FormsAuthentication you could also set a standard session variable cookie that will be deleted when they close their browser. This cookie would have non-identifying non-account related information. Just a simple "loggedIn:yes".
Now all your code would need to have on it's masterpage/materlayout is a high level call in the page cycle or constructor of the page cycle (or even a custom attribute) that would check both cookie and the user identity:
if(!HasLoginCookie() || !System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
{
// redirect user to log in page.
}
Basically if the cookie is removed when the browser is closed, you will redirect the user to the log in page.
Hopefully that helps (and works. As I said untested).

How to tackle this session problem in ASP.NET,VB.NET?

How to tackle this session problem in ASP.NET,VB.NET?
The following requirement are there:
When the authorized user logs into the system that user is not allowed to login from another computer or in different browser other than that user is using right at this time.
The remedy we applied was: We have kept "Is_Loggedin" as a column with data type "bit" in a mst_vendor as a table name. When a user logs in we set the flag, Is_Loggedin, to "1" and each time when someone tries to log in using this account, the system is showing the error "The user is already logged in.".
When the user logs out it turns to "0" as the logout procedure calls as soon as the user clicks the log out button.
Problem scenario:
When the user closes the browser the flag remains the same, that is, "1".
When power gets off, it remains the same as "1".
If the session timeouts after a predefined value it remains the same.
There may be different scenarios other than this.
Is there any way so that we can store this internal flagging for the user's login status using the application object?
It may improve efficiency of the system and also eliminates the above problematic scenarios.
You should use the Global.asax file and use the Session_End function.
Session_End: Fired when a user's session times out, ends, or they leave the application Web site.
Store a datetime as another column next to the bit, and update it each and every time the user requests a page.
When a new user comes along with the same credentials and the bit is "1" you can check the datetime, and if it was a while ago you can be certain the user is no longer there. So let the login go ahead.
You could keep a pulse going in script, and when the pulse times out, consider the user finished with that session.
The benefit to this is that you can tell the difference between the user sitting idle on the site and the user leaving the site.
From a very top level view, here is what you can do
Use Cache with SlidingExpiration.
Everytime a user attempts login, check the cache with his username as the key. If an entry exists in the cache, you can say that user is already logged in and deny login.
If the key is not found, allow login and create a new key in the cache as the username and set the sliding expiration time. (This should be carefully chosen as this would be the duration, the user wouldnt be locked out after the browser is closed and user attempts to relogin.)
In the Application_PreRequestHandlerExecute handler in Global, check if the user is currently active (you can use sessions for this), reset the sliding expiration time for the user. This way, with each page request the cache expiration time would be reset.
If the user closes the browser and moves off, the cache would expire after the set period of time, and would free the user to log in again.
if in case the user attempts to login again before the cache expires, the user would have to wait for some time to let the cache expire.
if the user logs off properly, you can remove the cache entry on the logoff event such that user doesnt have to wait to relogin.
The Sliding expiration timeout can be synced with session timeout to emulate the actual session timeout for the application.
With this approach, you would also save on a lot of database round trips to update/check the user status and this would work irrespective of the hosting enviornment or the session modes.
Yeah, a script would be a good idea. Just set the session timeout to be 5 minutes instead of 20 and then write a method into session.end in the global.asax file that updates the database accordingly.

Multiple log-in problem

We have a web application with feature for logging in with credientials
The important requirement is once the user logs in he is not allowed to login from any other system or even another browser on same system
We used following solution which is mssql based : We have kept " Is_Loggedin" as a column with data type "bit" in a table. when a user logs in we set the flag as "1" sowhen someone tries to log again ,the system is showing the error "The user is already logged in"
When user logsout bit turns to "0"indicating user logged out.
However this logic is failing in following scenarios
Problem scenario:
When user closes the browser the flag is "1"and user is locked in or situations when user gets system problem and unable to log out
Is there a better logic to handle this requirement?
While the user is logged in, you could have a AJAX call that pings the server every 30 seconds that the user is logged in. Have a column Is_LoggedIn, and Last_LoggedIn for the date/time when they last sent that AJAX call. If it has been more than, say 1 minute, allow the user to login from another system.
You will also have a problem scenario if the user leaves their browser open for more than the session timeout period, usually 20 minutes. Then they will get logged out on the next request, but not be able to login again because of that is_LoggedIn set to 1. You would be better off doing some sort of time-based solution because keeping track of whether the user is still actively using a website is a very difficult problem because of the many ways they can leave the website without actually logging out.
If it is absolutely critical to avoid any chance of the user being logged in multiple places, you could also force all other places to logout automatically when the user logs into some new place.
You can update 'Is_Loggedin' flag to 0 at session_end event of global.asax.
session_end event is always call. session _end event call when session_timeout is expire.
in the global.asax code behind I believe there is an even for session end. You could tie into that method and set the user's Is_LoggedIn flag to 0. You would then also need to tie a user to a session key to be able to track a user's session.
Edit:
Also, the use of a session cookie or a normal cookie may help if the user closes their browser. The cookie would authenticate them upon re-opening the browser window; however this has a potential security hole if the user is using a public computer.
You could be to log the user out after sometime of inactivity (say 30 minutes). This way if the user closes the browser without logging out he will be able to log in again after 30 minutes.
Use Session_End as Pankaj suggest to make sure that the user's bit is set to 0 when logging out.
The issue with system failures is another problem. Maybe this could do the trick: When the user log in, the store the user's session ID in the database. When the user logs out, then clear the session ID. Every time the user makes a request you verify that the session ID matches the one stored in the database. If that is not the case, then invalidate the session, so that the user is logged out.
This should happen: If the user signs in, in another browser, the session ID would be updated. If user then goes back to the first browser windows and clicks on something, that session would be invalidated, and the user would be signed out automatically.

Resources