Preserving state after HTTP session time out - asp.net

In my asp.net application, the HTTP session times out after 30 mins on which the user is redirected to a login page. Here is a scenario:
User clicks on an item to edit, with the URL like so:
http://localhost/app/edit?id=1
User makes certain changes on a page to edit item with id=1 but does not "save" them for 30 minutes.
On the 31st minute he clicks on save and he's redirected to the login page where I have a return URL to redirect to, if he enters the correct credentials.
What is correct way of preserving the state in which the user left the page?
All I have is the return URL which coming in with the login request which looks like: http://localhost/app/edit.
Clicking on save does a POST request but does not pass anything in the query string.
I want to be able to redirect to http://localhost/app/edit?id=1

Unless you have specifically built a mechanism to preserve state outside the ASP.NET session-based state mechanism, session is lost when it times out. You could, theoretically, construct a state system that stores intermediate drafts of data from selected pages/inputs on a per-userID basis, where pages containing data likely to be "orphaned" in this way could be somewhat retrieved, but that would also require periodic background saves of data back to the database on those pages deemed important enough to preserve changes otherwise lost due to timeout.

When the POST happens, you have the original URL, and the request object with all of the form values.
The request will be intercepted, and redirected to the login screen. At that point, you need to save the original URL and request values, handle the login, and then redirect to the original URL with the original values.
What does your POST request look like? Is there an object you could stuff into temporary storage (session, etc) or do you process the form collection?

Related

Push into browser's history via HTTP headers

I need to make the client to navigate through a series of redirects. After the user arrives to the destination, I'd like to allow the user to go back to an intermediate page to be redirected elsewhere.
For example, take the following diagram:
Current Page -> Processing Page -> Landing Page
Status: 3XX
|
V
Alternative Page
Disclaimer: I do not have control over Landing Page but I do have control over the others.
From the Current Page, the user is sent to the Processing Page which, after checking the DB, redirects the user to the Landing Page. What I would like is, if the user presses the back button, to be sent back to the Processing Page so it can redirect the user to the Alternative Page.
The problem is that, because of the 3XX status code, the Processing Page is never injected into the browser's history so when the users goes back, they are sent to the Current Page directly.
So far, I've achieved my goal by making Processing Page to return 200 and force a redirect via JS as the first thing but it feels like a clunky solution.
Would it be possible to achieve the same outcome with a combination of HTTP headers? Another solution, since I have control over Current Page is to place the decision making algorithm there but this is a complex enough page already that I'd rather prefer to avoid this option.
Many thanks!

Should Session be checked on Page Load in ASP.Net?

Page Load, as a sentence of 2 words, means when the page is loaded, means, when all elements are loaded.
Let's say I have a page called Ask.aspx, and this page is only allowed to users who have signed in, so technically I would write something like this :
if(Session["id"]==null)
Response.Redirect("Login.aspx");
This mean, that I'm testing the Session AFTER the page loads, theoretically, I think it sounds wrong, now of course I won't notice it, it will be fast, I will try to access the page, then I'm redirected to Login.aspx, but... is it correct to test the Session on Page Load method?
The Page_Load is part of the page lifecycle. It is called when the Server loads the page, not when the Client loads the page...
So this is the correct place to check the Session Variable...
You're actually saying: Before I post the page back to the client, check if I have the ID property set for this session... If I don't - tell the client to redirect to the Login.aspx page...
This is the correct way of doing this...
I recommened you also read about Server.Transfer. The difference between it and Response.Redirect is that in Server.Transfer the server itself "redirects" to another page and outputs the result of the new page back to the client (without the client knowing about it).
If you are trying to limit access to specific pages, you would be better off using forms authentication.
http://support.microsoft.com/kb/301240
It is fairly easy to setup and it allows checking of credentials before the request is passed to the asp.net pipeline. In what you are doing, your page goes through the entire lifecycle (controls are rendred and bound to data, access to database, calls to web services etc.) before the request is rejected. Depending on your situation, this might be costly and will not scale well.
Edit: You can also hook in to the AcquireRequestState event in the global.asax. This will also spare the entire page life cycle.

How to know if the current Servlet request is the result of a redirect?

Is there a way to know if the request has been redirected or forwarded in the doGet method of a Servlet?
In my application, when a user (whose session has timed out) clicks on a file download link, they're shown the login page, which is good. When they login, they are immediately sent the file they requested, without updating the page they see, which is bad. Basically, they get stuck on the login screen (a refresh is required).
What I want to do is interrupt this and simply redirect to the page with the link, when a file is requested as a result of a redirect.
Perhaps there are better ways to solve this?
The redirect happens client-side. The browser is instructed by the previous request to send a new request, so to the server it does not make a difference. The Referer header might contain some useful information, but it's not certain.
When redirecting you can append some parameter, like ?targetPage=dowloadpage and then check if the parameter exists. You may have to put this in a hidden field on the login page if you want it to be transferred through multiple pages.
If you're using container managed authentication, then I don't believe you can detect this since the server will only involve your resource once authentication has been completed successfully.
If you're managing authentication differently, please explain.

Prevent multiple users on a page at a time

What whould be the best way to prevent multiple users on a page?
For example if a user is at the page "Home.aspx", no other users should be allowed to go there.
I'm using asp.net on the server and the js-frameword jQuery on the client side.
The easy part is only allowing one user to access a page. You can for example store a session id in an application variable to keep track of who's on the page.
The hard part is to know when the user leaves the page. The HTTP protocol only handles requests, so the server only knows when a user enters the page. There is no concept of "being on" a page in the protocol.
You can use the onunload event in client code to catch when a user goes somewhere else, however this will not always work. If the user loses the internet connection, there is no way to communicate back to the server that the user leaves the page. If the browser or computer crashes, there will naturally be no onunload event.
You can keep requesting data from the server, by for example reloading an image on the page. That way the server can know if the user is still on the page at certain intervals. However, if the user loses the internet connection, the server will think that the user has left, while the user thinks that he/she is still on the page.
Another problem is browser history and cache. A user might leave the page, then go back to the page again. You have to make sure that the page is not cached, or the browser will just use the cached page and the server has no idea that the user thinks that he/she is on the page again.
Agreed with Guffa, you cannot be sure that the browser is already on the page or not, you can only check if the browser is already connected to that page or not.
You can do a sort of "ping", but its more a trick than a 100% working solution and it requires javascript enabled.
I didn't do it but I should look at XMLHTTPRequest and onreadystatechange to handle this :
1) On page load, the browser (client) initiate a XMLHTTPRequest with the web site (server) then wait for callback with the onreadystatechange event.
2) The web site receive the request and "mark" the page as "in use" with the current DateTime.Now.
3) Then the web site sends the response.
4) The onreadystatechange event get the response and the event code re-request the server to re-initiate the 2 after 1 min.
5) If another client request the page, the server check the DateTime mark : if the mark is greater than 1min ago, it means the client didnt respond to the request and may not be on the page again.
Not sure why you would want to do this because it flies in the face of web usability. You could do a locking mechanism on each page in server side code (write user name, page and time to a DB), which is freed up when they go to another page. You would then check on a the page load event to find out if anyone currently has that page locked. However, and this is a big however - have you considered what happens if somebody just shuts their browser down or walks off and leaves it on a page. You would need to seriously consider a timeout to free up locks too. That would need to be a back ground service, either in global.asax as global code or a separate process.
Maybe use static variables to hold the ip of the first user to access the page and then check whether other requests come from the same ip, otherwise display a "no access" page.
make sure you use lock it:
Object thisLock = new Object();
lock (thisLock)
{
// access static variables
}
You should also use "Session_End" method in global.asax to remove the ip address in case the user leaves your website without pressing the logout button

Time sensitive webpage access

Is it possible to create a page that redirects to a private page if a correct time sensitive variable is passed?
Ex:
http://www.mysite.com/redirectpage.aspx?code=0912042400
The code value is a year-month-day-time combination that must fall withing some time window (15 min, 30 min etc) based on the server's time.
The redirectpage would parse the code and would redirect to a private page (using an obfuscated url with the code variable) if the code is valid or show a 404.
Usage scenario:
Party A wishes to show party B a private page.
A sends a link to B with a code that is valid for the next 30 minutes.
B clicks the link and is redirected to a private page.
After 31 minutes clicking the link produces a 404 and a refresh/postback of the private page also produces a 404.
Thanks
Yes.
One approach is to concatenate the "valid start time" with a private string known only to the server. Generate a has code (e.g. MD5 hash) based on that concatenated value. Send the "valid start time" and the hash back to the client. They pass both back in to view the page. The server re-combines the "valid start time" with the secret key, recomputes the hash, and ensures it matches the passed-in hash. If it matches, compare the passed-in time to the server time to make sure the redirect is still valid.
There is no need for a database of valid keys and what time range they pertain to with this approach. You can even add the page name for the redirect to the time to make the system completely self-contained.
Server computes:
Hash = md5("2009-12-12 10:30:00" + "MyPage.aspx" + Secret Key)
Send to client:
"2009-12-12 10:30:00" + "MyPage.aspx", Hash
Client later sends to server
"2009-12-12 10:30:00" + "MyPage.aspx", Hash
Server checks
newHash = md5("2009-12-12 10:30:00" + "MyPage.aspx" + Secret Key)
Hash == newHash?
Yes and time within window then redirect, else error.
This is a simple task for a database connected web appliction. The basic algorithm would be to insert a "ticket" into a database table. The ticket would be composed of a random string and a timestamp.
When a request comes in for the page, the script that generates that page can look in the ticket table to see if there is a record that matches the code passed in via the URL argument. If there is a record, the script then checks to see if the timestamp is expired. If so, generate the 404 page. Otherwise show the correct info.
There may be a pre-built content management system module or a caned script that can do this, but I don't know of one myself.
As an example, in ASP.net i would cache a keyvaluepair with the code and the redirect page, and set the cache timeout to 30 mins, just a quick example, but this is very possible.
The one issue you are going to run into here is how easy it would be to simply change the url and view private information.
The approach I would take would be this:
When the private page is generated, make a new record in the database with an encrypted key, that contains the starting availible time, and the starting ending time.
Put this encrypted ID in the URL.
when the person goes to the page, look up the timestamps, make sure they are within range, then redirect them to a 404 page.
One way of doing it is to pass the page an encrypted time-limit as part of the query string. Something like http://www....aspx?timelimit=[encrypted]. Where [encrypted] isn't user editable. You may just need to hash the DateTime somehow.
Yes, you could do it that way. However, encoding the valid date range in the value passed is a security risk.
A better approach would be to generate a random code and store that code in a database along with a date range for when the code is valid.
That way there's less of an opportunity for malicious users to guess valid values.
Do you know ahead of time, when the X minutes will start ? Some sites have promotion codes for specific times (hours,days etc) and if you know it ahead of time you can check if the request from the client is within those times.
If you do not know it ahead of time, this is what I would do.
Make sure that the user given token/code is valid
Create a session object with the code as the session key(you can do that in asp.net, not sure about other programming languages) and the IP (or any unique string as value for that key, if behind a proxy, IP will not work, so generate a GUID and pass it as a secure cookie to the client when sending the response). This will prevent multiple users from accessing the secure resource at the same time (though not sure if this is a part of your requirement)
note down the first request time in the session and DB
You can expire the session after X minutes (Get Session to expire gracefully in ASP.NET) .
For subsequent requests check the validity of the key(cookie) sent by the client (against the server side value) and the request time with the first request time + X minutes, If the Key & time is valid, let him access the resource, if the Key is invalid, tell the used that there is already a session in progress
If the user tries to access it after X minutes, (you know it from the session) send a "your page cannot be served as your X minutes has expired since visiting the page the first time" instead of sending a 404 (404 says the resource was not found and would not convey that the request time was not valid) or log him out

Resources