Permalink
Browse files

Merge branch 'openid' for OpenID-authenticated, cookie-tracked sessio…

…n support
  • Loading branch information...
2 parents a72af56 + 22f4458 commit 14954343fc010321075694f3cc9fcc84db7f0b65 @MaxNanasy committed Nov 18, 2012
@@ -4,8 +4,15 @@
<title>Pick a Number</title>
</head>
<body>
+ {.section openId}
+ Hello {@}!
+ {.end}
<form method="post">
<input type="submit" value="New game" autofocus />
</form>
+ <a href="../login/">Login</a>
+ <form method="post" action="../logout/">
+ <input type="submit" value="Logout" />
+ </form>
</body>
</html>
@@ -0,0 +1,12 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pick a Number</title>
+ </head>
+ <body>
+ <form method="post">
+ <input name="openIdIdentifier" required autofocus />
+ <input type="submit" />
+ </form>
+ </body>
+</html>
@@ -2,9 +2,11 @@
"name": "pick-a-number",
"version": "0.0.0",
"dependencies": {
+ "cookies": "0.3.4",
"formidable": "1.0.9",
"http-status": "0.1.1",
"json-template-foo": "0.8.0",
- "node-uuid": "1.3.3"
+ "node-uuid": "1.3.3",
+ "openid": "https://github.com/havard/node-openid/tarball/ead2635b1d51e8383ec497c7fc6bcf1adf66c67b"
}
}
@@ -1,15 +1,19 @@
#!/usr/bin/env node
var
+ Cookies = require('cookies'),
formidable = require('formidable'),
fs = require('fs'),
http = require('http'),
httpStatus = require('http-status'),
jsontemplate = require('json-template-foo'),
+ openid = require('openid'),
url = require('url'),
uuid = require('node-uuid');
-var idToGameMap = {};
+var
+ idToGameMap = {},
+ idToSessionMap = {};
function validateAndParseDecimalNonNegativeInt(string) {
return string != null && string.match(/^\d+$/) ? parseInt(string, 10) : NaN;
@@ -22,19 +26,23 @@ http.ServerResponse.prototype.writeOnlyHead = function () {
http.createServer(function (request, response) {
var
+ cookies = new Cookies(request, response),
game,
gameId,
gamePathParse,
makeGuessPathParse,
urlParse = url.parse(request.url, true);
+ var
+ sessionId = cookies.get('sessionId'),
+ session = idToSessionMap.hasOwnProperty(sessionId) && idToSessionMap[sessionId];
switch (urlParse.pathname) {
case '/':
response.writeOnlyHead(httpStatus.FOUND, { 'Location': 'game/' });
break;
case '/game/': // TODO: Handle URI-encoded versions
switch (request.method) {
case 'GET':
- fs.createReadStream('game.html').pipe(response); // TODO: Content-Type
+ response.end(jsontemplate.Template(fs.readFileSync('game.html.jsont', 'UTF-8'), { default_formatter: 'html' }).expand({ openId: session && session.openId })); // TODO: Content-Type
break;
case 'POST':
gameId = uuid.v4();
@@ -51,6 +59,80 @@ http.createServer(function (request, response) {
response.writeOnlyHead(httpStatus.METHOD_NOT_ALLOWED);
}
break;
+ case '/login/':
+ function makeOpenIdRelyingParty() {
+ return new openid.RelyingParty(
+ (request.connection.encrypted ? 'https' : 'http') + '://' + request.headers.host + '/login/verify/'
+ );
+ }
+ switch (request.method) {
+ case 'GET':
+ fs.createReadStream('login.html').pipe(response); // TODO: Content-Type
+ break;
+ case 'POST':
+ new formidable.IncomingForm().parse(request, function (error, fields) {
+ if (error) {
+ response.writeHead(httpStatus.BAD_REQUEST); // TODO: Content-Type
+ response.end(error); // TODO: Test
+ return;
+ }
+ if (!fields.openIdIdentifier) {
+ response.writeOnlyHead(httpStatus.BAD_REQUEST);
+ return;
+ }
+ makeOpenIdRelyingParty().authenticate(fields.openIdIdentifier, false, function (error, authUrl) {
+ if (error)
+ // TODO: Return to login page
+ // TODO: Content-Type
+ response.end('Authentication failed: ' + error.message);
+ else if (!authUrl)
+ // TODO: Return to login page
+ // TODO: Content-Type
+ response.end('Authentication failed');
+ else
+ response.writeOnlyHead(httpStatus.SEE_OTHER, { 'Location': authUrl });
+ });
+ });
+ break;
+ default:
+ response.writeOnlyHead(httpStatus.METHOD_NOT_ALLOWED);
+ }
+ break;
+ case '/login/verify/':
+ if (request.method !== 'GET') {
+ response.writeOnlyHead(httpStatus.METHOD_NOT_ALLOWED);
+ return;
+ }
+ makeOpenIdRelyingParty().verifyAssertion(request, function (error, result) {
+ if (!error && result.authenticated) {
+ var
+ sessionId = uuid.v4(),
+ session = { openId: result.claimedIdentifier };
+ // FIXME: Sessions are never removed from memory
+ // TODO: Handle the case in which the user is already logged in
+ idToSessionMap[sessionId] = session;
+ cookies.set('sessionId', sessionId);
+ response.writeOnlyHead(httpStatus.SEE_OTHER, { 'Location': '/' });
+ }
+ else {
+ // TODO: Report errors to user
+ error && console.log('OpenID error:', error.message);
+ result && console.log('OpenID failure result:', result);
+ response.writeOnlyHead(httpStatus.SEE_OTHER, { 'Location': '..' });
+ }
+ });
+ break;
+ case '/logout/':
+ if (request.method !== 'POST') {
+ response.writeOnlyHead(httpStatus.METHOD_NOT_ALLOWED);
+ return;
+ }
+ if (session) {
+ delete idToSessionMap[sessionId];
+ cookies.set('sessionId');
+ }
+ response.writeOnlyHead(httpStatus.SEE_OTHER, { 'Location': '/' });
+ break;
default: {
if (gamePathParse = /^\/game\/([^\/]+)\/$/.exec(urlParse.pathname)) {
if (request.method !== 'GET') {

0 comments on commit 1495434

Please sign in to comment.