diff --git a/lib/primary.js b/lib/primary.js index 55861ece63a6614d02107bf4b4927705d3031e83..5e7f481d43acbc617408affb594cadad418190d4 100644 --- a/lib/primary.js +++ b/lib/primary.js @@ -186,7 +186,7 @@ exports.checkSupport = function(domain, cb, delegates) { if (typeof domain !== 'string' || !domain.length) { return process.nextTick(function() { cb("invalid domain"); }); } - getWellKnown(domain, delegates, function (err, body, domain, delegates) { + getWellKnown(domain, delegates, function (err, body, domain, cbdelegates) { if (err) { logger.debug(err); return cb(err); @@ -196,7 +196,7 @@ exports.checkSupport = function(domain, cb, delegates) { } try { - var r = parseWellKnownBody(body, domain, delegates, function (err, r) { + var r = parseWellKnownBody(body, domain, cbdelegates, function (err, r) { if (err) { logger.debug(err); cb(err); @@ -226,6 +226,18 @@ exports.getPublicKey = function(domain, cb) { }); }; +// Does emailDomain actual delegate to the issuingDomain? +exports.delegatesAuthority = function (emailDomain, issuingDomain, cb) { + exports.checkSupport(emailDomain, function(err, urls, publicKey) { + // Check http or https://{issuingDomain}/some/sign_in_path + if (! err && urls && urls.auth && + urls.auth.indexOf('://' + issuingDomain + '/') !== -1) { + cb(true); + } + cb(false); + }); +} + // verify an assertion generated to authenticate to browserid exports.verifyAssertion = function(assertion, cb) { if (config.get('disable_primary_support')) { diff --git a/lib/verifier/certassertion.js b/lib/verifier/certassertion.js index b437fe4f9abbc5ecbcb38b66ae71e21557ceda50..babd1eae4e55096bad33b0016b243c876ff2a521 100644 --- a/lib/verifier/certassertion.js +++ b/lib/verifier/certassertion.js @@ -134,20 +134,30 @@ function verify(assertion, audience, successCB, errorCB) { return errorCB("audience mismatch: " + err); } - // verify that the issuer is the same as the email domain - // NOTE: for "delegation of authority" support we'll need to make this check - // more sophisticated + var token_verify = function (tok, pk, principal, ultimateIssuer) { + if (tok.verify(pk)) { + return successCB(principal.email, tok.audience, tok.expires, ultimateIssuer); + } else { + return errorCB("verification failure"); + } + } + + // verify that the issuer is the same as the email domain or + // that the email's domain delegated authority to the issuer var domainFromEmail = principal.email.replace(/^.*@/, ''); + if (ultimateIssuer != HOSTNAME && ultimateIssuer !== domainFromEmail) { - return errorCB("issuer issue '" + ultimateIssuer + "' may not speak for emails from '" - + domainFromEmail + "'"); - } - - if (tok.verify(pk)) { - successCB(principal.email, tok.audience, tok.expires, ultimateIssuer); + primary.delegatesAuthority(domainFromEmail, ultimateIssuer, function (delegated) { + if (delegated) { + return token_verify(tok, pk, principal, ultimateIssuer); + } else { + return errorCB("issuer issue '" + ultimateIssuer + "' may not speak for emails from '" + + domainFromEmail + "'"); + } + }); } else { - errorCB("verification failure"); + return token_verify(tok, pk, principal, ultimateIssuer); } }, errorCB); }; diff --git a/lib/wsapi/address_info.js b/lib/wsapi/address_info.js index 68284f964fd8f325adabbf53c91d3a75e4201b4b..c40a4ff79967290ba7be2347f4d3251cbdeceefd 100644 --- a/lib/wsapi/address_info.js +++ b/lib/wsapi/address_info.js @@ -31,7 +31,7 @@ exports.process = function(req, resp) { return httputils.badRequest(resp, "invalid email address"); } - primary.checkSupport(m[1], function(err, urls, publicKey) { + primary.checkSupport(m[1], function(err, urls, publicKey, delegates) { if (err) { logger.warn('error checking "' + m[1] + '" for primary support: ' + err); return httputils.serverError(resp, "can't check email address");