Skip to content

Commit 61aa5a8

Browse files
flovilmartdrew-gross
authored andcommitted
Let auth data be updated on login (#2219)
* Let user update authData token upon login * Adds tests that ensures linked authData isnt overriden * fixes focused testing problem
1 parent 4e9e817 commit 61aa5a8

File tree

3 files changed

+122
-11
lines changed

3 files changed

+122
-11
lines changed

spec/ParseUser.spec.js

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -907,13 +907,11 @@ describe('Parse.User testing', () => {
907907
}));
908908
});
909909

910-
// Note that this mocks out client-side Facebook action rather than
911-
// server-side.
912-
var getMockFacebookProvider = function() {
910+
var getMockFacebookProviderWithIdToken = function(id, token) {
913911
return {
914912
authData: {
915-
id: "8675309",
916-
access_token: "jenny",
913+
id: id,
914+
access_token: token,
917915
expiration_date: new Date().toJSON(),
918916
},
919917
shouldError: false,
@@ -951,6 +949,12 @@ describe('Parse.User testing', () => {
951949
this.restoreAuthentication(null);
952950
}
953951
};
952+
}
953+
954+
// Note that this mocks out client-side Facebook action rather than
955+
// server-side.
956+
var getMockFacebookProvider = function() {
957+
return getMockFacebookProviderWithIdToken('8675309', 'jenny');
954958
};
955959

956960
var getMockMyOauthProvider = function() {
@@ -1025,6 +1029,40 @@ describe('Parse.User testing', () => {
10251029
});
10261030
});
10271031

1032+
it_exclude_dbs(['postgres'])("log in with provider and update token", (done) => {
1033+
var provider = getMockFacebookProvider();
1034+
var secondProvider = getMockFacebookProviderWithIdToken('8675309', 'jenny_valid_token');
1035+
var errorHandler = function(err) {
1036+
fail('should not fail');
1037+
done();
1038+
}
1039+
Parse.User._registerAuthenticationProvider(provider);
1040+
Parse.User._logInWith("facebook", {
1041+
success: (model) => {
1042+
Parse.User._registerAuthenticationProvider(secondProvider);
1043+
return Parse.User.logOut().then(() => {
1044+
Parse.User._logInWith("facebook", {
1045+
success: (model) => {
1046+
expect(secondProvider.synchronizedAuthToken).toEqual('jenny_valid_token');
1047+
// Make sure we can login with the new token again
1048+
Parse.User.logOut().then(() => {
1049+
Parse.User._logInWith("facebook", {
1050+
success: done,
1051+
error: errorHandler
1052+
});
1053+
});
1054+
},
1055+
error: errorHandler
1056+
});
1057+
})
1058+
},
1059+
error: errorHandler
1060+
}).catch((err) => {
1061+
errorHandler(err);
1062+
done();
1063+
});
1064+
});
1065+
10281066
it_exclude_dbs(['postgres'])('returns authData when authed and logged in with provider (regression test for #1498)', done => {
10291067
Parse.Object.enableSingleInstance();
10301068
let provider = getMockFacebookProvider();
@@ -1428,6 +1466,47 @@ describe('Parse.User testing', () => {
14281466
});
14291467
});
14301468

1469+
it_exclude_dbs(['postgres'])("link multiple providers and updates token", (done) => {
1470+
var provider = getMockFacebookProvider();
1471+
var secondProvider = getMockFacebookProviderWithIdToken('8675309', 'jenny_valid_token');
1472+
1473+
var errorHandler = function(model, error) {
1474+
console.error(error);
1475+
fail('Should not fail');
1476+
done();
1477+
}
1478+
var mockProvider = getMockMyOauthProvider();
1479+
Parse.User._registerAuthenticationProvider(provider);
1480+
Parse.User._logInWith("facebook", {
1481+
success: function(model) {
1482+
Parse.User._registerAuthenticationProvider(mockProvider);
1483+
let objectId = model.id;
1484+
model._linkWith("myoauth", {
1485+
success: function(model) {
1486+
Parse.User._registerAuthenticationProvider(secondProvider);
1487+
Parse.User.logOut().then(() => {
1488+
return Parse.User._logInWith("facebook", {
1489+
success: () => {
1490+
Parse.User.logOut().then(() => {
1491+
return Parse.User._logInWith("myoauth", {
1492+
success: (user) => {
1493+
expect(user.id).toBe(objectId);
1494+
done();
1495+
}
1496+
})
1497+
})
1498+
},
1499+
error: errorHandler
1500+
});
1501+
})
1502+
},
1503+
error: errorHandler
1504+
})
1505+
},
1506+
error: errorHandler
1507+
});
1508+
});
1509+
14311510
it_exclude_dbs(['postgres'])("link multiple providers and update token", (done) => {
14321511
var provider = getMockFacebookProvider();
14331512
var mockProvider = getMockMyOauthProvider();

spec/helper.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,17 @@ function range(n) {
281281
return answer;
282282
}
283283

284-
function mockFacebook() {
284+
function mockFacebookAuthenticator(id, token) {
285285
var facebook = {};
286286
facebook.validateAuthData = function(authData) {
287-
if (authData.id === '8675309' && authData.access_token === 'jenny') {
287+
if (authData.id === id && authData.access_token.startsWith(token)) {
288288
return Promise.resolve();
289289
} else {
290290
throw undefined;
291291
}
292292
};
293293
facebook.validateAppId = function(appId, authData) {
294-
if (authData.access_token === 'jenny') {
294+
if (authData.access_token.startsWith(token)) {
295295
return Promise.resolve();
296296
} else {
297297
throw undefined;
@@ -300,6 +300,10 @@ function mockFacebook() {
300300
return facebook;
301301
}
302302

303+
function mockFacebook() {
304+
return mockFacebookAuthenticator('8675309', 'jenny');
305+
}
306+
303307

304308

305309
// This is polluting, but, it makes it way easier to directly port old tests.
@@ -320,6 +324,7 @@ global.jequal = jequal;
320324
global.range = range;
321325
global.reconfigureServer = reconfigureServer;
322326
global.defaultConfiguration = defaultConfiguration;
327+
global.mockFacebookAuthenticator = mockFacebookAuthenticator;
323328

324329
global.it_exclude_dbs = excluded => {
325330
if (excluded.includes(process.env.PARSE_SERVER_TEST_DB)) {

src/RestWrite.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,14 +290,41 @@ RestWrite.prototype.handleAuthData = function(authData) {
290290
if (results.length > 0) {
291291
if (!this.query) {
292292
// Login with auth data
293-
// Short circuit
294293
delete results[0].password;
294+
let userResult = results[0];
295+
295296
// need to set the objectId first otherwise location has trailing undefined
296-
this.data.objectId = results[0].objectId;
297+
this.data.objectId = userResult.objectId;
298+
299+
// Determine if authData was updated
300+
let mutatedAuthData = {};
301+
Object.keys(authData).forEach((provider) => {
302+
let providerData = authData[provider];
303+
let userAuthData = userResult.authData[provider];
304+
if (!_.isEqual(providerData, userAuthData)) {
305+
mutatedAuthData[provider] = providerData;
306+
}
307+
});
308+
297309
this.response = {
298-
response: results[0],
310+
response: userResult,
299311
location: this.location()
300312
};
313+
314+
// We have authData that is updated on login
315+
// that can happen when token are refreshed,
316+
// We should update the token and let the user in
317+
if (Object.keys(mutatedAuthData).length > 0) {
318+
// Assign the new authData in the response
319+
Object.keys(mutatedAuthData).forEach((provider) => {
320+
this.response.response.authData[provider] = mutatedAuthData[provider];
321+
});
322+
// Run the DB update directly, as 'master'
323+
// Just update the authData part
324+
return this.config.database.update(this.className, {objectId: this.data.objectId}, {authData: mutatedAuthData}, {});
325+
}
326+
return;
327+
301328
} else if (this.query && this.query.objectId) {
302329
// Trying to update auth data but users
303330
// are different

0 commit comments

Comments
 (0)