Generic OAuth provider support
Refactors facebook login into oauth generic login Adds additional oauth2 providers adds ability to pass an oAuth validator in the config Adds Twitter validation support + OAuth 1 client Support auth_token instead of access_token for twitter Improves code coverage of OAuth Adds validation of oauth provider structures Better coverage of the OAuth spec 100% coverage of OAuth1.js Adds passing auth_token_secret for Twitter auth. Refactors auth validation methods to include authData parameter - Adds ability to extens oauth validator through configuration - Adds ability to extend oauth validator through external module (file or package) - Adds more tests - Adds tests to login with custom auth provider Adds more tests for REST API fixes twitter auth_token f
This commit is contained in:
@@ -9,7 +9,7 @@ var cache = require('./cache');
|
||||
var Config = require('./Config');
|
||||
var cryptoUtils = require('./cryptoUtils');
|
||||
var passwordCrypto = require('./password');
|
||||
var facebook = require('./facebook');
|
||||
var oauth = require("./oauth");
|
||||
var Parse = require('parse/node');
|
||||
var triggers = require('./triggers');
|
||||
|
||||
@@ -147,19 +147,26 @@ RestWrite.prototype.validateAuthData = function() {
|
||||
return;
|
||||
}
|
||||
|
||||
var facebookData = this.data.authData.facebook;
|
||||
var authData = this.data.authData;
|
||||
var anonData = this.data.authData.anonymous;
|
||||
|
||||
|
||||
if (this.config.enableAnonymousUsers === true && (anonData === null ||
|
||||
(anonData && anonData.id))) {
|
||||
return this.handleAnonymousAuthData();
|
||||
} else if (facebookData === null ||
|
||||
(facebookData && facebookData.id && facebookData.access_token)) {
|
||||
return this.handleFacebookAuthData();
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.UNSUPPORTED_SERVICE,
|
||||
'This authentication method is unsupported.');
|
||||
}
|
||||
|
||||
// Not anon, try other providers
|
||||
var providers = Object.keys(authData);
|
||||
if (!anonData && providers.length == 1) {
|
||||
var provider = providers[0];
|
||||
var providerAuthData = authData[provider];
|
||||
var hasToken = (providerAuthData && providerAuthData.id);
|
||||
if (providerAuthData === null || hasToken) {
|
||||
return this.handleOAuthAuthData(provider);
|
||||
}
|
||||
}
|
||||
throw new Parse.Error(Parse.Error.UNSUPPORTED_SERVICE,
|
||||
'This authentication method is unsupported.');
|
||||
};
|
||||
|
||||
RestWrite.prototype.handleAnonymousAuthData = function() {
|
||||
@@ -208,27 +215,71 @@ RestWrite.prototype.handleAnonymousAuthData = function() {
|
||||
|
||||
};
|
||||
|
||||
RestWrite.prototype.handleFacebookAuthData = function() {
|
||||
var facebookData = this.data.authData.facebook;
|
||||
if (facebookData === null && this.query) {
|
||||
// We are unlinking from Facebook.
|
||||
this.data._auth_data_facebook = null;
|
||||
RestWrite.prototype.handleOAuthAuthData = function(provider) {
|
||||
var authData = this.data.authData[provider];
|
||||
|
||||
if (authData === null && this.query) {
|
||||
// We are unlinking from the provider.
|
||||
this.data["_auth_data_" + provider ] = null;
|
||||
return;
|
||||
}
|
||||
|
||||
return facebook.validateUserId(facebookData.id,
|
||||
facebookData.access_token)
|
||||
var appIds;
|
||||
var oauthOptions = this.config.oauth[provider];
|
||||
if (oauthOptions) {
|
||||
appIds = oauthOptions.appIds;
|
||||
} else if (provider == "facebook") {
|
||||
appIds = this.config.facebookAppIds;
|
||||
}
|
||||
|
||||
var validateAuthData;
|
||||
var validateAppId;
|
||||
|
||||
|
||||
if (oauth[provider]) {
|
||||
validateAuthData = oauth[provider].validateAuthData;
|
||||
validateAppId = oauth[provider].validateAppId;
|
||||
}
|
||||
|
||||
// Try the configuration methods
|
||||
if (oauthOptions) {
|
||||
if (oauthOptions.module) {
|
||||
validateAuthData = require(oauthOptions.module).validateAuthData;
|
||||
validateAppId = require(oauthOptions.module).validateAppId;
|
||||
};
|
||||
|
||||
if (oauthOptions.validateAuthData) {
|
||||
validateAuthData = oauthOptions.validateAuthData;
|
||||
}
|
||||
if (oauthOptions.validateAppId) {
|
||||
validateAppId = oauthOptions.validateAppId;
|
||||
}
|
||||
}
|
||||
// try the custom provider first, fallback on the oauth implementation
|
||||
|
||||
if (!validateAuthData || !validateAppId) {
|
||||
return false;
|
||||
};
|
||||
|
||||
return validateAuthData(authData, oauthOptions)
|
||||
.then(() => {
|
||||
return facebook.validateAppId(this.config.facebookAppIds,
|
||||
facebookData.access_token);
|
||||
if (appIds && typeof validateAppId === "function") {
|
||||
return validateAppId(appIds, authData, oauthOptions);
|
||||
}
|
||||
|
||||
// No validation required by the developer
|
||||
return Promise.resolve();
|
||||
|
||||
}).then(() => {
|
||||
// Check if this user already exists
|
||||
// TODO: does this handle re-linking correctly?
|
||||
var query = {};
|
||||
query['authData.' + provider + '.id'] = authData.id;
|
||||
return this.config.database.find(
|
||||
this.className,
|
||||
{'authData.facebook.id': facebookData.id}, {});
|
||||
query, {});
|
||||
}).then((results) => {
|
||||
this.storage['authProvider'] = "facebook";
|
||||
this.storage['authProvider'] = provider;
|
||||
if (results.length > 0) {
|
||||
if (!this.query) {
|
||||
// We're signing up, but this user already exists. Short-circuit
|
||||
@@ -247,7 +298,7 @@ RestWrite.prototype.handleFacebookAuthData = function() {
|
||||
delete this.data.authData;
|
||||
return;
|
||||
}
|
||||
// We're trying to create a duplicate FB auth. Forbid it
|
||||
// We're trying to create a duplicate oauth auth. Forbid it
|
||||
throw new Parse.Error(Parse.Error.ACCOUNT_ALREADY_LINKED,
|
||||
'this auth is already used');
|
||||
} else {
|
||||
@@ -256,12 +307,12 @@ RestWrite.prototype.handleFacebookAuthData = function() {
|
||||
|
||||
// This FB auth does not already exist, so transform it to a
|
||||
// saveable format
|
||||
this.data._auth_data_facebook = facebookData;
|
||||
this.data["_auth_data_" + provider ] = authData;
|
||||
|
||||
// Delete the rest format key before saving
|
||||
delete this.data.authData;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// The non-third-party parts of User transformation
|
||||
RestWrite.prototype.transformUser = function() {
|
||||
|
||||
Reference in New Issue
Block a user