Skip to content
This repository has been archived by the owner on Feb 20, 2019. It is now read-only.

Commit

Permalink
Missed merge issue, pushing latest code
Browse files Browse the repository at this point in the history
  • Loading branch information
ozten committed Oct 2, 2013
1 parent 92bb1a4 commit 22d78db
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 70 deletions.
174 changes: 118 additions & 56 deletions server/lib/openid-tool.js
Expand Up @@ -2,64 +2,126 @@
* 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/. */

const email = require('./validation/email');
const pinCode = require('./pin_code'),
config = require('../lib/configuration'),
YahooStrategy = require('passport-yahoo').Strategy,
logger = require('./logging').logger,
oidTool = require('./openid-tool'),
passport = require('passport'),
session = require('./session_context'),
statsd = require('./statsd'),
util = require('util');

function validParams(params) {
/* jshint maxcomplexity:15 */
const RETURN_PATH = '/auth/yahoo/return';

// Find all AXSchema email types
var emailTypes = [];
var
baseUrl = util.format("https://%s", config.get('issuer')),
return_url = util.format("%s%s", baseUrl, RETURN_PATH),
realm = util.format("%s/", baseUrl);

console.log('boo ya');

Object.keys(params).forEach(function (key) {
if (params[key] === 'http://axschema.org/contact/email') {
emailTypes.push(key);
}
// Register the YahooStrategy with Passport.
var strategy = new YahooStrategy({
returnURL: return_url,
realm: realm,
stateless: true
},
function(identifier, profile, done) {
return done(null, profile);
});

console.log('boo ya 2');
// We should only have one potential email type to inspect.
if (emailTypes.length !== 1) { return false; }

// That type should be under a key formatted 'openid.NAMESPACE.type.TYPENAME'
// If the regex matches, it returns [match, NAMESPACE, TYPENAME]
var parts = emailTypes[0].match(/^openid\.([^\.]+)\.type\.([^\.]+)$/);
if (!parts || parts.length !== 3) { return false; }

var namespace = parts[1];
var typename = parts[2];

console.log('boo ya 3');
// The associated value should exist at openid.NAMESPACE.value.TYPENAME.
// It should be a valid email address.
var emailValuePath = 'openid.' + namespace + '.value.' + typename;
console.log(emailValuePath, params[emailValuePath]);
if (!email(params[emailValuePath])) { return false; }

// NAMESPACE must be registered under openid.ns.NAMESPACE
var nsPath = 'openid.ns.' + namespace;

console.log(nsPath, params[nsPath]);
if (params[nsPath] !== 'http://openid.net/srv/ax/1.0') { return false; }
console.log('boo ya 4');
// The namespace, email type, and email value must all be signed
var signed = (params['openid.signed'] || '').split(',');
if (signed.indexOf('ns.' + namespace) === -1) { return false; }
if (signed.indexOf(namespace + '.value.' + typename) === -1) { return false; }
if (signed.indexOf(namespace + '.type.' + typename) === -1) { return false; }

// Lastly, because this is only a Gmail bridge, hardcode the OpenID Endpoint
var yahooEndpoint = 'https://open.login.yahooapis.com/openid/op/auth';
if (params['openid.op_endpoint'] !== yahooEndpoint) { return false; }
if (signed.indexOf('op_endpoint') === -1 ) { return false; }
console.log('boo ya 5');
// ...and make sure the Claimed ID is a Yahoo one.
var yahooAccountRegex = /^https:\/\/me.yahoo.com\/a\//;
if (!yahooAccountRegex.test(params['openid.claimed_id'])) { return false; }
if (signed.indexOf('claimed_id') === -1 ) { return false; }
console.log('boo ya 6');
return true;
}

exports.validParams = validParams;
passport.use(strategy);

exports.init = function(app) {
app.use(passport.initialize());
app.use(passport.session());
};

exports.views = function(app) {
// GET /auth/yahoo/return
app.get(RETURN_PATH,
function(req, res, next) {
// Bug#920301 detect MITM which would have removed email value from
// the signed components.
if (! oidTool.validParams(req.query)) {
statsd.increment('warn.routes.auth.yahoo.return.mitm');
logger.error('MITM detected');
throw new Error('email not signed');
}
next();
},
passport.authenticate('yahoo', { failureRedirect: '/cancel' }),
function(req, res) {
// Are we who we said we are?
var start = new Date(),
metric = 'routes.auth.yahoo.return',
match = false;

statsd.increment('routes.auth.yahoo.return.get');

// keep track of emails reported by yahoo for logging in case
// of failure
var openid_emails = [];

if (req.user && req.user.emails) {
var rawClaimedEmail = session.getClaimedEmail(req) || "";
var claimedEmail = rawClaimedEmail.toLowerCase();
req.user.emails.forEach(function(email_obj, i) {

// add the email to the list of all emails reported by
// yahoo for logging in case of failure
openid_emails.push(email_obj.value);

if (match) { return; }

if (! email_obj.value) {
statsd.increment('warn.routes.auth.yahoo.return.no_email_value');
logger.warn("Yahoo should have had list of emails with a value property on each " + email_obj);
}
var email = email_obj.value.toLowerCase();
if (! match) {
if (email === claimedEmail ||
pinCode.wasValidated(claimedEmail, req)) {

if (email === claimedEmail) {
statsd.increment('routes.auth.yahoo.return.email_matched');
} else {
// With a previously PIN verified claimed email,
// it is okay to treat it like the user's current email
email = claimedEmail;
statsd.increment('routes.auth.yahoo.return.emails_linked');
}

var redirect_url = session.getBidUrl(baseUrl, req);
match = true;

session.clearClaimedEmail(req);
session.clearBidUrl(req);

session.setCurrentUser(req, email);
res.redirect(redirect_url);
statsd.timing(metric, new Date() - start);
return;
}
}
}); //forEach emails
} else {
logger.warn("Yahoo should have had user and user.emails" + req.user);
statsd.increment('warn.routes.auth.yahoo.return.no_emails');
res.redirect(session.getErrorUrl(baseUrl, req));
statsd.timing(metric, new Date() - start);
}

if (!match) {
statsd.increment('warn.routes.auth.yahoo.return.no_emails_matched');
logger.error('No email matched...');
// We store these wrong email addresses (okay address... Yahoo only returns
// one) under "mismatchedEmail". We will use this later to either:
// * Inform the user there is an auth error a@yahoo.com versus b@yahoo.com
// * Let the user do email verification loop for a@yahoo.com
session.setMismatchEmail(openid_emails.join(", "), req);
res.redirect(session.getMismatchUrl(baseUrl, req));
statsd.timing(metric, new Date() - start);
}

});
};
24 changes: 10 additions & 14 deletions server/lib/passport_yahoo.js
Expand Up @@ -13,7 +13,6 @@ statsd = require('./statsd'),
util = require('util');

const RETURN_PATH = '/auth/yahoo/return';
const OPENID_EMAIL_PARAM = 'ax.value.email';

var
baseUrl = util.format("https://%s", config.get('issuer')),
Expand All @@ -40,24 +39,23 @@ exports.init = function(app) {
exports.views = function(app) {
// GET /auth/yahoo/return
app.get(RETURN_PATH,
function(req, res, next) {
// Bug#920301 detect MITM which would have removed email value from
// the signed components.
if (! oidTool.validParams(req.query)) {
statsd.increment('warn.routes.auth.yahoo.return.mitm');
logger.error('MITM detected');
throw new Error('email not signed');
}
next();
},
passport.authenticate('yahoo', { failureRedirect: '/cancel' }),
function(req, res) {
// Are we who we said we are?
var start = new Date(),
metric = 'routes.auth.yahoo.return',
match = false;

// Bug#920301 detect MITM which would have removed email value from
// the signed components.
var signed = req.query['openid.signed'] || '';

if (signed.split(',').indexOf(OPENID_EMAIL_PARAM) === -1 ||
! oidTool.validParams(req.query)) {
statsd.increment('warn.routes.auth.yahoo.return.mitm');
logger.error('MITM detected' + signed);
throw new Error('email not signed');
}

statsd.increment('routes.auth.yahoo.return.get');

// keep track of emails reported by yahoo for logging in case
Expand All @@ -81,14 +79,12 @@ exports.views = function(app) {
}
var email = email_obj.value.toLowerCase();
if (! match) {

if (email === claimedEmail ||
pinCode.wasValidated(claimedEmail, req)) {

if (email === claimedEmail) {
statsd.increment('routes.auth.yahoo.return.email_matched');
} else {

// With a previously PIN verified claimed email,
// it is okay to treat it like the user's current email
email = claimedEmail;
Expand Down

0 comments on commit 22d78db

Please sign in to comment.