ServiceStack session lifetime is increased on heartbeat - c#

I have a Service with a ServerEventsFeature. I'm using a ServerEventsClient which by default sends heartbeats to the service. As far as I know ServiceStack doesn't support sliding expiration from the box, but session lifetime is refreshed after every heartbeat. Is this how it should be and are there any ways to control that? I've tested it by setting SessionExpiry to 30s and HeartbeatInterval to 20s - the app sends multiple (10+) heartbeats w\o any problems. In addition, if client app crashes and force closes - the session will be "alive" in the server sessions list until I try to use it, is there a way to drop it earlier?
Example:
start the server
launch client 1
execute
var sessionPattern = IdUtils.CreateUrn<IAuthSession>("");
var sessionKeys = Cache.GetKeysStartingWith(sessionPattern).ToList();
var allSessions = Cache.GetAll<IAuthSession>(sessionKeys);
the results count is 1
launch client 2 and 3
drop client 1 through force shutdown (no logout calls)
execute the same code again - results count is 3

A Server Events subscription doesn't have any impact on a Users Session.
A Users Session is created after a user successfully authenticates and is destroyed when they explicitly logout or when the session expiry elapses.
A Server Events subscription is just a reference to a users long-lived HTTP Connection to the SSE /event-stream, it's only relation to a Users Session is that the subscription may be that of an authenticated user.
But the life-cycle of a Users Session (which is just a AuthUserSession POCO persisted in the registered ICacheClient) is not affected by a Server Events subscription since it never re-saves the Users Session, so never changes the Session Expiry.

Related

Stop Users Concurrently Signing In Via Different Machines - Identity Server 4

I am using Identity Server 4 with the quickstart UI and a client using Cookie Authentication.
Lets say I have user A on machine A who is currently logged in via the browser. Then user A decides to go on machine B and logs into that one. As it stands, a new session cookie will be issued for user A on machine B as well as machine A.
This is fine, but I want the option to mark particular users with a flag e.g. IsConcurrent and if it is set to true, they will be given the option to either keep their existing session on machine A, or terminate it and start a new session on machine B.
I have done some reading and found references here to updating the security stamp for a user and setting the interval to zero, so it checks the security stamp in the cookie against the stored version. However, this code didn't seem to be inline with Identity Server's code. Also, it it a valid option in this case?
I also found here which mentions storing and checking the value of session IDs, but I'm not sure if this is valid either?
An initial idea was to implement some middleware that obtained the Machine ID and stored it in a table along with the user, but then I was unsure how to take something like this any further.
Any help or advice would be much appreciated.
Assuming cookie based authentication, you can extend the client to validate the user session provided that the client keeps track of user sessions.
For that you can create a session manager where you add a session for the user (sub) after login, this also includes automatic login sessions (SSO). Remove one or all sessions on logout, which should also be updated on back channel logout (LogoutCallback).
Assuming you use middleware, you can consult the session manager there and decide what to do. Make sure that the current session isn't already activated after login. It has to step through the middleware at least once. Some pseudo code to illustrate the idea:
public Task Invoke(HttpContext context, SessionManager sessionManager)
{
if (context.Principal.Identity.IsAuthenticated)
{
var sub = context.Principal.FindFirst("sub")?.Value;
var sid = context.Principal.FindFirst("sid")?.Value;
// User is allowed when the current session is active.
if (!sessionManager.CurrentSessionIsActive(sub, sid))
{
// Rewrite path if user needs and is allowed to choose: redirect to session selector or
// Activate the current session and deactivate other sessions, if any.
if (sessionManager.HasMultipleSessions(sub) && sessionManager.CanSelectSession(sub))
context.Request.Path = new PathString("/SelectSession");
else
sessionManager.ActivateCurrentSession(sub, sid);
}
}
return _next(context);
}
On post of the SelectSession form you can mark in the session manager which sessions are active. If the old session should be preserved, then ignore the old session (remains active) and mark the current session as active.
Make sure to add the middleware after authenticating the user.
Please note that for access tokens you'll need a different strategy.

ServiceStack ungraceful client disconnect

In a ServiceStack app is there any way to determine that the client has ungracefully disconnected? I would like to get a list of users that are online, but
var sessionPattern = IdUtils.CreateUrn<IAuthSession>("");
var sessionKeys = Cache.GetKeysStartingWith(sessionPattern).ToList();
var activeSessions = Cache.GetAll<IAuthSession>(sessionKeys).Values;
will only get valid sessions, that are valid until they expire or client logouts (which doesn't reflect whether he is onlline or not).
If you're referring to Server Events subscriptions, their lifetimes are completely unrelated to User Sessions. A Server Event subscription just represents a long-lived HTTP connection to the Server Events /event-stream which may or may not be from an Authenticated User.
The way to find out active connected users is to call /event-subscribers.
Inside ServiceStack, all information available on Server Event subscriptions is accessible through the IServerEvents dependency, e.g. To find out all active subscriptions for a user you can call GetSubscriptionInfosByUserId()

SignalR: How to stop creating new connection on page reload

Hi i am developing a chat application along with some other pages in my application. once i login i am maintaining the session of the user. My main intention is that user should get notification whenever another user connects to server.
The problem that i am facing is whenever i navigate to some other page in my application the connection is lost. How to stop this behaviour and continue the connection until user logs out.
I am using SignalR 2.0 in ASP.NET MVC4 project, any help??
Each connection only has a lifecycle for the duration of the time the user spends on a given page. When they navigate to another page, a new connection is established. Also, if a user has more than one tab or browser window open, they will have multiple connection Ids. I don't think you want to try to persist the connection Id beyond it's intended lifecycle.
In a similar scenario that I work on, we store the connectionIds OnConnect and delete them OnDisconnect. When a message needs to be sent to a given user, we send it to all of their connectionIds. This ensures that the message will be delivered to all tabs/windows.
EDIT 1 the following is in response to #Saurabh's comments:
Consider what the scope of the Hub is, and that of your other classes and the client. The Hub is there to facilitate communications between the browser and the server. While it's possible to do a lot of work within the hub, I think it's best to move most of the scope outside of communictions to other places.
The client knows that it just reloaded a page, so it's a good candidate for making the decision that this is a reconnect event.
_chatHub.server.reJoinRooms();
Then the Hub can query the user's rooms, by UserId, rather than ConnectionId.
public Task ReJoinRooms()
{
// get the user's rooms from your repository
// optionally get the user's connectionIds from your repository
// Clients.Caller.onJoinRooms(rooms);
// or Clients.Clients(_connectionIds).onJoinRooms(rooms);
}
Then the client can decide whether or not to take action:
$chatModule.client.onJoinRooms = function (rooms) {
for (var i in rooms) {
var _room = rooms[i];
// if I'm not already in this room, add it to my rooms
console.log('joining room', _room)
}
}
You could skin this many different ways. The client could own the scope of remembering rooms, instead of a server-side repository, too.
EDIT 2
If the number of groups/rooms that a user belongs to is ever-increasing, the above example may not scale up very well.
In that case, each user could join personal feed(s) instead (i.e. join a feed named for the user's GUID). We would keep track of each user that is affiliated with a group. When a message is sent to that group, we would iterate over those user's and publish a message to each feed.

Is session in Asp.net is shared between users of the website or not?

Is session in Asp.net is shared between users of the website or not?
Client 1
stored value in session in page load like that:
Session["editStudentID"] = editStudentID.ToString();
Client 2
Visiting the same page of client 1 in the same time so there will be other session stored
Session["editStudentID"] = editStudentID.ToString();
so can client 1 or 2 sessions interrupted by each other ?! or the session is unique per client
No, it is not shared.
The server, where the Client is sending the request to start a new Session, assigns that client a new Session ID. This is a unique ID or Token per Client. Each Post or Get to the server generally sends that Session ID or Token with it in order to tell the Server who it is(an identifier).
Also all session variable data is stored on the server.
Session is per-session ID, and session IDs are normally per-browser (via a cookie or a URL parameter).
No, it is not.
When a client connects to the service for the first time the initial response includes a cookie which is used to track subsequent connections from that client. The cookie's value is then used whenever you reference the Session object to determine which data in the backing Session store is referenced.
So changing the Session data in any request will only alter it for that client. If you need to have data shared between multiple clients you have to provide a different mechanism for doing so - a static dictionary or similar.

HttpSessionState Where, How, Advantages?

You see the code below, how I did use the session variable;
So the three questions are:
Where are they stored? (Server or Client side)
Are they unique for each web page visitor?
Can I remove it using ajax or simple js code when my job is done with it? or it will be removed automatically..?
.
sbyte[][] arrImages = svc.getImagesForFields(new String[] { "CustomerName", "CustomerSurName" });
Dictionary<string, byte[]> smartImageData = new Dictionary<string, byte[]>();
int i = 0;
foreach (sbyte[] bytes in arrImages)
{
smartImageData.Add(fieldNames[i], ConvertToByte(bytes));
i++;
}
Session.Add("SmartImageData", smartImageData);
Read more about sessions here. To answer your questions:
Depends on your configuration (in-process, Session State Server etc.), but always server-side.
Yes, each visitor gets a unique cookie.
You can remove it client-side by removing the session cookie (usually ASP.NET_SessionId), or server-side by calling Session.Abandon(). Also, a session times out after a certain (configurable) period of inactivity.
Session variable are stored on the Server? You can configure other state management mechanism (E.g Database).
They are unique for each user session. It will be removed when Session times out.
Session state information is stored on the server and not on the client side. When the session expires, this session information is removed completely and automatically. You can change the session expiration duration through web.config file. Session data is unique for each user. You can always use it using ajax or change it or even remove it.
If you want the session data persistent to be persistent, you can configure your database for storing the session information. You can even configure a state server to store the session data.
The session is usually stored on the server (depending on your server/application configuration). Each unique browser connection is allocated a session id which the server uses to associate the client with a unique server session on subsequent connections. The session id is passed to the client to store as either a cookie, or as a paramater attached to each url request to the server.
It is used as a means of preserving client state with the server between HTTP calls.
The session expires after a configurable time of inactivity. However in .NET you can call Session.Abandon() to end the current session.

Categories