School-Yard/Content-Server — pull request #1 by particlebanana (2012-10-29 21:59:43+00:00)
Title: Access Control and Authorization

I went a different way with the Authorization component. I know we talked about using the cookie headers but after playing around with Amazon's API's I liked the idea of using HMAC with a short-lived token. It makes the API more versatile and can be on a public endpoint so client-side applications can make requests directly to it without messing with cookie stuff and it can be used for multiple apps.

This means in our User database we will need to generate a public auth key and private auth secret in addition to a role property. This could be added to the SSO user database and create a table for mapping applications and role level per user.

I implemented the Authorization check as middleware that works the following way:

- The client generates an HMAC token using the user's email address and a time block that allows the token to be valid for 60 seconds then hashes it using the user's auth secret. (The data payload can include whatever data we want, it's not limited or restricted to the user's email)

- The client sends an `Authorization` header in the format `auth_key:computed_hash`

- The API server looks up the User in the database by auth_key and uses the same algorithm to generate an HMAC token and as long as the request has been made within 60 seconds of the client's token generation they should match.

- If a match is made it sets a `req.user` property on the req object that contains the user's role level and user id.

The issue that arises and we will need to figure out is how to get that header set in a client side application. We can't send the secret down and compute the HMAC on the client and because it's only valid for 60 seconds we can't bootstrap it on page load.

From what I have read the best way to go about it is to create an endpoint on the server that serves the client-side app that can generate the HMAC token and then do a setTimeout on the client every 60 seconds to refresh the token. Or if we use web sockets we can push down a new token when it needs it.

Then we have the Access Control layer that we worked on. This sets a minimum access level for each route that can be compared to the `req.user.role` attribute.

I also included a CORS middleware component so the API can be accessed from any domain when using a client-side option.

Tests are included and should be passing.