From c1dcaf12712eb025d502387e564d3b9c1093a768 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Tue, 6 Dec 2016 17:09:43 -0500 Subject: [PATCH] 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 --- ...spec.js => AuthenticationAdapters.spec.js} | 227 +++++++----------- spec/OAuth1.spec.js | 136 +++++++++++ spec/TwitterAuth.spec.js | 2 +- spec/helper.js | 2 +- spec/support/CustomAuth.js | 12 + spec/support/CustomAuthFunction.js | 14 ++ src/Adapters/AdapterLoader.js | 1 + src/Adapters/Auth/AuthAdapter.js | 22 ++ .../Auth}/OAuth1Client.js | 0 .../Auth}/facebook.js | 0 .../Auth}/github.js | 0 .../Auth}/google.js | 0 src/Adapters/Auth/index.js | 99 ++++++++ .../Auth}/instagram.js | 0 .../Auth}/janraincapture.js | 0 .../Auth}/janrainengage.js | 0 .../Auth}/linkedin.js | 0 .../Auth}/meetup.js | 0 src/{authDataManager => Adapters/Auth}/qq.js | 0 .../Auth}/spotify.js | 0 .../Auth}/twitter.js | 2 +- .../Auth}/vkontakte.js | 2 +- .../Auth}/wechat.js | 0 .../Auth}/weibo.js | 0 src/Config.js | 1 - src/ParseServer.js | 25 +- src/authDataManager/index.js | 110 --------- src/cli/definitions/parse-server.js | 19 +- 28 files changed, 407 insertions(+), 267 deletions(-) rename spec/{OAuth.spec.js => AuthenticationAdapters.spec.js} (61%) create mode 100644 spec/OAuth1.spec.js create mode 100644 spec/support/CustomAuth.js create mode 100644 spec/support/CustomAuthFunction.js create mode 100644 src/Adapters/Auth/AuthAdapter.js rename src/{authDataManager => Adapters/Auth}/OAuth1Client.js (100%) rename src/{authDataManager => Adapters/Auth}/facebook.js (100%) rename src/{authDataManager => Adapters/Auth}/github.js (100%) rename src/{authDataManager => Adapters/Auth}/google.js (100%) create mode 100755 src/Adapters/Auth/index.js rename src/{authDataManager => Adapters/Auth}/instagram.js (100%) rename src/{authDataManager => Adapters/Auth}/janraincapture.js (100%) rename src/{authDataManager => Adapters/Auth}/janrainengage.js (100%) rename src/{authDataManager => Adapters/Auth}/linkedin.js (100%) rename src/{authDataManager => Adapters/Auth}/meetup.js (100%) rename src/{authDataManager => Adapters/Auth}/qq.js (100%) rename src/{authDataManager => Adapters/Auth}/spotify.js (100%) rename src/{authDataManager => Adapters/Auth}/twitter.js (97%) rename src/{authDataManager => Adapters/Auth}/vkontakte.js (98%) rename src/{authDataManager => Adapters/Auth}/wechat.js (100%) rename src/{authDataManager => Adapters/Auth}/weibo.js (100%) delete mode 100755 src/authDataManager/index.js diff --git a/spec/OAuth.spec.js b/spec/AuthenticationAdapters.spec.js similarity index 61% rename from spec/OAuth.spec.js rename to spec/AuthenticationAdapters.spec.js index a8242961..c2f4a106 100644 --- a/spec/OAuth.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -1,145 +1,13 @@ -var OAuth = require("../src/authDataManager/OAuth1Client"); var request = require('request'); var Config = require("../src/Config"); var defaultColumns = require('../src/Controllers/SchemaController').defaultColumns; +var authenticationLoader = require('../src/Adapters/Auth'); +var path = require('path'); -describe('OAuth', function() { - it("Nonce should have right length", (done) => { - jequal(OAuth.nonce().length, 30); - done(); - }); - - it("Should properly build parameter string", (done) => { - var string = OAuth.buildParameterString({c:1, a:2, b:3}) - jequal(string, "a=2&b=3&c=1"); - done(); - }); - - it("Should properly build empty parameter string", (done) => { - var string = OAuth.buildParameterString() - jequal(string, ""); - done(); - }); - - it("Should properly build signature string", (done) => { - var string = OAuth.buildSignatureString("get", "http://dummy.com", ""); - jequal(string, "GET&http%3A%2F%2Fdummy.com&"); - done(); - }); - - it("Should properly generate request signature", (done) => { - var request = { - host: "dummy.com", - path: "path" - }; - - var oauth_params = { - oauth_timestamp: 123450000, - oauth_nonce: "AAAAAAAAAAAAAAAAA", - oauth_consumer_key: "hello", - oauth_token: "token" - }; - - var consumer_secret = "world"; - var auth_token_secret = "secret"; - request = OAuth.signRequest(request, oauth_params, consumer_secret, auth_token_secret); - jequal(request.headers['Authorization'], 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="8K95bpQcDi9Nd2GkhumTVcw4%2BXw%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"'); - done(); - }); - - it("Should properly build request", (done) => { - var options = { - host: "dummy.com", - consumer_key: "hello", - consumer_secret: "world", - auth_token: "token", - auth_token_secret: "secret", - // Custom oauth params for tests - oauth_params: { - oauth_timestamp: 123450000, - oauth_nonce: "AAAAAAAAAAAAAAAAA" - } - }; - var path = "path"; - var method = "get"; - - var oauthClient = new OAuth(options); - var req = oauthClient.buildRequest(method, path, {"query": "param"}); - - jequal(req.host, options.host); - jequal(req.path, "/"+path+"?query=param"); - jequal(req.method, "GET"); - jequal(req.headers['Content-Type'], 'application/x-www-form-urlencoded'); - jequal(req.headers['Authorization'], 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="wNkyEkDE%2F0JZ2idmqyrgHdvC0rs%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"') - done(); - }); - - - function validateCannotAuthenticateError(data, done) { - jequal(typeof data, "object"); - jequal(typeof data.errors, "object"); - var errors = data.errors; - jequal(typeof errors[0], "object"); - // Cannot authenticate error - jequal(errors[0].code, 32); - done(); - } - - it("Should fail a GET request", (done) => { - var options = { - host: "api.twitter.com", - consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX", - consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - }; - var path = "/1.1/help/configuration.json"; - var params = {"lang": "en"}; - var oauthClient = new OAuth(options); - oauthClient.get(path, params).then(function(data){ - validateCannotAuthenticateError(data, done); - }) - }); - - it("Should fail a POST request", (done) => { - var options = { - host: "api.twitter.com", - consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX", - consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - }; - var body = { - lang: "en" - }; - var path = "/1.1/account/settings.json"; - - var oauthClient = new OAuth(options); - oauthClient.post(path, null, body).then(function(data){ - validateCannotAuthenticateError(data, done); - }) - }); - - it("Should fail a request", (done) => { - var options = { - host: "localhost", - consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX", - consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - }; - var body = { - lang: "en" - }; - var path = "/"; - - var oauthClient = new OAuth(options); - oauthClient.post(path, null, body).then(function(){ - jequal(false, true); - done(); - }).catch(function(){ - jequal(true, true); - done(); - }) - }); - +describe('AuthenticationProviers', function() { ["facebook", "github", "instagram", "google", "linkedin", "meetup", "twitter", "janrainengage", "janraincapture", "vkontakte"].map(function(providerName){ it("Should validate structure of "+providerName, (done) => { - var provider = require("../src/authDataManager/"+providerName); + var provider = require("../src/Adapters/Auth/"+providerName); jequal(typeof provider.validateAuthData, "function"); jequal(typeof provider.validateAppId, "function"); jequal(provider.validateAuthData({}, {}).constructor, Promise.prototype.constructor); @@ -325,5 +193,90 @@ describe('OAuth', function() { }); }); + function validateValidator(validator) { + expect(typeof validator).toBe('function'); + } -}) + function validateAuthenticationHandler(authenticatonHandler) { + expect(authenticatonHandler).not.toBeUndefined(); + expect(typeof authenticatonHandler.getValidatorForProvider).toBe('function'); + expect(typeof authenticatonHandler.getValidatorForProvider).toBe('function'); + } + + it('properly loads custom adapter', (done) => { + var validAuthData = { + id: 'hello', + token: 'world' + } + let adapter = { + validateAppId: function() { + return Promise.resolve(); + }, + validateAuthData: function(authData) { + if (authData.id == validAuthData.id && authData.token == validAuthData.token) { + return Promise.resolve(); + } + return Promise.reject(); + } + }; + + let authDataSpy = spyOn(adapter, 'validateAuthData').and.callThrough(); + let appIdSpy = spyOn(adapter, 'validateAppId').and.callThrough(); + + let authenticationHandler = authenticationLoader({ + customAuthentication: adapter + }); + + validateAuthenticationHandler(authenticationHandler); + let validator = authenticationHandler.getValidatorForProvider('customAuthentication'); + validateValidator(validator); + + validator(validAuthData).then(() => { + expect(authDataSpy).toHaveBeenCalled(); + // AppIds are not provided in the adapter, should not be called + expect(appIdSpy).not.toHaveBeenCalled(); + done(); + }, (err) => { + jfail(err); + done(); + }) + }); + + it('properly loads custom adapter module object', (done) => { + let authenticationHandler = authenticationLoader({ + customAuthentication: path.resolve('./spec/support/CustomAuth.js') + }); + + validateAuthenticationHandler(authenticationHandler); + let validator = authenticationHandler.getValidatorForProvider('customAuthentication'); + validateValidator(validator); + + validator({ + token: 'my-token' + }).then(() => { + done(); + }, (err) => { + jfail(err); + done(); + }) + }); + + it('properly loads custom adapter module object', (done) => { + let authenticationHandler = authenticationLoader({ + customAuthentication: { module: path.resolve('./spec/support/CustomAuthFunction.js'), options: { token: 'valid-token' }} + }); + + validateAuthenticationHandler(authenticationHandler); + let validator = authenticationHandler.getValidatorForProvider('customAuthentication'); + validateValidator(validator); + + validator({ + token: 'valid-token' + }).then(() => { + done(); + }, (err) => { + jfail(err); + done(); + }) + }); +}); diff --git a/spec/OAuth1.spec.js b/spec/OAuth1.spec.js new file mode 100644 index 00000000..a6dce982 --- /dev/null +++ b/spec/OAuth1.spec.js @@ -0,0 +1,136 @@ +var OAuth = require("../src/Adapters/Auth/OAuth1Client"); + +describe('OAuth', function() { + it("Nonce should have right length", (done) => { + jequal(OAuth.nonce().length, 30); + done(); + }); + + it("Should properly build parameter string", (done) => { + var string = OAuth.buildParameterString({c:1, a:2, b:3}) + jequal(string, "a=2&b=3&c=1"); + done(); + }); + + it("Should properly build empty parameter string", (done) => { + var string = OAuth.buildParameterString() + jequal(string, ""); + done(); + }); + + it("Should properly build signature string", (done) => { + var string = OAuth.buildSignatureString("get", "http://dummy.com", ""); + jequal(string, "GET&http%3A%2F%2Fdummy.com&"); + done(); + }); + + it("Should properly generate request signature", (done) => { + var request = { + host: "dummy.com", + path: "path" + }; + + var oauth_params = { + oauth_timestamp: 123450000, + oauth_nonce: "AAAAAAAAAAAAAAAAA", + oauth_consumer_key: "hello", + oauth_token: "token" + }; + + var consumer_secret = "world"; + var auth_token_secret = "secret"; + request = OAuth.signRequest(request, oauth_params, consumer_secret, auth_token_secret); + jequal(request.headers['Authorization'], 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="8K95bpQcDi9Nd2GkhumTVcw4%2BXw%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"'); + done(); + }); + + it("Should properly build request", (done) => { + var options = { + host: "dummy.com", + consumer_key: "hello", + consumer_secret: "world", + auth_token: "token", + auth_token_secret: "secret", + // Custom oauth params for tests + oauth_params: { + oauth_timestamp: 123450000, + oauth_nonce: "AAAAAAAAAAAAAAAAA" + } + }; + var path = "path"; + var method = "get"; + + var oauthClient = new OAuth(options); + var req = oauthClient.buildRequest(method, path, {"query": "param"}); + + jequal(req.host, options.host); + jequal(req.path, "/"+path+"?query=param"); + jequal(req.method, "GET"); + jequal(req.headers['Content-Type'], 'application/x-www-form-urlencoded'); + jequal(req.headers['Authorization'], 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="wNkyEkDE%2F0JZ2idmqyrgHdvC0rs%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"') + done(); + }); + + + function validateCannotAuthenticateError(data, done) { + jequal(typeof data, "object"); + jequal(typeof data.errors, "object"); + var errors = data.errors; + jequal(typeof errors[0], "object"); + // Cannot authenticate error + jequal(errors[0].code, 32); + done(); + } + + it("Should fail a GET request", (done) => { + var options = { + host: "api.twitter.com", + consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX", + consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + }; + var path = "/1.1/help/configuration.json"; + var params = {"lang": "en"}; + var oauthClient = new OAuth(options); + oauthClient.get(path, params).then(function(data){ + validateCannotAuthenticateError(data, done); + }) + }); + + it("Should fail a POST request", (done) => { + var options = { + host: "api.twitter.com", + consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX", + consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + }; + var body = { + lang: "en" + }; + var path = "/1.1/account/settings.json"; + + var oauthClient = new OAuth(options); + oauthClient.post(path, null, body).then(function(data){ + validateCannotAuthenticateError(data, done); + }) + }); + + it("Should fail a request", (done) => { + var options = { + host: "localhost", + consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX", + consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + }; + var body = { + lang: "en" + }; + var path = "/"; + + var oauthClient = new OAuth(options); + oauthClient.post(path, null, body).then(function(){ + jequal(false, true); + done(); + }).catch(function(){ + jequal(true, true); + done(); + }) + }); +}); diff --git a/spec/TwitterAuth.spec.js b/spec/TwitterAuth.spec.js index 4c6ad55a..c7633939 100644 --- a/spec/TwitterAuth.spec.js +++ b/spec/TwitterAuth.spec.js @@ -1,4 +1,4 @@ -let twitter = require('../src/authDataManager/twitter'); +let twitter = require('../src/Adapters/Auth/twitter'); describe('Twitter Auth', () => { it('should use the proper configuration', () => { diff --git a/spec/helper.js b/spec/helper.js index 20880c6e..d7edb9cc 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -102,7 +102,7 @@ var defaultConfiguration = { bundleId: 'bundleId', } }, - oauth: { // Override the facebook provider + auth: { // Override the facebook provider facebook: mockFacebook(), myoauth: { module: path.resolve(__dirname, "myoauth") // relative path as it's run from src diff --git a/spec/support/CustomAuth.js b/spec/support/CustomAuth.js new file mode 100644 index 00000000..3a2630cf --- /dev/null +++ b/spec/support/CustomAuth.js @@ -0,0 +1,12 @@ + +module.exports = { + validateAppId: function() { + return Promise.resolve(); + }, + validateAuthData: function(authData) { + if (authData.token == 'my-token') { + return Promise.resolve(); + } + return Promise.reject(); + } +} diff --git a/spec/support/CustomAuthFunction.js b/spec/support/CustomAuthFunction.js new file mode 100644 index 00000000..d13165e7 --- /dev/null +++ b/spec/support/CustomAuthFunction.js @@ -0,0 +1,14 @@ + +module.exports = function(validAuthData) { + return { + validateAppId: function() { + return Promise.resolve(); + }, + validateAuthData: function(authData) { + if (authData.token == validAuthData.token) { + return Promise.resolve(); + } + return Promise.reject(); + } + } +} diff --git a/src/Adapters/AdapterLoader.js b/src/Adapters/AdapterLoader.js index d720fb99..cd7f33f3 100644 --- a/src/Adapters/AdapterLoader.js +++ b/src/Adapters/AdapterLoader.js @@ -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) { diff --git a/src/Adapters/Auth/AuthAdapter.js b/src/Adapters/Auth/AuthAdapter.js new file mode 100644 index 00000000..dd8fd838 --- /dev/null +++ b/src/Adapters/Auth/AuthAdapter.js @@ -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; diff --git a/src/authDataManager/OAuth1Client.js b/src/Adapters/Auth/OAuth1Client.js similarity index 100% rename from src/authDataManager/OAuth1Client.js rename to src/Adapters/Auth/OAuth1Client.js diff --git a/src/authDataManager/facebook.js b/src/Adapters/Auth/facebook.js similarity index 100% rename from src/authDataManager/facebook.js rename to src/Adapters/Auth/facebook.js diff --git a/src/authDataManager/github.js b/src/Adapters/Auth/github.js similarity index 100% rename from src/authDataManager/github.js rename to src/Adapters/Auth/github.js diff --git a/src/authDataManager/google.js b/src/Adapters/Auth/google.js similarity index 100% rename from src/authDataManager/google.js rename to src/Adapters/Auth/google.js diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js new file mode 100755 index 00000000..c6bc0e0b --- /dev/null +++ b/src/Adapters/Auth/index.js @@ -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, + }) +} diff --git a/src/authDataManager/instagram.js b/src/Adapters/Auth/instagram.js similarity index 100% rename from src/authDataManager/instagram.js rename to src/Adapters/Auth/instagram.js diff --git a/src/authDataManager/janraincapture.js b/src/Adapters/Auth/janraincapture.js similarity index 100% rename from src/authDataManager/janraincapture.js rename to src/Adapters/Auth/janraincapture.js diff --git a/src/authDataManager/janrainengage.js b/src/Adapters/Auth/janrainengage.js similarity index 100% rename from src/authDataManager/janrainengage.js rename to src/Adapters/Auth/janrainengage.js diff --git a/src/authDataManager/linkedin.js b/src/Adapters/Auth/linkedin.js similarity index 100% rename from src/authDataManager/linkedin.js rename to src/Adapters/Auth/linkedin.js diff --git a/src/authDataManager/meetup.js b/src/Adapters/Auth/meetup.js similarity index 100% rename from src/authDataManager/meetup.js rename to src/Adapters/Auth/meetup.js diff --git a/src/authDataManager/qq.js b/src/Adapters/Auth/qq.js similarity index 100% rename from src/authDataManager/qq.js rename to src/Adapters/Auth/qq.js diff --git a/src/authDataManager/spotify.js b/src/Adapters/Auth/spotify.js similarity index 100% rename from src/authDataManager/spotify.js rename to src/Adapters/Auth/spotify.js diff --git a/src/authDataManager/twitter.js b/src/Adapters/Auth/twitter.js similarity index 97% rename from src/authDataManager/twitter.js rename to src/Adapters/Auth/twitter.js index 480c613f..0eec82a6 100644 --- a/src/authDataManager/twitter.js +++ b/src/Adapters/Auth/twitter.js @@ -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) { diff --git a/src/authDataManager/vkontakte.js b/src/Adapters/Auth/vkontakte.js similarity index 98% rename from src/authDataManager/vkontakte.js rename to src/Adapters/Auth/vkontakte.js index a25925d4..0fdf28f2 100644 --- a/src/authDataManager/vkontakte.js +++ b/src/Adapters/Auth/vkontakte.js @@ -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) { diff --git a/src/authDataManager/wechat.js b/src/Adapters/Auth/wechat.js similarity index 100% rename from src/authDataManager/wechat.js rename to src/Adapters/Auth/wechat.js diff --git a/src/authDataManager/weibo.js b/src/Adapters/Auth/weibo.js similarity index 100% rename from src/authDataManager/weibo.js rename to src/Adapters/Auth/weibo.js diff --git a/src/Config.js b/src/Config.js index 743976b4..67cc3345 100644 --- a/src/Config.js +++ b/src/Config.js @@ -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; diff --git a/src/ParseServer.js b/src/ParseServer.js index bf9d0c62..0ae7b246 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -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); diff --git a/src/authDataManager/index.js b/src/authDataManager/index.js deleted file mode 100755 index 5fe0f32b..00000000 --- a/src/authDataManager/index.js +++ /dev/null @@ -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, - }) -} diff --git a/src/cli/definitions/parse-server.js b/src/cli/definitions/parse-server.js index 55c79f28..687cb547 100644 --- a/src/cli/definitions/parse-server.js +++ b/src/cli/definitions/parse-server.js @@ -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",