All pastes #24164 Raw Edit

Stuff

public text v1 · immutable
#24164 ·published 2005-09-29 05:07 UTC
rendered paste body
Authorization server is "auth.com"

auth.com has a small database on it:

site    secret     authorize url
------- ---------- ---------------------
b.com   secret1    /remoteauth.php
c.com   shhhh      /backend/remoteauth.php

It also contains a user database, with usernames, and passwords

Each member site (b.com, c.com) contains a "userauth" database with fields: UserToken, Username, LoginTime, LastAccessTime. This stores logged-in users.

Also, for this example, every page on b.com and c.com requires authorization: you can't even see either site without logging in.


Now, let's say a user opens their browser and visits http://b.com.

The first thing b.com does is checks for a UserToken cookie. None exists, so it knows this user is not logged in. It then inserts a new entry to the "authusers" database, with only "UserToken" = random string (lets say "foobar"), and LastAccessTime = time(). It then sets a cookie called UserToken to the same value inserted in the database, and sends a 302 Redirect header to "https://auth.com/authorize.php?usertoken=foobar&redirect=http://b.com"

auth.com checks for its own UserToken cookie (remember cookies are not shared across domains). None exists, so it shows them a login page. Once they login successfully, it sets a UserToken cookie for them, and creates its own corresponding userauth database entry. It then uses the site database (listed above) to see that it has to make the following query:

http://b.com/remoteauth.php?user=UESRNAME&usertoken=foobar&auth=AUTHCODE

where AUTHCODE = sha1(USERNAME."secret1") (the shared secret for b.com)

remoteauth.php on b.com gets this post, and after verifying that $_GET['auth'] == sha1($_GET['user']."secret1"), it updates the authusers database where UserToken = $_GET['usertoken'], setting the username to $_GET['user'], and LoginTime and LastAccessTime to time(). During this time, the user is still waiting for the page on auth.com to load (this is also why we don't set a cookie here or just use plain PHP sessions; this is auth.com visiting b.com, not the user).

Now authorize.php sends a 302 redirect back to http://b.com. The above process on b.com repeats. b.com looks for a UserToken cookie, but this time finds it.. then it looks in the database, and sees that there is indeed an entry for that UserToken, with Username filled in, so it now considers this user to be logged in.

Next time they hit a page on b.com, it checks for the UserToken, finds the user name in the userauth database, and considers them logged in.


Now, the user decides they're bored of b.com, and visits c.com.  c.com repeats the same process as b.com did at first. Doesn't find a UserToken cookie, so it sets a new one, and inserts it into the database and sets the cookie. Now it sends a 302 redirect to "https://auth.com/authorize.php?usertoken=nasdfn2fh2sadf&redirect=http://c.com/somepage". 

This time, auth.com finds its own UserToken, and checks its own userauth database. It finds the token, so it immediately posts back to c.com:

http://c.com/backend/remoteauth.php?user=UESRNAME&usertoken=nasdfn2fh2sadf&auth=AUTHCODE

where AUTHCODE = sha1(USERNAME."shhhh") 

c.com/remoteauth.php gets this post just like b.com did, and after validating it, updates its userauth database.

Now auth.com sends a 302 redirect to the user, sending them back to http://c.com/somepage.

c.com checks the UserToken, and finds a matching entry in the userauth database, and considers them logged in.



For the user, what has happened:

go to b.com, get redirected to https://auth.com/authorize.php?usertoken=foobar&redirect=http://b.com and see a login page.

Enter login information, and get redirected to http://b.com. 

Click a link, the page just loads, no redirects involved.

Go to c.com, get redirected to https://auth.com/authorize.php?usertoken=nasdfn2fh2sadf&redirect=http://c.com/somepage, and immediately redirected to http://c.com/somepage.



On every page load, we also want to update the userauth database and set LastAccessTime = time(). Say we have a timeout of 1200 seconds (20 minutes). On every page load (or every few loads, or in a cron script running every couple minutes), we want to do "DELETE FROM userauth WHERE LastAccessTime < time() - 1200". This will remove any entries where the page hasn't been accessed in 1200 seconds, requiring the user to authenticate again. The delete of course has to happen before the update.

This doesn't timeout on auth.com though. We only access auth.com when we're first accessing a new site. So, to keep auth.com 'in the loop', on every page we load an image: <img src="http://auth.com/reauth.php?user=USERNAME&auth=AUTHCODE" width="0" height="0" /> (we could also do with with javascript or an iframe, but an img seems most reliable)
This isn't really an image, it just updates the LastAccessTime on auth.com. We're passing it enough data to be able to figure out which user to update without the cookie. I was told that cookies wouldn't load when you loaded the page via a different site, but in my tests it works fine. 

So again, we just need to delete expired entries on auth.com on a regular basis (from cron). If they've been active on b.com, and then visit c.com, c.com will redirect to auth.com, and auth.com will return immediately because there's still an active session.





timeout = 600 seconds

auth.com -> b.com  1:10
b.com 1:10 - 1:18
-> auth.com thinks timeout is in 2 minutes, b.com thinks in 10 minutes