Auth Adapters refactoring (#3177)

* Moves all authentication providers to Adapter/Auth

* refactors specs

* Deprecates oauth option in favor of auth option

- Deprecates facebookAppIds option (in favor of auth.facebook.appIds)
- Adds warnings about the deprecated options

* nits
This commit is contained in:
Florent Vilmart
2016-12-06 17:09:43 -05:00
committed by Arthur Cinader
parent a9067260fc
commit c1dcaf1271
28 changed files with 407 additions and 267 deletions

View File

@@ -17,6 +17,7 @@ export function loadAdapter(adapter, defaultAdapter, options) {
}
}
} else if (typeof adapter === "string") {
/* eslint-disable */
adapter = require(adapter);
// If it's define as a module, get the default
if (adapter.default) {

View File

@@ -0,0 +1,22 @@
/*eslint no-unused-vars: "off"*/
export class AuthAdapter {
/*
@param appIds: the specified app ids in the configuration
@param authData: the client provided authData
@returns a promise that resolves if the applicationId is valid
*/
validateAppId(appIds, authData) {
return Promise.resolve({});
}
/*
@param authData: the client provided authData
@param options: additional options
*/
validateAuthData(authData, options) {
return Promise.resolve({});
}
}
export default AuthAdapter;

99
src/Adapters/Auth/index.js Executable file
View File

@@ -0,0 +1,99 @@
import loadAdapter from '../AdapterLoader';
const facebook = require('./facebook');
const instagram = require("./instagram");
const linkedin = require("./linkedin");
const meetup = require("./meetup");
const google = require("./google");
const github = require("./github");
const twitter = require("./twitter");
const spotify = require("./spotify");
const digits = require("./twitter"); // digits tokens are validated by twitter
const janrainengage = require("./janrainengage");
const janraincapture = require("./janraincapture");
const vkontakte = require("./vkontakte");
const qq = require("./qq");
const wechat = require("./wechat");
const weibo = require("./weibo");
const anonymous = {
validateAuthData: () => {
return Promise.resolve();
},
validateAppId: () => {
return Promise.resolve();
}
}
const providers = {
facebook,
instagram,
linkedin,
meetup,
google,
github,
twitter,
spotify,
anonymous,
digits,
janrainengage,
janraincapture,
vkontakte,
qq,
wechat,
weibo
}
function authDataValidator(adapter, appIds, options) {
return function(authData) {
return adapter.validateAuthData(authData, options).then(() => {
if (appIds) {
return adapter.validateAppId(appIds, authData, options);
}
return Promise.resolve();
});
}
}
module.exports = function(authOptions = {}, enableAnonymousUsers = true) {
let _enableAnonymousUsers = enableAnonymousUsers;
let setEnableAnonymousUsers = function(enable) {
_enableAnonymousUsers = enable;
}
// To handle the test cases on configuration
let getValidatorForProvider = function(provider) {
if (provider === 'anonymous' && !_enableAnonymousUsers) {
return;
}
const defaultAdapter = providers[provider];
let adapter = defaultAdapter;
const providerOptions = authOptions[provider];
if (!defaultAdapter && !providerOptions) {
return;
}
const appIds = providerOptions ? providerOptions.appIds : undefined;
// Try the configuration methods
if (providerOptions) {
const optionalAdapter = loadAdapter(providerOptions, undefined, providerOptions);
if (optionalAdapter) {
adapter = optionalAdapter;
}
}
if (!adapter.validateAuthData || !adapter.validateAppId) {
return;
}
return authDataValidator(adapter, appIds, providerOptions);
}
return Object.freeze({
getValidatorForProvider,
setEnableAnonymousUsers,
})
}

View File

@@ -1,7 +1,7 @@
// Helper functions for accessing the twitter API.
var OAuth = require('./OAuth1Client');
var Parse = require('parse/node').Parse;
var logger = require('../logger').default;
var logger = require('../../logger').default;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData, options) {

View File

@@ -4,7 +4,7 @@
var https = require('https');
var Parse = require('parse/node').Parse;
var logger = require('../logger').default;
var logger = require('../../logger').default;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData, params) {

View File

@@ -32,7 +32,6 @@ export class Config {
this.restAPIKey = cacheInfo.restAPIKey;
this.webhookKey = cacheInfo.webhookKey;
this.fileKey = cacheInfo.fileKey;
this.facebookAppIds = cacheInfo.facebookAppIds;
this.allowClientClassCreation = cacheInfo.allowClientClassCreation;
this.userSensitiveFields = cacheInfo.userSensitiveFields;

View File

@@ -7,7 +7,7 @@ var batch = require('./batch'),
Parse = require('parse/node').Parse,
path = require('path'),
url = require('url'),
authDataManager = require('./authDataManager');
authDataManager = require('./Adapters/Auth');
import defaults from './defaults';
import * as logging from './logger';
@@ -73,8 +73,6 @@ addParseCloud();
// to register your cloud code hooks and functions.
// "appId": the application id to host
// "masterKey": the master key for requests to this app
// "facebookAppIds": an array of valid Facebook Application IDs, required
// if using Facebook login
// "collectionPrefix": optional prefix for database collection names
// "fileKey": optional key from Parse dashboard for supporting older files
// hosted by Parse
@@ -112,11 +110,11 @@ class ParseServer {
restAPIKey,
webhookKey,
fileKey,
facebookAppIds = [],
userSensitiveFields = [],
enableAnonymousUsers = defaults.enableAnonymousUsers,
allowClientClassCreation = defaults.allowClientClassCreation,
oauth = {},
auth = {},
serverURL = requiredParameter('You must provide a serverURL!'),
maxUploadSize = defaults.maxUploadSize,
verifyUserEmails = defaults.verifyUserEmails,
@@ -191,6 +189,17 @@ class ParseServer {
const dbInitPromise = databaseController.performInitialization();
if (Object.keys(oauth).length > 0) {
/* eslint-disable no-console */
console.warn('oauth option is deprecated and will be removed in a future release, please use auth option instead');
if (Object.keys(auth).length > 0) {
console.warn('You should use only the auth option.');
}
/* eslint-enable */
}
auth = Object.assign({}, oauth, auth);
AppCache.put(appId, {
appId,
masterKey: masterKey,
@@ -202,7 +211,6 @@ class ParseServer {
restAPIKey: restAPIKey,
webhookKey: webhookKey,
fileKey: fileKey,
facebookAppIds: facebookAppIds,
analyticsController: analyticsController,
cacheController: cacheController,
filesController: filesController,
@@ -216,7 +224,7 @@ class ParseServer {
accountLockout: accountLockout,
passwordPolicy: passwordPolicy,
allowClientClassCreation: allowClientClassCreation,
authDataManager: authDataManager(oauth, enableAnonymousUsers),
authDataManager: authDataManager(auth, enableAnonymousUsers),
appName: appName,
publicServerURL: publicServerURL,
customPages: customPages,
@@ -232,11 +240,6 @@ class ParseServer {
userSensitiveFields
});
// To maintain compatibility. TODO: Remove in some version that breaks backwards compatibility
if (process.env.FACEBOOK_APP_ID) {
AppCache.get(appId)['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
}
Config.validate(AppCache.get(appId));
this.config = AppCache.get(appId);
Config.setupPasswordValidator(this.config.passwordPolicy);

View File

@@ -1,110 +0,0 @@
let facebook = require('./facebook');
let instagram = require("./instagram");
let linkedin = require("./linkedin");
let meetup = require("./meetup");
let google = require("./google");
let github = require("./github");
let twitter = require("./twitter");
let spotify = require("./spotify");
let digits = require("./twitter"); // digits tokens are validated by twitter
let janrainengage = require("./janrainengage");
let janraincapture = require("./janraincapture");
let vkontakte = require("./vkontakte");
let qq = require("./qq");
let wechat = require("./wechat");
let weibo = require("./weibo");
let anonymous = {
validateAuthData: () => {
return Promise.resolve();
},
validateAppId: () => {
return Promise.resolve();
}
}
let providers = {
facebook,
instagram,
linkedin,
meetup,
google,
github,
twitter,
spotify,
anonymous,
digits,
janrainengage,
janraincapture,
vkontakte,
qq,
wechat,
weibo
}
module.exports = function(oauthOptions = {}, enableAnonymousUsers = true) {
let _enableAnonymousUsers = enableAnonymousUsers;
let setEnableAnonymousUsers = function(enable) {
_enableAnonymousUsers = enable;
}
// To handle the test cases on configuration
let getValidatorForProvider = function(provider) {
if (provider === 'anonymous' && !_enableAnonymousUsers) {
return;
}
let defaultProvider = providers[provider];
let optionalProvider = oauthOptions[provider];
if (!defaultProvider && !optionalProvider) {
return;
}
let appIds;
if (optionalProvider) {
appIds = optionalProvider.appIds;
}
var validateAuthData;
var validateAppId;
if (defaultProvider) {
validateAuthData = defaultProvider.validateAuthData;
validateAppId = defaultProvider.validateAppId;
}
// Try the configuration methods
if (optionalProvider) {
if (optionalProvider.module) {
validateAuthData = require(optionalProvider.module).validateAuthData;
validateAppId = require(optionalProvider.module).validateAppId;
}
if (optionalProvider.validateAuthData) {
validateAuthData = optionalProvider.validateAuthData;
}
if (optionalProvider.validateAppId) {
validateAppId = optionalProvider.validateAppId;
}
}
if (!validateAuthData || !validateAppId) {
return;
}
return function(authData) {
return validateAuthData(authData, optionalProvider).then(() => {
if (appIds) {
return validateAppId(appIds, authData, optionalProvider);
}
return Promise.resolve();
})
}
}
return Object.freeze({
getValidatorForProvider,
setEnableAnonymousUsers,
})
}

View File

@@ -83,7 +83,12 @@ export default {
},
"oauth": {
env: "PARSE_SERVER_OAUTH_PROVIDERS",
help: "Configuration for your oAuth providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth",
help: "[DEPRECATED (use auth option)] Configuration for your oAuth providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth",
action: objectParser
},
"auth": {
env: "PARSE_SERVER_AUTH_PROVIDERS",
help: "Configuration for your authentication providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth",
action: objectParser
},
"fileKey": {
@@ -92,9 +97,15 @@ export default {
},
"facebookAppIds": {
env: "PARSE_SERVER_FACEBOOK_APP_IDS",
help: "Comma separated list for your facebook app Ids",
type: "list",
action: arrayParser
help: "[DEPRECATED (use auth option)]",
action: function() {
throw 'facebookAppIds is deprecated, please use { auth: \
{facebook: \
{ appIds: [] } \
}\
}\
}';
}
},
"enableAnonymousUsers": {
env: "PARSE_SERVER_ENABLE_ANON_USERS",