Classic ASP / End of session redirect - asp-classic

I want to automatically redirect to the login page when the users session has expired.
I have been using the following code in an include file that sits at the top of every page in my application:
Session.Timeout = 60
Response.AddHeader "Refresh", CStr(CInt(Session.Timeout + 1) * 60)
Response.AddHeader "cache-control", "private"
Response.AddHeader "Pragma","No-Cache"
Response.Buffer = True
Response.Expires = 0
Response.ExpiresAbsolute = 0
If Session("accountID") = "" Then
Response.Redirect("http://www.mydomain.com/")
End If
This works but there is very slight bug. Every now and then the page will refresh even though the session is still alive and it seems that it refreshes before the 60 minutes is up!
Can anybody see what the problem is or can you suggest a different method?

Seeing as though you have to do this client side I'd favour JavaScript/jQuery and AJAX over that method. Here's an example of how to do it.
Essentially you just set-up an AJAX call to poll a script which returns (in JSON format) whether the user is logged in or not; if they're not then you can transfer them to another page.
The benefits to this method are that you can poll whenever you want; e.g. every 10 seconds to see whether the user is still logged in rather than having to wait a full hour. It also means that you don't need to state the session time-out figure in your code and so you can leave that to be determined in IIS. Also if the user logged off elsewhere in your system, or your application pool recycled and their session was reset this would detect it fairly quickly.
I notice from your profile that you're a Paparazzi photographer. I'd consider this the DSLR method and the response header method the cheap phone camera method :o.
To build your session checker page create a file called session.asp (in the same folder as your other files to make life simpler). In it put:
<%
Response.ContentType = "application/json"
If Session("LoggedOn") Then
Response.Write "{""loggedOn"": true}"
Else
Response.Write "{""loggedOn"": false}"
End If
%>
If the user is logged in it returns {"loggedOn": true}, if they're not {"loggedOn": false}. This is what we'll use on your other page to poll if they're logged in by calling this page periodically and reading the response.
Now onto your pages which originally had your Response.AddHeader code in. Remove all of your code as this replaces it.
First make sure you have a reference to jQuery on your pages:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
And then put under this line the following:
<script type="text/javascript">
$(document).ready(function() {
var checkLoggedOn = function() {
$.getJSON('session.asp', function(data) {
if (!data.loggedOn)
window.location.replace("http://stackoverflow.com");
});
};
// Call checkLoggedOn every x milliseconds
setInterval(checkLoggedOn, 30000);
});
</script>
All being well, it should work. I set the above to poll every 30 seconds (30000) but you could increase/decrease this to whatever you wanted.
Note I borrowed large parts of the code above from https://stackoverflow.com/a/4928564/171703 and https://stackoverflow.com/a/2709160/171703.
Update:
From the comments below, if you want the user's session to expire after the timeout figure (whether they are keeping their session alive or not) then you could do this.
When the user is logged in, set a new session variable for LoginExpiration:
Session("LoginExpiration") = DateAdd("n", Session.TimeOut, Now())
This takes the current time and adds to it the session timeout figure - giving you the time when their session should be destroyed.
If you now modify your session.asp to the following it takes the LoginExpiration figure and returns that the user is not logged in the event of:
The users session has timed out (IIS application pool reset, or they clicked logoff etc)
The current date/time is greater than the set LoginExpiration time
Which is:
<%
Response.ContentType = "application/json"
LoggedOn = "false"
LoginExpiration = Session("LoginExpiration")
DateNow = Now()
If IsDate(LoginExpiration) Then
If DateNow < LoginExpiration Then
LoggedOn = "true"
End If
End If
Response.Write "{"
Response.Write """loggedOn"": " & LoggedOn & ", "
Response.Write """loginExpiration"": """ & LoginExpiration & """"
Response.Write "}"
%>
I've put the loginExpiration figure into the JSON response so you could work with it client side if you wanted too.

'If the session variable is False or does not exist (IsNull)
'then redirect the user to the unauthorised user page
If Session("accountID") = False or IsNull(Session("accountID")) = True then
'Redirect to unathorised user page
Response.Redirect "pagename.asp"
End If
Place this in an include file that you include in all pages you need protected.
<%#LANGUAGE="VBSCRIPT"%>
<!--#include file="checkmem.asp"-->
<!--#include file="includes/dtdsql.asp" -->
<!--#include file="includes/functions.asp" -->

The ASP Global.asa file may be what you're looking for. It allows you to run code at certain events, such as Session start and end. See https://www.w3schools.com/asp/asp_globalasa.asp for more info, but I believe the following will work:
Global.asa
<script language="vbscript" runat="server">
sub Session_OnEnd
Response.Redirect("http://www.example.com/")
end sub
</script>

Related

Server Sent Event and ASP Classic (with Javascript)

So I'm trying to implement some server side event in ASP Classic. This is because I can't do push notifications with ASP Classic. It consists of a Javascript and ASP code. The idea is to send a notice in the form of a sound when you have a new message.
ASP Code in a file named "poller.asp". It polls the private messages and if a new message is found, it executes this code. The code is basically the 'event' that makes up the server event.
Response.ContentType = "text/event-stream"
Response.Expires = -1
response.write ("retry: 10000") & vbcrlf
Response.Write("data: New Mail" & vbCrLf & vbCrLf )
Response.Flush()
and the Javascript:
<!DOCTYPE html>
<html><body>
<div id="result"></div>
<script src="/poller/audio-fx.js"></script>
<script>
var pool = AudioFX('/poller/alert',
{ formats: ['mp3'], volume: 0.8, autoplay: false });
if (!!window.EventSource) {
var source = new EventSource("/poller/poller.asp");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data + "<br>";
pool.play();
}
}
</script>
</body>
</html>
So this code WORKS in that it receives a message when a new private message is detected. It reads it from the stream (poller.asp). There are two issues however:
1) This only works if a new message exists from the time the script is run. If there's no new messages, the stream seems to close. Let's say there are no new messages, then someone sends me one, nothing happens. If there is a new message when I run the script, it works, but if I delete it and receive another one, it also doesn't notify me. I suspect this is something to do with the stream closing.
2) You will notice the Audio-FX. JS and the pool.play. This plays a short mp3 "You have a new message". The issue is that it fails on the first two tries. Say I have a new message waiting. It will say "New Mail" as per the
document.getElementById("result").innerHTML += event.data + ""
but only after doing so twice, will it play the audio. I think maybe it's a buffering issue. As it plays every time thereafter.
Any help would be appreciated :)

Session timed out when POST/GET. Allow login, then post data

Classic asp.
Sometimes the session has timed out while the user has filled out a large form.
Currently the user just gets "you are not logged in", and the login-form.
When the user logs in again, (s)he have to start over, and navigate to the previous form to fill it out again.
I'd like to just submit the formdata again, if the user logs in successfully.
There a many forms/pages in the system, so the login-check is in a common include-file.
Hi Leif Session time is for Server to control the data keeping time , maybe you can use cookie for your issue because it is controlled by Client(Browser). hopefully my idea can help you ,thanks willie
Classic ASP, our "One Way" posting code.
I set a cookie and save the cookie to the members table.
The cookie doesn't need to be anything fancy, date, name, IP, session works just fine. Encode them SHA256 with a Salt.
The idea is to use this special cookie if on a forms page and their user session has been lost or timed out.
Basic setup: (Not complete code just enough to get the idea and flow)
Login page.
Create SHA256 Hash
Save as Cookie
SetKeysCookie "CookieName","LostSession",strSHA256Hash,mysite.ext,"1"
Sub SetKeysCookie(strCookieName,strCookieKey,strCookieValue,strCookieDomain,strCookieExpires)
Response.Cookies(strCookieName).Expires = DateAdd("d",strCookieExpires, Now())
Response.Cookies(strCookieName).Domain = strCookieDomain
Response.Cookies(strCookieName).Path = "/"
Response.Cookies(strCookieName)(strCookieKey) = strCookieValue
Response.Cookies(strCookieName).Secure = True
End Sub
Optional: I use the HTTP_Cookie which would be as follows.
Sub SetKeysCookieHttpOnly(strCookieName,strCookieKey,strCookieValue,strCookieDomain,strCookieExpires)
strGMTDateRFC22 = CookieServerUTC("d","&strCookieExpires&",5,"GMT") ' 1 Day set in char enc dec page
Response.AddHeader "Set-Cookie", strCookieName & "=" & strCookieKey & "=" & strCookieValue & "; expires=" & strGMTDateRFC22 & "; domain="& strCookieDomain &"; path=/;"
End Sub
Update members database:
UPDATE Member SET LostSession='"&strSHA256Hash&"' WHERE ID = "&id&"" .....
On forms page:
Check Session on Post... If Session = NULL then
Check if Cookie is set.
Get the cookie
Old method: Request.Cookies("CookieName")("LostSession")
New HTTP_Cookie
strCookieX = Request.ServerVariables("HTTP_COOKIE")
If InStr(strCookieX,"LostSession=") Then
j = InStrRev(strCookieX, "LostSession=")
if j > 0 Then
strCookieTEMP = Mid(strCookieX, j+12)
end if
j = 64
if j > 0 Then
strCookieTEMP = Left(strCookieTEMP, j-0)
End If
strCookie = strCookieTEMP
End If
The above will pull all your HTTP cookies and then search for your LostSession cookie.
Because we know the fixed length we can pull it cleanly.
Next on the form we check to see which member this cookie is assigned to.
strSQL = "SELECT TOP 1 "
strSQL = strSQL & " ID,Email,ClientID,LostSession"
strSQL = strSQL & " FROM Members "
strSQL = strSQL & " WHERE LostSession = '"&strCookie&"' "
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open strSQL,Conn,3,3
If rs.EOF=False Then
Session("id") = rs("ID")
End If
rs.Close
Set rs = Nothing
When found, we set the minimum Session Variables to allow this post to complete.
Session("id") or Session("authorized") whatever you need to complete the post.
At the end of the post, as we successfully submitted the form we now can send the session failed user to the login page.
Session.Abandon
sRedirectPage = "https://domain.ext/logout.asp"
Response.Status="403.6 IP Restricted"
Response.AddHeader "Location",sRedirectPage
Response.end
You should be able to see the different parts of the http cookie method of saving a session that has timed out.
If you need anything just ask.
Murray
My solution is, in the header file included on all pages, if the user is logged out, create a form with all post and get values hidden, and the username/password field visible.
User then re-enters the username and password, and submits the form.
If the user is then succesfully logged in, the script continues and processes the data.
It will not work for uploads, but this is rarely used anyway.

update Master page label with username without pulling from session

On my site I display a logged in username on the master page (in a label) this is done as below, by pulling the username from the session object and putting it into the label on the master page, page_init page event. My problem is that I am bypassing the session now because of timeout issues i wont bore you all with but now I need to change the code to pop the username into the master page label once, then not try and access the session again as it clears after around 10 minutes due to the IIS pool. I realise i could open a new connection to the database each time the master page loaded to retrieve the user name but I thought there might be an easier way than that. any help would be really appreciated.
Protected Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init
txtUserInfo.Text = (Session("name") & " [ " & Session("org") & " ]")
End Sub
For the user name alone Humpy's reply would suffice (assuming the thread principal/identity is populated correctly). If you need more bits of information you could use cookies:
After login, set the cookie with a reasonable expiration:
Response.Cookies["userInfo"]["name"] = "currentUsername";
Response.Cookies["userInfo"]["org"] = "currentOrg";
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);
On subsequent requests you can pull the data out of the cookie:
if(Request.Cookies["userInfo"] != null)
{
HttpCookie c = Request.Cookies["userInfo"];
txtUserInfo.Text = Server.HtmlEncode(c["name"]) & " [" & Server.HtmlEncode(c["org"]) & "]";
}
See here for more details: http://msdn.microsoft.com/en-us/library/ms178194.ASPX
You should be able to use..
txtUserInfo.Text = User.Identity.Name;
This is how I use mine. Once the user logs in, displays the user's names perfectly. Hope this helps!

How to Make Very Simple ASP.Net Password Protected Page

I am looking for a very simple solution to password protect an ASP.Net page.
I found exactly what I am looking for here but it is in ASP and I do not know the syntax to convert it to ASP.Net.
It simply creates a temporary cookie that will expire as soon as they close their browser window.
I am not looking to store the username / password in a db. I will manually change the password occasionally.
Simply helping me convert the following code to ASP.Net would be wonderful!
This goes on the logon.aspx page and pulls values from a form.
Username="Administrator"
Password="Admin"
Validated = "OK"
if Strcomp(Request.Form("User"),Username,1)=0 AND Request.Form("password") = Password then
Response.Cookies("ValidUser") = Validated
If (Request.QueryString("from")<>"") then
Response.Redirect Request.QueryString("from")
else
Response.Redirect "MyPage.aspx"
End if
Else
If Request.Form("User") <> "" then
Response.Write "<h3>Authorization Failed.</h3>" & "<br>" & _ "Please try again.<br> <br>"
End if
End if
This goes on the password protected page to confirm the cookie was created.
Validated = "OK"
if Request.Cookies("ValidUser") <> Validated then
dim s
s = "http://"
s = s & Request.ServerVariables("HTTP_HOST")
s = s & Request.ServerVariables("URL")
if Request.QueryString.Count > 0 THEN
s = s & "?" & Request.QueryString
end if
Response.Redirect "Logon.aspx"
End if
Just use the built-in forms authentication and setup your credentials store in the web.config.
Here's a quick and dirty example
Another example

Get Session to expire gracefully in ASP.NET

I need a way to tell ASP.NET "Kill the current session and start over with a brand new one" before/after a redirect to a page.
Here's what I'm trying to do:
1) Detect when a session is expired in the master page (or Global.asax) of an ASP.NET application.
2) If the session is expired, redirect the user to a page telling them that their session is expired. On this page, it will wait 5 seconds and then redirect the user to the main page of the application, or alternatively they can click a link to get there sooner if they wish.
3) User arrives at main page and begins to use the application again.
Ok, so far I have steps 1 and 2 covered. I have a function that detects session expiry by using the IsNewSession property and the ASP.NET Session ID cookie value. if it detects an expired session it redirects, waits five seconds and then TRIES to go to the main page.
The problem is that when it tries to redirect, it gets to the part in the master page to detect an expired session and it returns true. I've tried calling Session.Abandon(), Session.Clear(), even setting the session to NULL, with no luck.
Someone out there has had to have faced this problem before, so I'm confident in the community to have a good solution. Thanks in advance.
The problem you are describing happens because asp.net is reusing the sessionid, if the sessionid still exists in the auth cookie when you call abandon() it will just reuse it, you need to explicitly create a new sessionid afaik something like:
HttpCookie mycookie = new HttpCookie("ASP.NET_SessionId");
mycookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(mycookie);
For ASP.NET MVC this is what I'm doing with an action method.
Note:
Returns a simple view with no other resources that might accidentally re-create a session
I return the current time and session id so you can verify the action completed succcessfully
public ActionResult ExpireSession()
{
string sessionId = Session.SessionID;
Session.Abandon();
return new ContentResult()
{
Content = "Session '" + sessionId + "' abandoned at " + DateTime.Now
};
}
The code in your master page, which detects an expired session and redirects, should look like this:
if (Session != null
&& Session.IsNewSession
&& Request.Cookies["ASP.NET_SessionId"] != null
&& Request.Cookies["ASP.NET_SessionId"].Value != "")
{
Session.Clear();
Response.Redirect(timeoutPageUrl);
}
Calling session.Clear() before redirecting ensures that on the subsequent page, Session.IsNewSession will be false.
Also note that I am checking for an empty string in the value of of the ASP.NET_SessionId cookie. This helps to prevent a logout from being mistaken as an expired session, if you happen to call Session.Abandon() in your logout process. In that case, make sure you expire the old session cookie as a part of the logout process:
Response.Cookies["ASP.NET_SessionId"].Expires = DateTime.MinValue;
The adding the cookie trick worked for me also, as follows:
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when a new session is started
If Session.IsNewSession Then
'If Not IsNothing(Request.Headers("Cookie")) And Request.Headers("Cookie").IndexOf("ASP.NET_SessionId") >= 0 Then
If Not IsNothing(Request.Headers("Cookie")) AndAlso Request.Headers("Cookie").IndexOf("ASP.NET_SessionId") >= 0 Then
'VB code
Dim MyCookie As HttpCookie = New HttpCookie("ASP.NET_SessionId")
MyCookie.Expires = System.DateTime.Now.AddDays(-1)
Response.Cookies.Add(MyCookie)
'C# code
'HttpCookie mycookie = new HttpCookie("ASP.NET_SessionId");
'mycookie.Expires = DateTime.Now.AddDays(-1);
'Response.Cookies.Add(mycookie);
Response.Redirect("/timeout.aspx")
End If
End If
End Sub
Are you calling Session.Abandon in your special "Your session expired" page? If so, don't.

Resources