diff --git a/src/auth/OAuthAuthenticator.js b/src/auth/OAuthAuthenticator.js index 6586b81ba..31a841bd5 100644 --- a/src/auth/OAuthAuthenticator.js +++ b/src/auth/OAuthAuthenticator.js @@ -1,10 +1,24 @@ var extend = require('util')._extend; +var sanitizeArguments = require('../utils').sanitizeArguments; var ArgumentError = require('rest-facade').ArgumentError; var RestClient = require('rest-facade').Client; var OAUthWithIDTokenValidation = require('./OAUthWithIDTokenValidation'); +function getParamsFromOptions(options) { + const params = {}; + if (!options || typeof options !== 'object') { + return params; + } + if (options.forwardedFor) { + params._requestCustomizer = function(req) { + req.set('auth0-forwarded-for', options.forwardedFor); + }; + } + return params; +} + /** * @class * Abstracts the sign-in, sign-up and change-password processes for Database & @@ -75,17 +89,21 @@ var OAuthAuthenticator = function(options) { * console.log(userData); * }); * - * @param {Object} userData User credentials object. - * @param {String} userData.username Username. - * @param {String} userData.password User password. - * @param {String} userData.connection The identity provider in use. + * @param {Object} userData User credentials object. + * @param {String} userData.username Username. + * @param {String} userData.password User password. + * @param {String} userData.connection The identity provider in use. + * @param {Object} [options] Additional options. + * @param {String} [options.forwardedFor] Value to be used for auth0-forwarded-for header * * @return {Promise|undefined} */ -OAuthAuthenticator.prototype.signIn = function(userData, cb) { - var params = { +OAuthAuthenticator.prototype.signIn = function(userData, options, cb) { + var { options, cb } = sanitizeArguments(options, cb); + var defaultParams = { type: 'ro' }; + var params = extend(defaultParams, getParamsFromOptions(options)); var defaultFields = { client_id: this.clientId, grant_type: 'password', @@ -140,17 +158,21 @@ OAuthAuthenticator.prototype.signIn = function(userData, cb) { * console.log(userData); * }); * - * @param {Object} userData User credentials object. - * @param {String} userData.username Username. - * @param {String} userData.password User password. - * @param {String} [userData.realm] Name of the realm to use to authenticate or the connection name + * @param {Object} userData User credentials object. + * @param {String} userData.username Username. + * @param {String} userData.password User password. + * @param {String} [userData.realm] Name of the realm to use to authenticate or the connection name + * @param {Object} [options] Additional options. + * @param {String} [options.forwardedFor] Value to be used for auth0-forwarded-for header * * @return {Promise|undefined} */ -OAuthAuthenticator.prototype.passwordGrant = function(userData, cb) { - var params = { +OAuthAuthenticator.prototype.passwordGrant = function(userData, options, cb) { + var { options, cb } = sanitizeArguments(options, cb); + var defaultParams = { type: 'token' }; + var params = extend(defaultParams, getParamsFromOptions(options)); var defaultFields = { client_id: this.clientId, client_secret: this.clientSecret, diff --git a/src/utils.js b/src/utils.js index 8d9f2caa8..ab562a2ab 100644 --- a/src/utils.js +++ b/src/utils.js @@ -102,3 +102,16 @@ utils.maybeDecode = url => { } return url; }; + +utils.sanitizeArguments = function(optionsCandidate, cbCandidate) { + if (optionsCandidate instanceof Function) { + return { + cb: optionsCandidate, + options: undefined + }; + } + return { + cb: cbCandidate, + options: optionsCandidate + }; +}; diff --git a/test/auth/oauth.tests.js b/test/auth/oauth.tests.js index c3433d121..3cfe3419d 100644 --- a/test/auth/oauth.tests.js +++ b/test/auth/oauth.tests.js @@ -67,6 +67,9 @@ describe('OAuthAuthenticator', function() { password: 'pwd', connection: 'Username-Password-Authentication' }; + var options = { + forwardedFor: '0.0.0.0' + }; beforeEach(function() { this.authenticator = new Authenticator(validOptions); @@ -230,6 +233,26 @@ describe('OAuthAuthenticator', function() { }) .catch(done); }); + + it('should make it possible to pass auth0-forwarded-for header', function(done) { + nock.cleanAll(); + + var request = nock(API_URL) + .post(path, function() { + return this.getHeader('auth0-forwarded-for') === options.forwardedFor; + }) + .reply(200); + + this.authenticator + .signIn(userData, options) + .then(function() { + expect(request.isDone()).to.be.true; + + done(); + }) + .catch(done); + }); + it('should use OAUthWithIDTokenValidation', function(done) { this.authenticator .signIn(userData) @@ -247,6 +270,9 @@ describe('OAuthAuthenticator', function() { username: 'username', password: 'pwd' }; + var options = { + forwardedFor: '0.0.0.0' + }; beforeEach(function() { this.authenticator = new Authenticator(validOptions); @@ -400,6 +426,26 @@ describe('OAuthAuthenticator', function() { }) .catch(done); }); + + it('should make it possible to pass auth0-forwarded-for header', function(done) { + nock.cleanAll(); + + var request = nock(API_URL) + .post(path, function() { + return this.getHeader('auth0-forwarded-for') === options.forwardedFor; + }) + .reply(200); + + this.authenticator + .passwordGrant(userData, options) + .then(function() { + expect(request.isDone()).to.be.true; + + done(); + }) + .catch(done); + }); + it('should use OAUthWithIDTokenValidation', function(done) { this.authenticator .passwordGrant(userData) @@ -416,6 +462,7 @@ describe('OAuthAuthenticator', function() { var userData = { refresh_token: 'refresh_token' }; + beforeEach(function() { this.authenticator = new Authenticator(validOptions); this.request = nock(API_URL) @@ -902,6 +949,7 @@ describe('OAuthAuthenticator', function() { }) .catch(done); }); + it('should use OAUthWithIDTokenValidation', function(done) { this.authenticator .authorizationCodeGrant(data)