From 76677bbd0263912f287b526faaf0c6c11c6b9696 Mon Sep 17 00:00:00 2001 From: Zachary Carter Date: Wed, 2 Apr 2014 14:38:56 -0700 Subject: [PATCH] initial oauth flow --- packages/123done/config.json | 8 ++++ packages/123done/oauth.js | 63 ++++++++++++++++++++++++++++++ packages/123done/package.json | 17 ++++---- packages/123done/server.js | 36 ++++------------- packages/123done/static/index.html | 1 - 5 files changed, 89 insertions(+), 36 deletions(-) create mode 100644 packages/123done/config.json create mode 100644 packages/123done/oauth.js diff --git a/packages/123done/config.json b/packages/123done/config.json new file mode 100644 index 0000000000..44af33113e --- /dev/null +++ b/packages/123done/config.json @@ -0,0 +1,8 @@ +{ + "client_id": "dcdb5ae7add825d2076572862ac0697f", + "client_secret": "b93ef8a8f3e553a430d7e5b904c6132b2722633af9f03128029201d24a97f2a8", + "redirect_uri": "http://127.0.0.1:8080/api/oauth", + "signin_uri": "http://127.0.0.1:3030/oauth/signin/", + "oauth_uri": "http://127.0.0.1:9010/v1", + "scopes": "user:email" +} diff --git a/packages/123done/oauth.js b/packages/123done/oauth.js new file mode 100644 index 0000000000..4d1a09808b --- /dev/null +++ b/packages/123done/oauth.js @@ -0,0 +1,63 @@ +var config = require('./config.json'), + crypto = require('crypto'), + request = require('request') + ; + +// oauth flows are stored in memory +var oauthFlows = { }; + +// construct a redirect URL +function redirectUrl(nonce) { + + return config.signin_uri + + "?client_id=" + config.client_id + + "&redirect_uri=" + config.redirect_uri + + "&state=" + nonce + + "&scope=" + config.scopes; +} + +module.exports = function(app, db) { + + // begin a new oauth flow + app.get('/login', function(req, res) { + var nonce = crypto.randomBytes(32).toString('hex'); + oauthFlows[nonce] = true; + var url = redirectUrl(nonce); + return res.redirect(url); + }); + + app.get('/api/oauth', function(req, res) { + var state = req.query.state; + var code = req.query.code; + + if (code && state && state in oauthFlows) { + req.session.code = code; + delete oauthFlows[state]; + + request.post({ + uri: config.oauth_uri + '/token', + json: { + code: code, + client_id: config.client_id, + client_secret: config.client_secret + } + }, function(err, r, body) { + if (err) res.send(r.status, err); + + console.log(err, res, body); + req.session.scopes = body.scopes; + req.session.token_type = body.token_type; + + // store the bearer token + db.set(code, body.access_token); + + // TODO get the email/avatar from the profile server + + res.send(200); + }); + } else { + res.send(400); + } + }); + +}; diff --git a/packages/123done/package.json b/packages/123done/package.json index 3a290f1e04..d2d7ae4963 100644 --- a/packages/123done/package.json +++ b/packages/123done/package.json @@ -3,13 +3,15 @@ "description": "A simple tasklist app that demonstrates Persona Sign-In", "version": "0.0.1", "author": { - "name" : "Mozilla", - "url" : "https://mozilla.org/" + "name": "Mozilla", + "url": "https://mozilla.org/" }, - "licenses" : [{ - "type": "MPL 2.0", - "url": "https://mozilla.org/MPL/2.0/" - }], + "licenses": [ + { + "type": "MPL 2.0", + "url": "https://mozilla.org/MPL/2.0/" + } + ], "homepage": "http://123done.org/", "bugs": "https://github.com/mozilla/123done/issues", "repository": { @@ -24,7 +26,8 @@ "redis": "0.7.1", "postprocess": "0.2.4", "connect-fonts": "0.0.9-alpha8", - "connect-fonts-drsugiyama": "0.0.1" + "connect-fonts-drsugiyama": "0.0.1", + "request": "^2.34.0" }, "engines": { "node": ">=0.8.0" diff --git a/packages/123done/server.js b/packages/123done/server.js index 442568b0e0..5848f251c8 100644 --- a/packages/123done/server.js +++ b/packages/123done/server.js @@ -4,7 +4,8 @@ var express = require('express'), redis = require('redis'), fonts = require('connect-fonts'), font_sugiyama = require('connect-fonts-drsugiyama'), - verifier = require('browserid-verify'); + oauth = require('./oauth'); + // create a connection to the redis datastore var db = redis.createClient(); @@ -19,7 +20,7 @@ var app = express.createServer( express.bodyParser() ); -app.use(require('./retarget.js')); +//app.use(require('./retarget.js')); app.use(fonts.setup({ allow_origin: "123done.org", @@ -44,40 +45,18 @@ app.use(function (req, res, next) { } }); +// add oauth endpoints +oauth(app, db); + // a function to verify that the current user is authenticated function checkAuth(req, res, next) { - if (!req.session.user) { + if (!req.session.code) { res.send("authentication required\n", 401); } else { next(); } } -app.post('/api/verify', function(req, res) { - var body = JSON.stringify({ - assertion: req.body.assertion, - audience: 'http://' + req.headers.host - }); - - // 123done.org can be served from a wildcard subdomain, and we match - // that subdomain to *.personatest.org. So, our audience is dynamic, - // and the verifier could be as well. - // Ex: ex.123done.org -> ex.personatest.org - var audience = 'http://' + req.headers.host; - var verify = verifier({ - url: 'https://' + req.verifier_host + '/verify' - }); - - verify(req.body.assertion, audience, function(err, email, data) { - if (err) { - return res.status(400).json(data); - } - - req.session.user = email; - res.json(data); - }); -}); - // auth status reports who the currently logged in user is on this // session app.get('/api/auth_status', function(req, res) { @@ -89,6 +68,7 @@ app.get('/api/auth_status', function(req, res) { // logout clears the current authenticated user app.post('/api/logout', checkAuth, function(req, res) { req.session.user = null; + req.session.code = null; res.send(200); }); diff --git a/packages/123done/static/index.html b/packages/123done/static/index.html index 87340957cd..e3bbab019e 100644 --- a/packages/123done/static/index.html +++ b/packages/123done/static/index.html @@ -57,7 +57,6 @@ -