Skip to content

Commit 7d78732

Browse files
committed
Merge pull request #952 from ParsePlatform/flovilmart.OAuthImprovements
AuthData logic refactor
2 parents 2c991a4 + daad05a commit 7d78732

18 files changed

+389
-179
lines changed

spec/OAuth.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
var OAuth = require("../src/oauth/OAuth1Client");
1+
var OAuth = require("../src/authDataManager/OAuth1Client");
22
var request = require('request');
33

44
describe('OAuth', function() {
@@ -138,7 +138,7 @@ describe('OAuth', function() {
138138

139139
["facebook", "github", "instagram", "google", "linkedin", "meetup", "twitter"].map(function(providerName){
140140
it("Should validate structure of "+providerName, (done) => {
141-
var provider = require("../src/oauth/"+providerName);
141+
var provider = require("../src/authDataManager/"+providerName);
142142
jequal(typeof provider.validateAuthData, "function");
143143
jequal(typeof provider.validateAppId, "function");
144144
jequal(provider.validateAuthData({}, {}).constructor, Promise.prototype.constructor);

spec/ParseUser.spec.js

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,50 @@ describe('Parse.User testing', () => {
905905
}
906906
};
907907
};
908+
909+
var getMockMyOauthProvider = function() {
910+
return {
911+
authData: {
912+
id: "12345",
913+
access_token: "12345",
914+
expiration_date: new Date().toJSON(),
915+
},
916+
shouldError: false,
917+
loggedOut: false,
918+
synchronizedUserId: null,
919+
synchronizedAuthToken: null,
920+
synchronizedExpiration: null,
921+
922+
authenticate: function(options) {
923+
if (this.shouldError) {
924+
options.error(this, "An error occurred");
925+
} else if (this.shouldCancel) {
926+
options.error(this, null);
927+
} else {
928+
options.success(this, this.authData);
929+
}
930+
},
931+
restoreAuthentication: function(authData) {
932+
if (!authData) {
933+
this.synchronizedUserId = null;
934+
this.synchronizedAuthToken = null;
935+
this.synchronizedExpiration = null;
936+
return true;
937+
}
938+
this.synchronizedUserId = authData.id;
939+
this.synchronizedAuthToken = authData.access_token;
940+
this.synchronizedExpiration = authData.expiration_date;
941+
return true;
942+
},
943+
getAuthType: function() {
944+
return "myoauth";
945+
},
946+
deauthenticate: function() {
947+
this.loggedOut = true;
948+
this.restoreAuthentication(null);
949+
}
950+
};
951+
};
908952

909953
var ExtendedUser = Parse.User.extend({
910954
extended: function() {
@@ -1285,6 +1329,151 @@ describe('Parse.User testing', () => {
12851329
}
12861330
});
12871331
});
1332+
1333+
it("link multiple providers", (done) => {
1334+
var provider = getMockFacebookProvider();
1335+
var mockProvider = getMockMyOauthProvider();
1336+
Parse.User._registerAuthenticationProvider(provider);
1337+
Parse.User._logInWith("facebook", {
1338+
success: function(model) {
1339+
ok(model instanceof Parse.User, "Model should be a Parse.User");
1340+
strictEqual(Parse.User.current(), model);
1341+
ok(model.extended(), "Should have used the subclass.");
1342+
strictEqual(provider.authData.id, provider.synchronizedUserId);
1343+
strictEqual(provider.authData.access_token, provider.synchronizedAuthToken);
1344+
strictEqual(provider.authData.expiration_date, provider.synchronizedExpiration);
1345+
ok(model._isLinked("facebook"), "User should be linked to facebook");
1346+
Parse.User._registerAuthenticationProvider(mockProvider);
1347+
let objectId = model.id;
1348+
model._linkWith("myoauth", {
1349+
success: function(model) {
1350+
expect(model.id).toEqual(objectId);
1351+
ok(model._isLinked("facebook"), "User should be linked to facebook");
1352+
ok(model._isLinked("myoauth"), "User should be linked to myoauth");
1353+
done();
1354+
},
1355+
error: function(error) {
1356+
console.error(error);
1357+
fail('SHould not fail');
1358+
done();
1359+
}
1360+
})
1361+
},
1362+
error: function(model, error) {
1363+
ok(false, "linking should have worked");
1364+
done();
1365+
}
1366+
});
1367+
});
1368+
1369+
it("link multiple providers and update token", (done) => {
1370+
var provider = getMockFacebookProvider();
1371+
var mockProvider = getMockMyOauthProvider();
1372+
Parse.User._registerAuthenticationProvider(provider);
1373+
Parse.User._logInWith("facebook", {
1374+
success: function(model) {
1375+
ok(model instanceof Parse.User, "Model should be a Parse.User");
1376+
strictEqual(Parse.User.current(), model);
1377+
ok(model.extended(), "Should have used the subclass.");
1378+
strictEqual(provider.authData.id, provider.synchronizedUserId);
1379+
strictEqual(provider.authData.access_token, provider.synchronizedAuthToken);
1380+
strictEqual(provider.authData.expiration_date, provider.synchronizedExpiration);
1381+
ok(model._isLinked("facebook"), "User should be linked to facebook");
1382+
Parse.User._registerAuthenticationProvider(mockProvider);
1383+
let objectId = model.id;
1384+
model._linkWith("myoauth", {
1385+
success: function(model) {
1386+
expect(model.id).toEqual(objectId);
1387+
ok(model._isLinked("facebook"), "User should be linked to facebook");
1388+
ok(model._isLinked("myoauth"), "User should be linked to myoauth");
1389+
model._linkWith("facebook", {
1390+
success: () => {
1391+
ok(model._isLinked("facebook"), "User should be linked to facebook");
1392+
ok(model._isLinked("myoauth"), "User should be linked to myoauth");
1393+
done();
1394+
},
1395+
error: () => {
1396+
fail('should link again');
1397+
done();
1398+
}
1399+
})
1400+
},
1401+
error: function(error) {
1402+
console.error(error);
1403+
fail('SHould not fail');
1404+
done();
1405+
}
1406+
})
1407+
},
1408+
error: function(model, error) {
1409+
ok(false, "linking should have worked");
1410+
done();
1411+
}
1412+
});
1413+
});
1414+
1415+
it('should fail linking with existing', (done) => {
1416+
var provider = getMockFacebookProvider();
1417+
Parse.User._registerAuthenticationProvider(provider);
1418+
Parse.User._logInWith("facebook", {
1419+
success: function(model) {
1420+
Parse.User.logOut().then(() => {
1421+
let user = new Parse.User();
1422+
user.setUsername('user');
1423+
user.setPassword('password');
1424+
return user.signUp().then(() => {
1425+
// try to link here
1426+
user._linkWith('facebook', {
1427+
success: () => {
1428+
fail('should not succeed');
1429+
done();
1430+
},
1431+
error: (err) => {
1432+
done();
1433+
}
1434+
});
1435+
});
1436+
});
1437+
}
1438+
});
1439+
});
1440+
1441+
it('should have authData in beforeSave and afterSave', (done) => {
1442+
1443+
Parse.Cloud.beforeSave('_User', (request, response) => {
1444+
let authData = request.object.get('authData');
1445+
expect(authData).not.toBeUndefined();
1446+
if (authData) {
1447+
expect(authData.facebook.id).toEqual('8675309');
1448+
expect(authData.facebook.access_token).toEqual('jenny');
1449+
} else {
1450+
fail('authData should be set');
1451+
}
1452+
response.success();
1453+
});
1454+
1455+
Parse.Cloud.afterSave('_User', (request, response) => {
1456+
let authData = request.object.get('authData');
1457+
expect(authData).not.toBeUndefined();
1458+
if (authData) {
1459+
expect(authData.facebook.id).toEqual('8675309');
1460+
expect(authData.facebook.access_token).toEqual('jenny');
1461+
} else {
1462+
fail('authData should be set');
1463+
}
1464+
response.success();
1465+
});
1466+
1467+
var provider = getMockFacebookProvider();
1468+
Parse.User._registerAuthenticationProvider(provider);
1469+
Parse.User._logInWith("facebook", {
1470+
success: function(model) {
1471+
Parse.Cloud._removeHook('Triggers', 'beforeSave', Parse.User.className);
1472+
Parse.Cloud._removeHook('Triggers', 'afterSave', Parse.User.className);
1473+
done();
1474+
}
1475+
});
1476+
});
12881477

12891478
it('set password then change password', (done) => {
12901479
Parse.User.signUp('bob', 'barker').then((bob) => {

spec/RestCreate.spec.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ describe('rest create', () => {
148148
});
149149

150150
it('handles no anonymous users config', (done) => {
151-
var NoAnnonConfig = Object.assign({}, config, {enableAnonymousUsers: false});
151+
var NoAnnonConfig = Object.assign({}, config);
152+
NoAnnonConfig.authDataManager.setEnableAnonymousUsers(false);
152153
var data1 = {
153154
authData: {
154155
anonymous: {
@@ -162,6 +163,7 @@ describe('rest create', () => {
162163
}, (err) => {
163164
expect(err.code).toEqual(Parse.Error.UNSUPPORTED_SERVICE);
164165
expect(err.message).toEqual('This authentication method is unsupported.');
166+
NoAnnonConfig.authDataManager.setEnableAnonymousUsers(true);
165167
done();
166168
})
167169
});

spec/helper.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000;
55
var cache = require('../src/cache').default;
66
var DatabaseAdapter = require('../src/DatabaseAdapter');
77
var express = require('express');
8-
var facebook = require('../src/oauth/facebook');
8+
var facebook = require('../src/authDataManager/facebook');
99
var ParseServer = require('../src/index').ParseServer;
10+
var path = require('path');
1011

1112
var databaseURI = process.env.DATABASE_URI;
1213
var cloudMain = process.env.CLOUD_CODE_MAIN || '../spec/cloud/main.js';
@@ -36,7 +37,7 @@ var defaultConfiguration = {
3637
oauth: { // Override the facebook provider
3738
facebook: mockFacebook(),
3839
myoauth: {
39-
module: "../spec/myoauth" // relative path as it's run from src
40+
module: path.resolve(__dirname, "myoauth") // relative path as it's run from src
4041
}
4142
}
4243
};

src/Config.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export class Config {
2020
this.restAPIKey = cacheInfo.restAPIKey;
2121
this.fileKey = cacheInfo.fileKey;
2222
this.facebookAppIds = cacheInfo.facebookAppIds;
23-
this.enableAnonymousUsers = cacheInfo.enableAnonymousUsers;
2423
this.allowClientClassCreation = cacheInfo.allowClientClassCreation;
2524
this.database = DatabaseAdapter.getDatabaseConnection(applicationId, cacheInfo.collectionPrefix);
2625

@@ -34,7 +33,7 @@ export class Config {
3433
this.pushController = cacheInfo.pushController;
3534
this.loggerController = cacheInfo.loggerController;
3635
this.userController = cacheInfo.userController;
37-
this.oauth = cacheInfo.oauth;
36+
this.authDataManager = cacheInfo.authDataManager;
3837
this.customPages = cacheInfo.customPages || {};
3938
this.mount = mount;
4039
}

0 commit comments

Comments
 (0)