Authentication between multiple systems/platforms within the same web application context
Consider the following scenario: Web application is using two separate systems (they can share data/state through DB). First one is used for processing standard web stuff like HTTP requests/responses, HTML content, forms and all things related. Second is used for real-time communication like sending messages and notifications (long poll or WebSocket server).
User can be authenticated through the first system/platform and if the credentials are valid, some web page is sent back to the client. Once this page is loaded, client should be connected with the second system/platform transparently in the background.
The question is: how to authenticate user on a web page/application which consists of multiple systems/platforms on the back-end?
I can imagine it this way:
- When user is authenticated through the first system/platform, GUID token is generated and stored in a database bound to some user. This token and user ID is also sent in a response back to the client and, for example, rendered on the page in hidden fields.
- When the page is loaded and connection with the second system/platform is taking place, token and user ID from hidden fields are retrieved and sent as parameters with connection request. Back-end finds user, compares his token in the database and if they match real-time connection could be initiated.
I understand that this approach is vulnerable to sniffing for example, but I'm namely interested in the authentication procedure between two separated systems/platforms.
Please see here for an example. https://www.login.mtu.edu/docs/public/mtuiso/howitworks2.html I will make an answer when I have a second.
@this.josh: yeah what I really meant is to store these informations somewhere on the client, doesn't have to be hidden fields, it can be a cookie...
A fundamental question is whether the two systems are serving pages from the same domain (e.g., www.example.com/a and www.example.com/b); from two related domains (e.g., a.example.com and b.example.com); or two unrelated domains (e.g., a.com and b.com). This affects what solutions are or are not viable.
- Generate a session token upon login.
- Store that session token in the database.
- Check for valid session tokens when authenticating.
Pretty much what you have. Just consider if you want to have more than one valid session at once and how you'll go about expiring sessions.
EDIT for crazy comment thread below
While one can provide tokens to the client that are verified by the 2nd server without communicating with the 1st server, that's ugly and involves a lot of work. Such a scenario does not permit one to invalidate sessions unless the client takes care of it. It also requires a certain time window when tokens are passed, timestamping of tokens, tracking of tokens by the 2nd system, signing or HMACs in the token passing, etc. Unless these two systems can't see each other on the Internet, just avoid that mess entirely.
I gather that both systems can access the same database, but if for some reason they couldn't, having a API exposed to the second system that can remotely verify would be appropriate as well (secret.page?checkUser=token... or such).
Without SSL, there is nothing you can do to prevent session hijacking by means Firesheep / MITM attacks.
I also need to cover the case when user is authenticated from multiple browsers for example, or when the real-time connection is lost and needs to be reinitiated (I can think of one problem which may happen here - I will be passing expired token to the second system so the authentication would fail).
Design your schema so authentication tokens are in their own table and joined to the user table by user id. Primary key (user_id, token). Then you can have multiple valid sessions. You may also want to add an expiry timestamp that is checked by your app and have a cron job to delete expired tokens.
Other solution which came to my mind: when the page is loaded, send AJAX request for token to the first system and in the success callback of this AJAX call pass token to the second system connection request. This way there is no need for storing token or user ID in the hidden fields.
EDIT: nevermind; You don't want to be authenticating like that. There shouldn't be anything like this on the client side. I know the right way to do this, but I don't know the specifics. I will research and get back to you.
How will you prevent replay attacks? How will you invalidate a session on logout? Deal with a disconnected session? It is possible to do this with client-side work, but you've made a much much larger headache for yourself if you go down that route.
@user606723: but don't you have to send something from the client side to the second system in order to authenticate user bound to some session?
You're right, I suppose I was a big vauge and you do have to send -something- from client side. A cookie is a good option. If not a cookie, then something signed with a private key.
Also, the problem with Jeff Ferland's suggestion is this assumes that the Apps have some sort of real-time communication, such as a common database. I think this is a bad real world assumption.
@user606723 If not a database, then some sort of programmatic API. Need to address concerns from my last comment. Systems can't do that without communication of some kind.
@Jeff Ferland: token from that AJAX call would be returned only if you are already authenticated to the first system. This AJAX would also return entirely new token (it will also have timestamp on the server) each time you make this call. So if you try to connect with the same token for example 15 seconds later it won't be valid and you would have to request new one. Is this approach still invalid?
@yojimbo, how is the second app going to know it's a valid token? Do they share a database?
@user606723: Yes, they both have access to the same database on the backend in order to share state and other stuff.
The problem is that, that makes for a very easy man-in-the-middle attack. All I have to do is get a token and respond with in 15 seconds? easy peasy. You could do a few things to address this to make it *almost valid* but it will never be a optimal approach.
My recommendation is a single web app that is used for primary user authentication.
Note: Because of the nature of cookies, this method will only work if the webapps share a common domain. (ie. appone.example.com and apptwo.example.com)
openid does something similar but bypasses the cookie problem, you might want to look intot hat.
How this would work.
- User points his browser toward App A. App A checks for valid cookie/session/whatever.
- It first checks for it's own session/cookie information.
- If it can't find it's own cookie, it looks for Auth App's "transfer" cookie.
- If it's found, then it create a new session for this app. The user has just logged in.
- When it finds this is invalid or missing, it forwards the page towards Auth App.
- Auth App checks for a valid session on it's end.
- When it discovers this missing, it brings up a login screen, etc.
- Once it has a valid session, the Auth App sets a specific "transfer" cookie for that app and redirects the person back to App A.
You should put extra information in this transfer cookie such as-
- IP address.
- Random number.
See the following for an example. https://www.login.mtu.edu/docs/public/mtuiso/howitworks2.html
This will be mostly seemless from the user perspective. For example.
- User point his browser toward app A.
- App A does it's authentication dance with Auth App. (requiries user to log in, etc.)
- User clicks a link that forwards to app B.
- App B does it's authentication dance with Auth App. (This time, Auth app already has a cookie for itself.)
- App B forwards to Auth App.
- Auth App finds cookie and then right away creates transfer cookie and forwards to App B.
- User doesn't even notice this, and finds himself at App B right away.
- User points his browser toward App A. App A checks for valid cookie/session/whatever.
Four options, first one being with maximum cost(money and performance both) and third being cheapest
Deploy solution like Siteminder, Novell, Tivoli etc
Maintaining session state in DB. For doing this. Problem with this approach is that it would be difficult to track logouts, session expiry and propogating this informaton between the two applications. As querying the DB before each request would be very expensive
Using a Third application just to manage the session states. This application not exposed to end user only restricted within the network with access to only the two applications It stores the states for all users in Application context and the two application send a request to this application
On login events On logout events On session expiry events before processing any request to check session validity
Using a cookie ( with the assumption that both application share the same parent domain)
Create a cookie which contains username + salt/ecret key and this encrypted Secret key and the encryption keys are with both applications Any request from user will carry this cookie ( Cookie path set to /) So if the cookie contains a username, other application trusts user is logged in on other application