MVC2 and Session Start Event - asp.net

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.

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.

Invalidate session of other user

I've made an asp.net site, which uses Session objects to store information for each logged in user. To check if a user is still logged in, I check if a certain object exists in the Session.
The system used Jasig CAS authentication, and the single sign on part works (as in: after the log in, the Session object of the user is set up correctly).
CAS also supports single sign out. The way this happens is that CAS calls a url on my site, with some parameters about the CAS session.
What I need to do now, is invalidate all Session objects for the specified user.
How can I, from a page on my site, invalid the Session object of a random other user? Is there a db I can clear, is it all in memory (I can look at web.config if I know what to look for)?
I've seen this question asked before, and most answers are "keep a global variable next to the Session global variable, and check that one too to see if the user should be logged out or not", but I don't like that solution...
Cheers!
The session is by design private to individual users. Therefore to abandon it, it has to be done by the user.
So you might have to use another a list & check that.
Ideally though, you shouldn't tie your authentication state to the session. Whether the user is authenticated or not should be independent. You can then choose to abandon the session by querying the authentication state. It also makes it easier to implement mechanisms like counting logged in users & ensuring login from only 1 location - should you require these.

Secure an ASP.NET Application Using limit for number of logins

I am trying to find a solution to control the number of logins on asp.net application.
I need to install the application in the client server, and set the number of licences. e.g. only 10 users are allowed to access the app.
Every time someone tries to login I need to check how many user are logged in, compare with the total allowed then authorize that user to proceed.
I tried with Certificate, but I couldn't see where to match the number of logged in users with the max number of allowed user.
Also I would like to use the IP address as identifier, then if I open 3 browser windows, it count only one user logged.
Basically this web application will be sold by licences. We need to control the logins per computer, and not per user, and block logins if the limit of logins are reached.
Please forgive me, if i am not clear with the description.
Thanks for any help.
I would use the SessionID in the Session object as the key, I'd store that along with the UserID for the logged in user in a database or some kind of backing store. I'd use Session_End in the global.asax to remove the records above for any session expiring and also remove them in any logout function. You should find it fairly simple to count the number of active sessions you have and confirm that it's not the same user logging in again, if that's allowed.
What I would do is use the global.asax file and increment a counter in session_start and decrement on session_end.
Since the session is stored in a cookie, several sessions on the same computer only create one session.
Here is a good refrence for the global.asax file:
http://aspalliance.com/1114_Understanding_the_Globalasax_file.3
I would use the Membership.GetNumberOfUsersOnline method, if you are using the Membership API, to determine the number of active users.
I believe this number only counts the number of users you have authenticated so it is safe to use in your scenario.

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.

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