How to avoid using the same account from multiple machines? - asp.net

Requirement:
A user can login only once per session period. for example, if a user login to the website from two different machines the website will show a message "The account is already in use". That would apply if the user login from two different browsers.
I am working on a web application that uses "InProc" Session. the app do the following:
A- When user login, Put Session_ID, user_ID and IP in a table called Sessions.
B- When Session_End is called, Set the row of Sessions table to be marked InActive.
C- When Application_Start is called, the web app deactivate all Sessions.
First: I don't like this, it causes a deadlock in the database. I can't verify the reason yet.
Second: Is session_end gurantee to run in all cases, I could not find MSDN page says that Session_End is called when App pool is recycled. See http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstatemodule.end.aspx
Do you have a better idea? Does Session_End is called everytime App pool is recycled?
Thanks

I think what you have is conceptually correct, however I don't think you can rely on the session_end event firing, as this will only happen if the user hits your site when their session has expired, rather than just closing the browser.
What you also probably need is a service that runs on a fairly regular basis and removes items from your session table after a certain period has passed (you may want a date field that is updated when a session is created/refreshed).
Don't know where you deadlock is coming from, but am guessing that you're not closing something properly...

Related

Only one user of asp.net web application at time

I have a specific request to allow only one user to use asp.net application at time because of web application nature.
I've tried to implement this by using Application state using some sort of session counter which is incrementing on session_start and decrementing on session_end, but the problem is that session starts immediately when application display login form (because of form authentication).
If first user browser displays login.aspx, session_start in global.asax is called and sessioncounter is increased for 1. SessionCounter now equals 1.
If another user browser also displays login.aspx, before first user is authenticated, session_start in global.asax is called and sessioncounter is increased for 1. SessionCounter now equals 2.
My idea was to authenticate user only if SessionCounter <= 1. But in upper described case we will have a lock becase sessionCounter is already 2 and if first or second user tries to login, it will not be able to authenticate because sessioncounter is greater then 1.
The second problem is when session times out before authentication times out. If first user's session times out, and in that moment second user tries to login second user will succeed to enter application. But what happens if first users makes some postback because his auhentication has not timed out. New session will be started, session_Start event handler will be called, session counter will increase, but user will still be logged on because user is already authenticated.
What is the best approach? Is it possible to avoid Application state because ASP.net 3.5 has known issue of calling session_end immediately after session_Start if session object is not used.
I've thought about using some database flag, but then I'll have another problem. What happens if user closes browser before resetting this flag. I can insert some timestamp when raising flag. Then I'll have following scenario:
First user logs in. DB flag is raised and timestamp is inserted. First user forgets to log out and only closes browser.
Second user tries to log in. DB flag is checked and because it is already raised he can not access application. If I set one more condition to check if some period of time has passed from last inserted timestamp, for example 30 min, I could allow second user to access application regardless of DB flag, but that is not good solution becase I'll have to wait for this period of time.
What is the best solution for this problem? Is there any global variable available in .net framework which allows us to check total online user count (I am not using membership provider)?
You should be able to do this through IIS by limiting the number of connections and adding a custom error page to handle 403.9 (Forbidden - Too Many Users) errors.
Limiting Connections to Manage Resources (IIS 6.0)

MVC2 and Session Start Event

The Setup:
Account controller with the typical logon / logoff stuff that comes baked in from the template. Not much modification here on the logon page. Using a custom membership provider (SQL), but I don't think that is impacting what I am trying to do here.
The Requirements:
The client wants to handle licensing by limiting concurrent users and not by total users. So, after referencing this post here, I set out to make this work for what I need to do. And that is to track maximum and current users for each organization that has signed up for our application. No problem, just have an application("max") and application ("current") which are both hashtables with the key being the organization id and the value being current or max users for the organization. On Session_Start, I would increment the current users, check if it exceeds max and either a) redirect to an error page or b) let them go on with what they need to do. On Session_End, I would decrement the count.
The Problem:
When using formsService.signIn, what is actually stored in session? I cannot seem to gather any information about my session in the session_start except for the session ID. So, I cannot increment the correct number for user tracking. And I cannot add a variable to session as session_start will have already fired before I get the opportunity.
The notion that session is somehow connected with authentication is a myth. They are entirely independent of each other. Session can even be shared between multiple users if they happen to share their session key; that's why you never put security-sensitive info in session. Session can also expire while you're logged in. Likewise, your session is still active after logout unless you explicitly abandon it.
Session is more like a user-specific cache.
So you need to accept this fact and adapt to it. Look and see if the current user is authenticated during session start. You'll need to increment during logon as well, since the session will have already started. Etc.

ASP.NET sessions

I am trying to find out in my asp.net application the users that are currently logged in the application by searching on the session info. Currently, I am only able to see my current session, but I cannot find out if there are other users using it. Is there a way to see if there are other users using the application by looking at the session information
Session state is per user - Application state (global) seems to be what you're looking for.
There are 2 hashes Session and Application, in which you can store key-value pairs.
A way to do it would be to update Application[UserNamesList] whenever there is a successful login. This would then be visible to all users. Application state would however be lost whenever the App Web Server recycles or restarts... but that shouldn't be a problem in this case.
A session is supposed to only give you information about the currently logged-in user.
If you need to keep track of all logged-in users, you could consider writing the users into a global variable. Here is info on how that works. Note that sessions expire. You would have to write, for each user, the time the user was last seen (i.e. each time they hit a new page, update their record). When the time they were last seen is greater than your session timeout, it's safe to assume they are no longer logged in and you can remove them from the list of current users. If they just up and close their browser, you will not be alerted and you will still think they are logged in even though they are not.

How to check if a user is still active?

How do i keep checking if a user still is active, for like every 1 minute? I need to know which user is currently active and who is not! I'm not using ASP.NET membership provider!
Lets say, maximum 3 log in are allowed for one user to log in simultaneously from 3 different locations, if the same user, which is the 4th log in, try to log in from another location again, i would like to block the 4th log in.
I have few issues regarding this as well! If the user unplug the connection cable or close the browser, how do i figure out if the user is still active?
I would need more detail about exactly what you are trying to accomplish, as you have asked a fairly vague question. However, I would think the best way to determine if a user is active is to check if their ASP.NET session is still alive. There is no "accurate" way to test if a user is still browsing your site, because they could be sitting there reading, or be AFK, or be in another program on their computer...dozens, if not hundreds of scenarios could exist on the client side.
However, the user's ASP.NET session will only live for a specific period of time between each activity from the user (GET, POST, etc.) Usually after 20 minutes, ASP.NET will clean up the users session, and when it does, it will fire a Session_End event that can be handled either in Global.asax, or with a custom HttpModule. You would then be able to flag that user as inactive in your own database, send an email, or do whatever it is you need to do.
You can use the HttpResponse.IsClientConnected property to check if the user is still conncted to the session. For details see this -->
http://msdn.microsoft.com/en-us/library/system.web.httpresponse.isclientconnected.aspx
Alternatevely, you can set a counter at Session_OnState at global.asax to check for the active session available and do your stuff based on that.

Event to capture when a formsauthenticated user is un-authenticated

I'm basically looking for the event that is the opposite of FormsAuthentication_OnAuthenticate. I want to remove some values from the database when a user logs out. I tried putting it into the Session_End event, but it seems that the user is already gone by the time this executes.
Update:
If I can't determine when a specific user is deauthenticated (ie, due to session timeout) then is there a way to get a list of all currently authenticated users? If I could, then in the Session_End I could just remove the records from the DB that are not associated with a currently authenticated users.
Session_End isn't guarenteed to fire - if you're not using InProc sessions for example, then it won't fire at all. If your application recycles or dies, again, it won't fire.
Your best bet would be to have this code in a shared method that you can call from numerous places:
In your LoginStatus control you can set the LoggingOut event - call your method there to handle people who log out sensibly.
If you're using InProc sessions, in your Session_End event, but make sure you check to see if they are logged out already (as you've seen).
If you're not using InProc sessions, you'll need to get a little more creative. Perhaps look at having an event that fires every now and then (perhaps on Session_Start which does fire regardless) that goes through and clears out those users who's last active time is older than the session timeout (as mentioned by Greg).
Unforunately the Membership class gives you some useful details, but not all of them:
GetNumberOfUsersOnline
This will "Gets the number of users currently accessing an application." - great, but the only methods that will get users either:
GetAllUsers // Gets all the users from the storage provider (can be paged)
FindUsersByName
FindUsersByEmail
Sadly none of these have a property to only return "active users" as per the count.
Looking at the members of MembershipUser there isn't a "IsOnline" property - only LastLogonDate and LastActivtyDate - due to the disconnected nature of the web, this is probably as good as you're going to get.
I would imagine you have them logging out via the click of a button or link or something like that. Why not just put the code in that same event / block. Near where you put the FormsAuthentication.SignOut() call.
There is a Session_End handler in the Global.asax in which you could put could that you want to execute when the session expires.
I am not sure that this is what you want though. Session and authentication are two different things. If your authentication technique is providing a FormsAuthenticationTicket to the user (inside a cookie) and that ticket has an expiration, well the expiration of the authentication is controlled via this ticket. It will not be actively managed on the server. Each request the user makes the ticket is provided and the server then determines if the user is still authenticated.
Bottom line is, you can detect when the user's session expires, but you probably won't be able to determine when their authentication expires, unless both expiration values are identical.
If you're using the SQL provider, the aspnet_Users table has a "LastActivityDate" column. If you compare that to the timeout value of forms authentication, you could come up with a list of users are definitely not logged in. Your count would be low if they log out manually with a "log out" link.

Resources