Azure AD - multiple tabs or browsers - session management - c#

I'm trying to determine how to handle session management with multiple tabs and browsers. I want my react application to:
Only allow one active token, so that if you logged into a new tab or browser, the previous tab's session would end (or at least future requests on it would be invalid). Currently I can log in any number of times in new tabs or different browsers and get a new token every time, the previous ones still work too.
If you duplicate tab, the same session / local storage info is there, so the token is the same, that's permissible.
If you have two tabs via duplication, and you sign out of one, the other should stop working because the token should no longer be valid
I'm using the react-adal package and mainly followed This tutorial for session mgmnt but these are the missing requirements I'm trying to fill in. I can't find anything about these configurations in the AAD documentation. All I've found are timeout options, nothing about simultaneous tabs and different browsers.

There isn't a boilerplate solution I'm aware of. However, if you are able to maintain in-process session state, or out-of-process (using Redis, SQL or storage account etc) then you could generate a single use token for each dynamic (state changing) content request.
You will need to validate this token for each and every request and it must be associated with the user. If the user doesn't present a token, or there is a token mismatch, redirect them to the logout URL. Your logic could overwrite the token on a new login thus rendering the old session invalid. This is similar to anti-CSRF tokens.
The tutorial you linked explains how you can log the user out.

Related

What authentication model should my application use?

We have a SPA application that makes use of cookie-based authentication. The cookie is validated on the app server by checking the expiration time of the user's stored session in a database.
The client requirement is that each new tab/browser opened should force the user to log in on that new tab/browser instance, thus allowing the user to have multiple sessions open for concurrent work purposes. Closing a tab or signing out needs to expire the user's session for that specific tab and still keep the other sessions active. Refreshing a tab should obviously still keep the user logged in on that specific tab.
At the moment, we make use of a unique identifier to identify the specific tab with its accompanying cookie, in order to only clear the relevant cookie when the user logs out or closes the tab. This unique identifier is stored in Session Storage and gets passed as a header with each server request. This unique identifier is visible in the the browser URL, for the reason that when the tab is refreshed, that identifier is used to get the relevant cookie and authenticate it.
This whole process feels clunky and prone to bad security practice.
What type of authentication would be best to facilitate the client requirements?
It feels like a very old-fashion and outdate requirement, to have separate sessions per tab. One approach is to let the backend redirect each new request to it, to its own unique per-tab sub-domain, so that each sub-domain can get its own independent set of cookies.
like
session1.mysite.com
session2.mysite.com
session3.mysite.com
session4.mysite.com
session5.mysite.com

How can I get a list of logged in users with IdenityServer4?

I've an AspnetCore + Angular setup where the authentication part is handled by IdentityServer4. One of the requirements now is to get a list of all users who are currently logged in. Any ideas/suggestions how to proceed on this?
PS: Just in case it's needed, I'm using implicit flow .
Auth is persisted via a cookie, which lives client-side. The server doesn't know who all is logged in. It only know in the context of a particular request (where the client sends the auth cookie back) whether that particular client is authenticated or not.
If you really need this, you'll need to manually track it yourself somehow, like adding a record to a table for each login. However, this can get gnarly fast. You'll need to also manage sign outs and expirations, to keep your custom data fresh.
A generic answer could be: ASP.NET CORE keeps each user session in a cookie, separately located at each user's browser on each device. Once you need, you have to centralize that system yourself. Howerwer, since the question regards Identityserver, we can look into what is already done in that area by the IdentityServer authors. And they have provided at least two extensibility points.
The first one is to employ Reference Token (instead of the jwt by default), then look through the persisted grants database, fetch all the sessions grouped by userId. Not a standard way for OpenIdConnect, but it exists.
The other approach is to implement your custom session store based on a database (instead of the cookie based by default). That provides you access to all the clients logged in with the given user id. Here is my old (but still valid) example of a hybrid (cookie + IDistributedCache such as REDIS) extension for the DefaultUserSession. Usually after the requirement to list all the user sessions, appears the other one: to create a kill the session button next to each row. Here you have to be careful with access token lifetime (make it reasonably short), as a jwt once issued can not be invalidated before its normal expiration.
There is provision in the default cookie provider in ASP.Net Core to use a DB or distributed cache to store cookie payloads. Check out the Microsoft.AspNetCore.Authentication.Cookies.ITicketStore interface and the CookieAuthenticationOptions.SessionStore property.
We created our own implementation that stores auth cookies in the PersistedGrants table along with IDS4 stuff. It works well, keeps cookies small and facilitates a "sign out on all devices" option also. If you align the expiry of the entry with the cookie authentication properties then the housekeeping is done for you.

In Identity Server 4, is it possible to make logging out of one application log that user out in all applications?

I currently have a .net core application that uses Identity Server 4 to authenticate users. We have two different applications; an MVC portion of our site that users can login to, and a SPA that users have to login to as well. Is it possible to make it so that anytime the user logs out of one of those areas, that it logs out of both?
This is the main idea of Single Sign-On. Not only single login, but also single logout. Identity Server 4 fully support this, but you just need to configure both your clients (the MVC app and SPA) with their proper configurations. This is the official documentation about signing out. It works.
EDIT
PS: Have in mind that Identity Server does not invalidate the access token, once you are logged out. In other words - if you, by any chance, still have the access token, you will be able to use it, as long as it is valid (its validity period has not expired). This is why usually the access token is set to have a shorter lifetime.
There are 2 front channel ways to acheive this and I'd recommend using both.
1) Front channel log out which uses an endpoint registered against each client. When you sign out of IDS4 (assuming it's implemented properly) it will make a request to the registered endpoint for each app that was signed into during the current session. http://openid.net/specs/openid-connect-frontchannel-1_0.html
2) The session monitoring spec which uses a bit of javascript and cross-domain iframe magic to notify the client app when the user's session changes on the IDP. Using this you can immediately respond to changes and do any cleanup you need to. http://openid.net/specs/openid-connect-session-1_0.html
As mentioned in m3n7alsnak3's answer this will not invalidate any JWT access tokens (you can use the revocation endpoint to revoke refresh or reference tokens however). Therefore I'd recommend having the client applications to the best job they can of clearing up any state they can, i.e. clearing all cookies, session/local storage etc.

Prevent concurrent user sessions ASP.NET Core

I am trying to prevent multiple concurrent sessions for a user using ASP.NET Core and CookieAuthentication middleware.
Any tips on how to do this?
Ideally, once a user signs in, the app would invalidate and effectively "sign out" all other existing cookies issued for that user. Then, the old sessions would be redirected to the sign in page on the next interaction with the server. So far, I have not found a way to do this.
I have been trying to figure out a way to use a custom validator as described in the documentation.
Thanks!
This is how I've handled it (using ASP.NET Core, but that is irrelevant): To do this you need to maintain state somewhere that is accessible to your server(s). You can store a session ID in a database when the user logs in. Each web app client should hit a heartbeat url (e.g., every few minutes). The back end for the heartbeat checks the session id in the database. If it is the active one for the user, then all is good; otherwise it clears the cookie. If you are using a persistent connection to the client (websocket) then you can push a message to the client to indicate the session is no longer valid.
If you need to be sure that no other action by the user's other session can take place once a new session has started, then you'll need to check the session (as described above) on every call. ASP.NET Core's middleware capability is perfect for this.

global admin page for multiple applications in ASP.Net

I was wondering if anybody could give advice on a secure way to implement a global login. I have an admin page that accesses active directory admin groups after typing in your username and password.
current logged in account (on computer) does not matter
user in web browser goes to web app, redirects to global login page with query string of app name
types user name and password of an account in AD (not necessarily current computers logged in user)
authenticates (looks up user, pass etc and authentication is valid)
redirects back to original web app.
Once redirection happens, how do I securely tell the original web app that this user is ok until the original web session dies?
The way I'm thinking of implementing it:
My original thought was to pass the session ID of original app to the login page as well as the app
name. Store that session in a DB once authentication is checked. Master page of the other app validates on page load that the session ID matches. On session close, remove current session ID from DB.
You cannot depend on sessionID accurately in some cases. SessionID only becomes a constant value after a (any) page makes a request for a session variable, if you dont have Session_Start not defined in global.asax. If you log the user in and the default page does not access session, you will end up with a different session id for the subsequent requests until a request to session is made. Usually it is always constant as there is a default empty session_start event in global.asax.
But similar to your model, you could generate a GUID (or make sure you access session on login/authentication) and store it in the user table with an expiration. Your web sites can check this key and if currently valid, auto sign the user in.
You also cannot depend on session_end event since there is no real accurate way of detecting it (eg: user closing browser). So, you should store this ID with an expiration time along with it, preferably the same as session timeout. Just like session, you will need to extend this, something like a sliding expiration. This way, this id will be expired after a period of inactivity.
also, this Claims-Based Single Sign-On for the Web may be of interest to you.
What you're describing sounds like it would be better implemented using Windows Identity Foundation and Active Directory Federation Services 2.0. I don't know the extent of all your requirements, but it might be valuable to check out what these will give you out of the box.
You could use a cookie. If you pass the name of the application to the login page, you can set that application name to the PATH property of the formsauthentication cookie. By setting the PATH property, you're effectively limiting the readability of the cookie to the pages within that path. Because it's a common login interface, this may require some code being done perhaps in a common page base class that handles the parsing of the cookie information.
You can share authentication tokens between .NET applications, even between .NET CLR's if you want to. I think this will give you the single sign on you're looking for.
At a high level you need to share a machine key between the applications. You can generate the machine key using the key generator app code example found on this link, and providing you then reference the same key in each application the sign on can be shared:
http://msdn.microsoft.com/en-us/library/ms998288.aspx
There are some consideration when looking at things across domains or accross machines/web farms etc, but if all apps are on the same box it's not too hard.
The harder side of things is sharing things like session state which I don't believe can be done accross app pools. (I ended up recreating the session object on the new app manually last time I did it :( but that was between 1.1 and 2.0 apps )
EDIT: I did a rough write up of it last year and was using it as a test for a demo article on my site, might be worth a read through if you want things broken down a bit more (Ignore the unfinished site!):
http://www.dougmcdonald.co.uk/test/html5/v5/articles/2010/05/10/Sharing-forms-authentication-between-applications/

Categories