From 20758754519ca2358b5b76ef6776056e3d5ae3b5 Mon Sep 17 00:00:00 2001 From: Chris Geihsler Date: Tue, 18 Feb 2020 09:18:54 -0500 Subject: [PATCH] [DXEX-455] Allow custom headers to be set in Management/Auth Clients. In order to better determine what version of the Deploy CLI tool is being used by our customers, we would like to include the Deploy CLI's version in the User-agent header as opposed to the current behavior (the version of node under which the CLI is running). The Deploy CLI uses ManagementClient to do its work, but the User-agent header was not configurable before this change. This commit provides a new option called `headers` that will allow the caller to provide an optional set of additional headers to outgoing requests. In the case of the `User-agent` header, if it is not provided by the caller, the original User-agent string will be used (e.g. `node.js/13.1.2`). --- src/auth/index.js | 12 +++++--- src/management/index.js | 13 +++++--- test/auth/authentication-client.tests.js | 36 ++++++++++++++++++++++ test/management/management-client.tests.js | 33 ++++++++++++++++++++ 4 files changed, 86 insertions(+), 8 deletions(-) diff --git a/src/auth/index.js b/src/auth/index.js index bcbceff2c..191dcd726 100644 --- a/src/auth/index.js +++ b/src/auth/index.js @@ -4,6 +4,7 @@ var util = require('util'); var utils = require('../utils'); var jsonToBase64 = utils.jsonToBase64; var ArgumentError = require('rest-facade').ArgumentError; +var assign = Object.assign || require('object.assign'); // Authenticators. var OAuthAuthenticator = require('./OAuthAuthenticator'); @@ -43,6 +44,7 @@ var BASE_URL_FORMAT = 'https://%s'; * @param {String} [options.clientSecret] Default client Secret. * @param {String} [options.supportedAlgorithms] Algorithms that your application expects to receive * @param {Boolean} [options.__bypassIdTokenValidation] Whether the id_token should be validated or not + * @param {Object} [options.headers] Additional headers that will be added to the outgoing requests. */ var AuthenticationClient = function(options) { if (!options || typeof options !== 'object') { @@ -53,14 +55,16 @@ var AuthenticationClient = function(options) { throw new ArgumentError('Must provide a domain'); } + var defaultHeaders = { + 'User-agent': 'node.js/' + process.version.replace('v', ''), + 'Content-Type': 'application/json' + }; + var managerOptions = { clientId: options.clientId, domain: options.domain, clientSecret: options.clientSecret, - headers: { - 'User-agent': 'node.js/' + process.version.replace('v', ''), - 'Content-Type': 'application/json' - }, + headers: assign(defaultHeaders, options.headers || {}), baseUrl: util.format(BASE_URL_FORMAT, options.domain), supportedAlgorithms: options.supportedAlgorithms, __bypassIdTokenValidation: options.__bypassIdTokenValidation diff --git a/src/management/index.js b/src/management/index.js index b2c8d11ca..88deab422 100644 --- a/src/management/index.js +++ b/src/management/index.js @@ -90,6 +90,7 @@ var MANAGEMENT_API_AUD_FORMAT = 'https://%s/api/v2/'; * @param {Number} [options.tokenProvider.cacheTTLInSeconds] By default the `expires_in` value will be used to determine the cached time of the token, this can be overridden. * @param {Boolean} [options.retry.enabled=true] Enabled or Disable Retry Policy functionality. * @param {Number} [options.retry.maxRetries=10] Retry failed requests X times. + * @param {Object} [options.headers] Additional headers that will be added to the outgoing requests. * */ var ManagementClient = function(options) { @@ -102,11 +103,15 @@ var ManagementClient = function(options) { } var baseUrl = util.format(BASE_URL_FORMAT, options.domain); + var userAgent = options.userAgent || 'node.js/' + process.version.replace('v', ''); + + var defaultHeaders = { + 'User-agent': 'node.js/' + process.version.replace('v', ''), + 'Content-Type': 'application/json' + }; + var managerOptions = { - headers: { - 'User-agent': 'node.js/' + process.version.replace('v', ''), - 'Content-Type': 'application/json' - }, + headers: assign(defaultHeaders, options.headers || {}), baseUrl: baseUrl }; diff --git a/test/auth/authentication-client.tests.js b/test/auth/authentication-client.tests.js index 7cb62e23f..d7f7c07e2 100644 --- a/test/auth/authentication-client.tests.js +++ b/test/auth/authentication-client.tests.js @@ -143,6 +143,42 @@ describe('AuthenticationClient', function() { }); }); + describe('user agent', function() { + it('should use the node version when the user agent option is not provided', function() { + var client = new AuthenticationClient({ + token: 'token', + domain: 'auth0.com' + }); + + var expected = { 'User-agent': 'node.js/' + process.version.replace('v', '') }; + + expect(client.oauth.oauth.options.headers).to.contain(expected); + expect(client.database.dbConnections.options.headers).to.contain(expected); + expect(client.passwordless.passwordless.options.headers).to.contain(expected); + expect(client.users.headers).to.contain(expected); + expect(client.tokens.headers).to.contain(expected); + }); + + it('should include additional headers when provided', function() { + var customHeaders = { + 'User-agent': 'my-user-agent', + 'Another-header': 'test-header' + }; + + var client = new AuthenticationClient({ + token: 'token', + domain: 'auth0.com', + headers: customHeaders + }); + + expect(client.oauth.oauth.options.headers).to.contain(customHeaders); + expect(client.database.dbConnections.options.headers).to.contain(customHeaders); + expect(client.passwordless.passwordless.options.headers).to.contain(customHeaders); + expect(client.users.headers).to.contain(customHeaders); + expect(client.tokens.headers).to.contain(customHeaders); + }); + }); + describe('instance methods', function() { var methods = []; var client = new AuthenticationClient({ token: 'token', domain: 'auth0.com' }); diff --git a/test/management/management-client.tests.js b/test/management/management-client.tests.js index e50d53304..742c74d8d 100644 --- a/test/management/management-client.tests.js +++ b/test/management/management-client.tests.js @@ -198,6 +198,39 @@ describe('ManagementClient', function() { } }; + describe('user agent', function() { + for (var name in managers) { + manager = managers[name]; + + it(manager + ' should use the node version by default', function() { + var client = new ManagementClient(withTokenConfig); + + expect( + client[manager.property].resource.restClient.restClient.options.headers + ).to.contain({ + 'User-agent': 'node.js/' + process.version.replace('v', '') + }); + }); + + it(manager + ' should include additional headers when provided', function() { + var customHeaders = { + 'User-agent': 'my-user-agent', + 'Another-header': 'test-header' + }; + + var options = assign({ headers: customHeaders }, withTokenConfig); + var client = new ManagementClient(options); + + expect( + client[manager.property].resource.restClient.restClient.options.headers + ).to.contain({ + 'User-agent': 'my-user-agent', + 'Another-header': 'test-header' + }); + }); + } + }); + describe('client info', function() { it('should configure instances with default telemetry header', function() { var utilsStub = {