Transparent user session over several sites (single sign-on + single sign-off)

17,440

Solution 1

Well, let me explain a bit further then. (All URLs are fictional!) As I said, the visitor goes to http://www.yourwebpage.com and indicates he wants to log in. He is redirected to http://your.loginpage.org?return=http://www.yourwebpage.com/Authenticated where he will have to provide his username and password.
When his account information is valid, he will return to the page that was provided in the login URL, but with an additional parameter that will be used as ID. Thus, he goes to http://www.yourwebpage.com/Authenticated?ID=SharedSecret where SharedSecret would be a temporary ID, valid for 30 seconds or less.
When your authentication page gets called, the page would then call a method that's shared between yourwebpage.com and loginpage.org to look for the account information of SharedSecret to retrieve a more permanent ID. This permanent ID is stored in the web session of yourwebpage.com and should NEVER be shown to the user.
The shared method could be anything. If both servers are on the same machine, they could just both access the same database. Otherwise, they might communicate with another server through web services. This would be server-to-server communication thus it doesn't matter if the user is a robot or has no cookie support. This part won't be noticed by the user.
The only thing you'll have to deal with is the session for the user. Normally, users will be sent a session ID that's stored in a cookie but it can also be part of the URL as part of a GET request. It's a bit more secure to have the session ID inside a POST request, though, by adding a hidden input field to your form.

Fortunately, several web development languages do already provide session support so you don't even have to worry about maintaining sessions and sending session ID's. The technique is interesting, though. And you need to be aware that sessions should always be temporary since there's a risk that session ID's get hijacked.

If you have to deal with multiple sites on different domains then you will need to work on some server-to-server communication first. The easiest would be by letting them share the same database but it's better to build a web service around this database, for additional protection. Make sure this web service only accepts requests from your own domains just to add even a bit more protection.
When you have server-to-server connections, then the user will be able to switch between your domains and as long as you're passing along a session ID to the new domain, the user will be logged in. If the user is using cookies, it's not very likely that the session gets lost which would require to log in again. Without cookies, there's a chance that the user will have to log in again to get a new cookie if the session ID gets lost between browsing pages. (For example, the visitor goes to visit Google and then goes back to your site. With a cookie, the session could be read from the cookie. Without a cookie the session is lost since Google won't pass the session ID forwards.

Do keep in mind that passing on session ID's between different domains is a security risk. The session ID can be hijacked, thus making it possible for someone else to impersonate your visitor. Therefore, session ID's should be short-lived and obfuscated. But even if a hacker gains access to a session ID, he still won't have full access to the account itself. He won't be able to intercept the server-to-server communication so he can't access the database with your user information, unless he goes to the login page directly.

Solution 2

AFAIK, Google just uses a cookie for the "Google.com" domain. But Google also uses OpenID which allows for a generic login mechanism. Basically, this works by redirecting you to a special login page. This login page will detect if you're logged in or not and if you're not logged in it will ask you to log in. Otherwise, it just redirects you straight to the next page.

So, in your case a user would open somepage.example.com and the session for this app has no login ID. Thus it would redirect the user to logon.example.biz where the user will log in. Behind this page would also be a session and that session would tell that the user is already logged in. (Or not, in which case the user must log in first.) It then redirects the user somepage.example.com?sessionid=something where this sessionid would be stored in the session of somepage.example.com. Then this session will also know that the user has logged on and for the user it would almost seem to be transparent.

In reality, the user is redirected twice.

Solution 3

Are you using ASP.NET? If so, you might want to have a look at the enableCrossAppRedirects property.

Solution 4

If all your applications are on the one domain, then it is not too difficult because you can use a domain level cookie to handle the session control. (Cookie-less session management is difficult, but can be done, but is difficult.)

However, you indicated some sites on the example.com domain, and some on the example.org domain.

Playing a bit with my google sigh-in, and other sites of theirs orkut.com, it looks like when you hit a page that needs credentials, it redirects you to a common site for account login, which then redirects you back to the original site, presumably passing some sort of session token in the URL. From this, presumably the orkut.com servers confer directly with the google.com servers to verify the token and get whatever other user information is needed.

More Info On Domain Level Cookies as Reqeusted

If you have two sites, say foo.example.com and bar.example.com, you can set a cookie specific to the host, but you can also set a cookie for the domain that will be seen by all hosts on the domain.

So, foo.example.com can set a cookie for foo.example.com specifically, and it will only be seen by itself, but it can also set a cookie for the domain example.com, and when the user goes to bar.example.com they will also see this second cookie.

However, if you also have a site, snafu.example.org, it cannot see this domain level cookie that foo set, because example.org and example.com are two completely different domains.

You can use the domain level cookie to maintain session information across sites in the same domain.

How you set domain level cookies depends on your development environment (I have no experience with rails, sorry).

Share:
17,440
drdaeman
Author by

drdaeman

Just another code monkey. Did various things with various languages. Some projects went well, some weren't as good as others, but the experience was always valuable. English is not my native language, so please excuse my grammar mistakes. Feel free to correct me — I'll be grateful for that! Every my contribution, if could be considered copyrightable, unless explicitly stated otherwise, in addition to regular Stack Exchange licensing (CC BY-SA), may be used under any applicable license, recognized as free by Free Software Foundation. That includes WTFPLv2 for all your proprietary needs (but you should feel ashamed). The permission above obviously could not and does not cover parts not directly authored by me, i.e. fair-used quotations from other sources. I (hopefully) usually credit such inclusions fairly explicitly, so be sure to read the whole text before copy-pasting parts.

Updated on June 03, 2022

Comments

  • drdaeman
    drdaeman about 2 years

    I have several sites in different domains: example.com, example.org, mail.example.com and passport.example.org. All of the sites are having common look-and-feel and should share the same user base.

    And in such extreme case I still want all the sites to transparently (as much as possible) share user sessions with the following key properties:

    1. Single sign-on. When user signs on at passport.example.org and visits any other site — he should be treated as logged in.

      Logged in users get “Hello, $username“ greeting in site header and different navigation menu, listing services they have access to. If he's not signed in, instead of greeting there's a “Sign on” link, pointing to passport.example.org/signon.

      The list of trusted domains is known, so this is fairly simple to implement either with OpenID or with some homebrewn lightweight protocol. When user first hits the site, I'm redirecting him to special authentication endpoint at passport.example.org, which then silently redirects him back, with identity information (or “not signed on” anonymous identity) included. For most browsers this is completely transparent. Obviously, I'm using nonce values to fight redirection loops.

    2. Single sign-off. When user clicks “sign off” in the header of any site the next time he visits any site — he should be seen as “not sign on”.

      OpenID was not designed for this. My current idea (I already have a partially-working implementation) is to send not user identity, but “global” session token and share global sessions table (global_session_token ↔ user relation) in DB.

    3. Robots and cookieless-users support. Sites are having public areas, which should be accessible by user-agents without any cookie support.

      Because of this, redirection I've mentioned in (1) becomes a problem, because for every single page request, I'll end up throwing user-agent to auth endpoint and back. Not only this will confuse robots, but it will pollute my session database with dead-on-birth sessions very quickly. And I definitely don't want to display “hey, you don't have cookies enabled, go away!” page, that'd be extremely rude and disappointing. While I require cookie support to login, I want users to freely read what the sites are for and so on — without any restrictions.

      And I explicitly don't want to put session IDs in URLs except for some transparent cross-domain redirections I've mentioned. I believe doing such is a security problem and just generally a Bad Thing.

      And here I'm almost out of ideas.

    Okay, I know this is hard, but Google actually does this somehow with (google.com, google.lot‑of‑gTLDs, gmail.com and so on), right? So this should be possible.

    I'd be grateful for either protocol description ideas (that'd be the best) or links to systems (either code to read or just live sites to watch and learn upon) already successfully implementing something like this.

    To sum it up: Several domains without common root, shared user base, single sign-on, single sign-off, no cookies required to browse anonymously.

    All of the sites are on the same network (but rest on different servers) and partially share the same PostgreSQL database (resting in the different schemes of the same database). Most of sites are written with Python/Django, but some of them are using PHP and Ruby on Rails. While I'm thinking of something framework- and language-agnostic, I'm grateful for pointing to any implementations. Even if I won't be able to use them, if I'll get the idea how it's done there maybe I'll be able to come up implementing something similar.

  • drdaeman
    drdaeman about 15 years
    Well, I'm not using ASP.NET. Sites are written in Python/Django (mostly), PHP and Ruby on Rails, but thanks for the suggestion! I'll take a look and if this is what I'm looking for I'll try to see whenever I can find or create something similar.
  • drdaeman
    drdaeman about 15 years
    Thanks! The only problem remains is what to do with robots and users with cookie support disabled or not available. Sites (somepage.example.com) have a public parts, which should be accessible by not-legged-in users and robots. Redirecting them on every hit, and creating new never-to-be-used sessions is a problem.
  • Wim ten Brink
    Wim ten Brink about 15 years
    Without cookies, even Google will complain and advise users to turn on cookies. Otherwise your Google account won't work. Basically, the web server needs something on the client side to remember the session. Sometimes you can solve this by sending the session as part of the HTML page and back as postdata but the guys at Google just tell everyone to turn on cookies.
  • Wim ten Brink
    Wim ten Brink about 15 years
    About redirecting, you don't have to redirect the user on every page, just on the pages that need some additional protection. In your session data you would store the user ID if the user is logged on, or nothing for anonymous visitors and robots. All pages could check if there's a user-ID in your session. But the protected pages would redirect the user to a login page if they're unknown while all other pages just keep them anonymous.
  • drdaeman
    drdaeman about 15 years
    Thank you for such a detailed explaination! "and indicates he wants to log in" — this is where the problem was. I actually want user to be identified as logged in automatically, without any actions. I've did this with JavaScript JSONP request (making users without JavaScript click "Log in" link, but otherwise it seems that I can't support robots properly) to auth server and everything became simple, then.
  • DanielV
    DanielV almost 9 years
    Would be better to use a comment instead of an answer.
  • Juanito
    Juanito almost 9 years
    does not meet OP requirements