Skip to content

Commit 3af7fad

Browse files
Silently migrate from OpenID to OAuth2 authentication for Google. Closes #484.
1 parent 7c9f9d9 commit 3af7fad

5 files changed

Lines changed: 58 additions & 11 deletions

File tree

controllers/auth.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var User = require('../models/user').User;
1515
var verifyPassport = require('../libs/passportVerify').verify;
1616
var cleanFilename = require('../libs/helpers').cleanFilename;
1717
var addSession = require('../libs/modifySessions').add;
18+
var jwt = require('jwt-simple');
1819

1920
// Unused but removing it breaks passport
2021
passport.serializeUser(function (aUser, aDone) {
@@ -43,16 +44,22 @@ exports.auth = function (aReq, aRes, aNext) {
4344
var authedUser = aReq.session.user;
4445
var strategy = aReq.body.auth || aReq.params.strategy;
4546
var username = aReq.body.username || aReq.session.username;
47+
var authOpts = { failureRedirect: '/register?stratfail' };
4648

4749
function auth() {
48-
var authenticate = passport.authenticate(strategy, { failureRedirect: '/register?stratfail' });
50+
var authenticate = null;
51+
52+
if (strategy === 'google') {
53+
authOpts.scope = ['https://www.googleapis.com/auth/userinfo.profile'];
54+
}
55+
authenticate = passport.authenticate(strategy, authOpts);
4956

5057
// Just in case some dumbass tries a bad /auth/* url
5158
if (!strategyInstances[strategy]) {
5259
return aNext();
5360
}
5461

55-
authenticate(aReq, aRes);
62+
authenticate(aReq, aRes, aNext);
5663
}
5764

5865
// Allow a logged in user to add a new strategy
@@ -128,6 +135,14 @@ exports.callback = function (aReq, aRes, aNext) {
128135
strategyInstance._verify = function (aId, aDone) {
129136
verifyPassport(aId, strategy, username, aReq.session.user, aDone);
130137
};
138+
} else if (strategy === 'google') { // OpenID to OAuth2 migration
139+
strategyInstance._verify =
140+
function(aAccessToken, aRefreshToken, aParams, aProfile, aDone) {
141+
var openIdId = jwt.decode(aParams.id_token, null, true).openid_id;
142+
var oAuthId = aProfile.id;
143+
144+
verifyPassport([openIdId, oAuthId], strategy, username, aReq.session.user, aDone);
145+
};
131146
} else {
132147
strategyInstance._verify =
133148
function (aToken, aRefreshOrSecretToken, aProfile, aDone) {

controllers/strategies.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
},
2626
"google": {
2727
"name": "Google",
28-
"oauth": false
28+
"oauth": true
2929
},
3030
"imgur": {
3131
"name": "Imgur",

libs/passportLoader.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ exports.strategyInstances = nil();
2121
// This will load a single passport
2222
// Notice it is general so it can load any passport strategy
2323
exports.loadPassport = function (aStrategy) {
24-
var requireStr = 'passport-' + aStrategy.name;
25-
var PassportStrategy = require(requireStr).Strategy;
24+
var requireStr = 'passport-' + aStrategy.name
25+
+ (aStrategy.name === 'google' ? '-oauth' : '');
26+
var PassportStrategy = require(requireStr)[
27+
aStrategy.name === 'google' ? 'OAuth2Strategy' : 'Strategy'];
2628
var instance = null;
29+
var authParams = null;
2730

2831
if (aStrategy.openid) {
2932
instance = new PassportStrategy(
@@ -50,6 +53,15 @@ exports.loadPassport = function (aStrategy) {
5053
);
5154
}
5255

56+
if (aStrategy.name === 'google') {
57+
authParams = instance.authorizationParams;
58+
instance.authorizationParams = function() {
59+
var val = authParams.apply(this, arguments);
60+
val['openid.realm'] = AUTH_CALLBACK_BASE_URL + '/';
61+
return val;
62+
};
63+
}
64+
5365
exports.strategyInstances[aStrategy.name] = instance;
5466
passport.use(instance);
5567
};

libs/passportVerify.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,18 @@ var userRoles = require('../models/userRoles.json');
1616
exports.verify = function (aId, aStrategy, aUsername, aLoggedIn, aDone) {
1717
var shasum = crypto.createHash('sha256');
1818
var digest = null;
19+
var query = {};
20+
var aIds = [];
1921

20-
// We only keep plaintext ids for GH since that's all we need
21-
if (aStrategy === 'github') {
22+
if (aId instanceof Array) {
23+
aIds = aId.map(function (aId) {
24+
var shasum = crypto.createHash('sha256');
25+
shasum.update(String(aId));
26+
return shasum.digest('hex');
27+
});
28+
query.auths = { '$in': aIds };
29+
} else if (aStrategy === 'github') {
30+
// We only keep plaintext ids for GH since that's all we need
2231
digest = aId;
2332
} else {
2433
// Having these ids would allow us to do things with the user's
@@ -27,9 +36,13 @@ exports.verify = function (aId, aStrategy, aUsername, aLoggedIn, aDone) {
2736
digest = shasum.digest('hex');
2837
}
2938

30-
findDeadorAlive(User, { 'auths': digest }, true,
39+
if (!query.auths) {
40+
query.auths = digest;
41+
}
42+
43+
findDeadorAlive(User, query, true,
3144
function (aAlive, aUser, aRemoved) {
32-
var pos = aUser ? aUser.auths.indexOf(digest) : -1;
45+
var pos = aUser ? aUser.auths.indexOf(digest || aIds[0]) : -1;
3346
if (aRemoved) { aDone(null, false, 'user was removed'); }
3447

3548
if (!aUser) {
@@ -69,6 +82,12 @@ exports.verify = function (aId, aStrategy, aUsername, aLoggedIn, aDone) {
6982
aUser.save(function (aErr, aUser) {
7083
return aDone(aErr, aUser);
7184
});
85+
} else if (aIds.length > 0 && pos > -1) {
86+
// Migrate from OpenID to OAuth
87+
aUser.auths[pos] = aIds[1];
88+
aUser.save(function (aErr, aUser) {
89+
return aDone(aErr, aUser);
90+
});
7291
} else {
7392
// The user was authenticated
7493
return aDone(null, aUser);

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"passport-flickr": "0.2.0",
3737
"passport-foursquare": "1.0.0",
3838
"passport-github": "0.1.5",
39-
"passport-google": "0.3.0",
39+
"passport-google-oauth": "0.1.5",
4040
"passport-imgur": "0.0.2",
4141
"passport-instagram": "0.1.2",
4242
"passport-linkedin": "0.1.3",
@@ -52,7 +52,8 @@
5252
"select2": "3.5.2-browserify",
5353
"select2-bootstrap-css": "1.4.6",
5454
"serve-favicon": "2.2.0",
55-
"underscore": "1.7.0"
55+
"underscore": "1.7.0",
56+
"jwt-simple": "0.2.0"
5657
},
5758
"repository": {
5859
"type": "git",

0 commit comments

Comments
 (0)