Skip to content
Permalink
Browse files
handle non-standard (sloppy) fallback's ommision of auth + prov url's
  • Loading branch information
lloyd committed Nov 22, 2013
1 parent 847a836 commit 8b51f42e3ce28e3d296ca6c9c62b117432d52002
Showing with 93 additions and 22 deletions.
  1. +5 −1 bin/browserid-lookup.js
  2. +31 −13 lib/lookup.js
  3. +10 −8 lib/well-known-parser.js
  4. +47 −0 tests/sloppy-support-doc.js
@@ -24,6 +24,9 @@ var args = require('optimist')
.describe('f', 'domain of fallback IdP (often - login.persona.org)')
.alias('p', 'principalDomain')
.describe('p', 'specify the prinicpal email domain')
.alias('t', 'timeout')
.describe('t', 'HTTP timeout when fetching support documents')
.default('t', 8)
.alias('v', 'verbose')
.boolean('v')
.describe('v', 'print annoyinglymuch info about the discovery process')
@@ -40,7 +43,8 @@ var principalDomain = argv.p || domain;
var browserid = new BrowserID({
fallback: argv.fallback,
domain: domain,
principalDomain: principalDomain
principalDomain: principalDomain,
httpTimeout: argv.timeout
});

if (argv.v) {
@@ -5,7 +5,8 @@
var
https = require('https'),
wellKnownParser = require('./well-known-parser.js'),
urlparse = require('urlparse');
urlparse = require('urlparse'),
_ = require('underscore');

const WELL_KNOWN_URL = "/.well-known/browserid";

@@ -82,15 +83,24 @@ var fetchWellKnown = function (emitter, args, currentDomain, principalDomain, cl
handleResponse(null, res.statusCode, res.headers, body);
});
});
req.end();

// front-end shows xhr delay message after 10 sec; timeout sooner to avoid this
var reqTimeout = setTimeout(function() {
req.abort();
return cb('timeout trying to load well-known for ' + currentDomain);
}, args.httpTimeout * 1000);
req.on('response', function() { clearTimeout(reqTimeout); });
req.on('response', function() {
if (reqTimeout) {
clearTimeout(reqTimeout);
reqTimeout = null;
}
});
req.on('error', function(e) {
if (reqTimeout) { clearTimeout(reqTimeout); }
if (reqTimeout) {
clearTimeout(reqTimeout);
reqTimeout = null;
}
return cb(currentDomain + ' is not a browserid primary: ' + String(e));
});
}
@@ -115,7 +125,7 @@ function lookup(emitter, args, currentDomain, principalDomain, cb, delegationCha

var supportDoc;
try {
supportDoc = wellKnownParser(unparsedDoc);
supportDoc = wellKnownParser(unparsedDoc, args.allowURLOmission);
} catch (e) {
return cb("bad support document for '" + currentDomain + "': " + String(e));
}
@@ -157,20 +167,26 @@ function lookup(emitter, args, currentDomain, principalDomain, cb, delegationCha

var details = {
publicKey: supportDoc.publicKey,
urls: {
auth: url_prefix + supportDoc.paths.authentication,
prov: url_prefix + supportDoc.paths.provisioning
},
delegationChain: delegationChain,
authoritativeDomain: delegationChain[delegationChain.length - 1]
authoritativeDomain: delegationChain[delegationChain.length - 1],
urls: {
}
};

// validate the urls
// the well know parser has verified that urls are present unless
// allowURLOmission is specified. Now we'll validate urls are
// correct if they have been supplied
try {
urlparse(details.urls.auth).validate();
urlparse(details.urls.prov).validate();
if (supportDoc.paths.authentication) {
details.urls.auth = url_prefix + supportDoc.paths.authentication;
urlparse(details.urls.auth).validate();
}
if (supportDoc.paths.provisioning) {
details.urls.prov = url_prefix + supportDoc.paths.provisioning;
urlparse(details.urls.prov).validate();
}
} catch(e) {
return cb("invalid URLs in support document: " + e.toString());
return cb("invalid URL in support document: " + e.toString());
}

// success!
@@ -194,6 +210,8 @@ module.exports = function (browserid, args, cb) {
lookup(browserid, args, args.domain, args.principalDomain, function(err, details) {
// if there is an error, then let's try the fallback if configured
if (err && args.fallback) {
// compatibility code. Allow fallbacks to omit auth and prov urls
args = _.extend({}, args, { allowURLOmission: true });
return lookup(browserid, args, args.fallback, args.principalDomain, cb, [ args.fallback ]);
}
cb(err, details);
@@ -13,7 +13,7 @@ var jwcrypto = require("jwcrypto");
// * publicKey - a parsed representation of the public key
// * paths.authentication - the path to the 'authentication' html
// * paths.provisioning - the path to the 'provisioning' html
module.exports = function(doc) {
module.exports = function(doc, allowURLOmission) {
try {
doc = JSON.parse(doc);
} catch(e) {
@@ -61,13 +61,15 @@ module.exports = function(doc) {
publicKey: null
};

[ 'authentication', 'provisioning' ].forEach(function(requiredKey) {
if (typeof doc[requiredKey] !== 'string') {
throw "support document missing required '" + requiredKey + "'";
} else {
parsed.paths[requiredKey] = doc[requiredKey];
}
});
if (!allowURLOmission) {
[ 'authentication', 'provisioning' ].forEach(function(requiredKey) {
if (typeof doc[requiredKey] !== 'string') {
throw "support document missing required '" + requiredKey + "'";
} else {
parsed.paths[requiredKey] = doc[requiredKey];
}
});
}

if (!doc['public-key']) {
throw "support document missing required 'public-key'";
@@ -0,0 +1,47 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* global describe,it,require */

const
should = require('should'),
BrowserID = require('../'),
IdP = require('./lib/idp.js').IdP,
Client = require('./lib/client.js'),
jwcrypto = require('jwcrypto');

require("jwcrypto/lib/algs/rs");
require("jwcrypto/lib/algs/ds");

describe('conditionally support sloppy well-known documents', function() {
// a sloppy fallback that has no auth nor prov urls
var fallback = new IdP({
wellKnown: {
"public-key": {
"algorithm": "RS",
"n":"13847129683346859941264989674568093903817733347507886483659072610887035115410884319746624743249873208613096773517649937232300491784030920639144918224162068671400821902037583483041672764299306953103026060664680502797174343514269310587598551716299517313631315828939375461655862731946934365379077922079015460490916404855526919865126417791640455294879012843461329126172228137733279330910651237329531496694237928709223634994176813985784350468828176558279934807392490900567770727183145892059849913866957956369313527767655739421507886573261431996201380835691492402207640696740537706612595819413637640492969110348638013564489",
"e":"65537"
}
}
});

it('test idps should start up', function(done) {
fallback.start(done);
});

it('assertion for fallback vouched email should succeed', function(done) {
BrowserID.lookup({
insecureSSL: true,
httpTimeout: 0.1, // fail faster for prompt tests
domain: fallback.domain(),
allowURLOmission: true
}, function(err) {
done(err);
});
});

it('test idp should shut down', function(done) {
fallback.stop(done);
});
});

0 comments on commit 8b51f42

Please sign in to comment.