Add AppSecret to Facebook Auth (#5695)
Closes: https://github.com/parse-community/parse-server/issues/5448
This commit is contained in:
@@ -416,6 +416,7 @@ describe('AuthenticationProviders', function() {
|
|||||||
const options = {
|
const options = {
|
||||||
facebook: {
|
facebook: {
|
||||||
appIds: ['a', 'b'],
|
appIds: ['a', 'b'],
|
||||||
|
appSecret: 'secret',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const {
|
const {
|
||||||
@@ -428,6 +429,56 @@ describe('AuthenticationProviders', function() {
|
|||||||
expect(providerOptions).toEqual(options.facebook);
|
expect(providerOptions).toEqual(options.facebook);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle Facebook appSecret for validating appIds', async () => {
|
||||||
|
const httpsRequest = require('../lib/Adapters/Auth/httpsRequest');
|
||||||
|
spyOn(httpsRequest, 'get').and.callFake(() => {
|
||||||
|
return Promise.resolve({ id: 'a' });
|
||||||
|
});
|
||||||
|
const options = {
|
||||||
|
facebook: {
|
||||||
|
appIds: ['a', 'b'],
|
||||||
|
appSecret: 'secret_sauce',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const authData = {
|
||||||
|
access_token: 'badtoken',
|
||||||
|
};
|
||||||
|
const {
|
||||||
|
adapter,
|
||||||
|
appIds,
|
||||||
|
providerOptions,
|
||||||
|
} = authenticationLoader.loadAuthAdapter('facebook', options);
|
||||||
|
await adapter.validateAppId(appIds, authData, providerOptions);
|
||||||
|
expect(
|
||||||
|
httpsRequest.get.calls.first().args[0].includes('appsecret_proof')
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle Facebook appSecret for validating auth data', async () => {
|
||||||
|
const httpsRequest = require('../lib/Adapters/Auth/httpsRequest');
|
||||||
|
spyOn(httpsRequest, 'get').and.callFake(() => {
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
const options = {
|
||||||
|
facebook: {
|
||||||
|
appIds: ['a', 'b'],
|
||||||
|
appSecret: 'secret_sauce',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const authData = {
|
||||||
|
id: 'test',
|
||||||
|
access_token: 'test',
|
||||||
|
};
|
||||||
|
const { adapter, providerOptions } = authenticationLoader.loadAuthAdapter(
|
||||||
|
'facebook',
|
||||||
|
options
|
||||||
|
);
|
||||||
|
await adapter.validateAuthData(authData, providerOptions);
|
||||||
|
expect(
|
||||||
|
httpsRequest.get.calls.first().args[0].includes('appsecret_proof')
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('properly loads a custom adapter with options', () => {
|
it('properly loads a custom adapter with options', () => {
|
||||||
const options = {
|
const options = {
|
||||||
custom: {
|
custom: {
|
||||||
|
|||||||
@@ -1,11 +1,27 @@
|
|||||||
// Helper functions for accessing the Facebook Graph API.
|
// Helper functions for accessing the Facebook Graph API.
|
||||||
const httpsRequest = require('./httpsRequest');
|
const httpsRequest = require('./httpsRequest');
|
||||||
var Parse = require('parse/node').Parse;
|
var Parse = require('parse/node').Parse;
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
function getAppSecretPath(authData, options = {}) {
|
||||||
|
const appSecret = options.appSecret;
|
||||||
|
if (!appSecret) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const appsecret_proof = crypto
|
||||||
|
.createHmac('sha256', appSecret)
|
||||||
|
.update(authData.access_token)
|
||||||
|
.digest('hex');
|
||||||
|
|
||||||
|
return `&appsecret_proof=${appsecret_proof}`;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns a promise that fulfills iff this user id is valid.
|
// Returns a promise that fulfills iff this user id is valid.
|
||||||
function validateAuthData(authData) {
|
function validateAuthData(authData, options) {
|
||||||
return graphRequest(
|
return graphRequest(
|
||||||
'me?fields=id&access_token=' + authData.access_token
|
'me?fields=id&access_token=' +
|
||||||
|
authData.access_token +
|
||||||
|
getAppSecretPath(authData, options)
|
||||||
).then(data => {
|
).then(data => {
|
||||||
if (
|
if (
|
||||||
(data && data.id == authData.id) ||
|
(data && data.id == authData.id) ||
|
||||||
@@ -21,7 +37,7 @@ function validateAuthData(authData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a promise that fulfills iff this app id is valid.
|
// Returns a promise that fulfills iff this app id is valid.
|
||||||
function validateAppId(appIds, authData) {
|
function validateAppId(appIds, authData, options) {
|
||||||
var access_token = authData.access_token;
|
var access_token = authData.access_token;
|
||||||
if (process.env.TESTING && access_token === 'test') {
|
if (process.env.TESTING && access_token === 'test') {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -32,7 +48,9 @@ function validateAppId(appIds, authData) {
|
|||||||
'Facebook auth is not configured.'
|
'Facebook auth is not configured.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return graphRequest('app?access_token=' + access_token).then(data => {
|
return graphRequest(
|
||||||
|
'app?access_token=' + access_token + getAppSecretPath(authData, options)
|
||||||
|
).then(data => {
|
||||||
if (data && appIds.indexOf(data.id) != -1) {
|
if (data && appIds.indexOf(data.id) != -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user