From 607f6e650757defd91e7ba2af37ef834db424d9f Mon Sep 17 00:00:00 2001 From: Shu Shen Date: Sun, 8 Mar 2020 15:03:24 -0700 Subject: [PATCH 1/3] utils: generalize utils.convertClientNamesToIds translation --- src/auth0/handlers/clientGrants.js | 6 ++---- src/auth0/handlers/connections.js | 25 +++++++++++++++---------- src/auth0/handlers/databases.js | 7 ++----- src/utils.js | 9 +++++++++ tests/utils.tests.js | 14 ++++++++++++++ 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/auth0/handlers/clientGrants.js b/src/auth0/handlers/clientGrants.js index 36b897a..470a823 100644 --- a/src/auth0/handlers/clientGrants.js +++ b/src/auth0/handlers/clientGrants.js @@ -1,4 +1,5 @@ import DefaultHandler, { order } from './default'; +import { convertClientNamesToIds } from '../../utils'; export const schema = { type: 'array', @@ -58,10 +59,7 @@ export default class ClientHandler extends DefaultHandler { const clients = await this.client.clients.getAll({ paginate: true }); const excludedClientsByNames = (assets.exclude && assets.exclude.clients) || []; - const excludedClients = excludedClientsByNames.map((clientName) => { - const found = clients.find(c => c.name === clientName); - return (found && found.client_id) || clientName; - }); + const excludedClients = convertClientNamesToIds(excludedClientsByNames, clients); // Convert clients by name to the id const formatted = assets.clientGrants.map((clientGrant) => { diff --git a/src/auth0/handlers/connections.js b/src/auth0/handlers/connections.js index 783c896..26c0b0a 100644 --- a/src/auth0/handlers/connections.js +++ b/src/auth0/handlers/connections.js @@ -1,5 +1,5 @@ import DefaultHandler, { order } from './default'; -import { filterExcluded } from '../../utils'; +import { filterExcluded, convertClientNameToId, convertClientNamesToIds } from '../../utils'; export const schema = { type: 'array', @@ -31,6 +31,13 @@ export default class ConnectionsHandler extends DefaultHandler { return super.objString({ name: connection.name, id: connection.id }); } + getClientWithIds(clients, mappings) { + return clients.map((clientNameOrId) => { + const found = mappings.find(c => c.name === clientNameOrId); + return (found && found.client_id) || clientNameOrId; + }); + } + async getType() { if (this.existing) return this.existing; const connections = await this.client.connections.getAll({ paginate: true }); @@ -49,19 +56,17 @@ export default class ConnectionsHandler extends DefaultHandler { // Convert enabled_clients by name to the id const clients = await this.client.clients.getAll({ paginate: true }); const excludedClientsByNames = (assets.exclude && assets.exclude.clients) || []; - const excludedClients = excludedClientsByNames.map((clientName) => { - const found = clients.find(c => c.name === clientName); - return (found && found.client_id) || clientName; - }); + const excludedClients = convertClientNamesToIds(excludedClientsByNames, clients); const formatted = assets.connections.map(connection => ({ ...connection, enabled_clients: [ - ...(connection.enabled_clients || []).map((name) => { - const found = clients.find(c => c.name === name); - if (found) return found.client_id; - return name; - }).filter(item => ![ ...excludedClientsByNames, ...excludedClients ].includes(item)) + ...convertClientNamesToIds( + connection.enabled_clients || [], + clients + ).filter( + item => ![ ...excludedClientsByNames, ...excludedClients ].includes(item) + ) ] })); diff --git a/src/auth0/handlers/databases.js b/src/auth0/handlers/databases.js index 2326e4e..4265329 100644 --- a/src/auth0/handlers/databases.js +++ b/src/auth0/handlers/databases.js @@ -1,6 +1,6 @@ import DefaultHandler, { order } from './default'; import constants from '../../constants'; -import { filterExcluded } from '../../utils'; +import { filterExcluded, convertClientNamesToIds } from '../../utils'; export const schema = { type: 'array', @@ -69,10 +69,7 @@ export default class DatabaseHandler extends DefaultHandler { // Convert enabled_clients by name to the id const clients = await this.client.clients.getAll({ paginate: true }); const excludedClientsByNames = (assets.exclude && assets.exclude.clients) || []; - const excludedClients = excludedClientsByNames.map((clientName) => { - const found = clients.find(c => c.name === clientName); - return (found && found.client_id) || clientName; - }); + const excludedClients = convertClientNamesToIds(excludedClientsByNames, clients); const formatted = databases.map((db) => { if (db.enabled_clients) { return { diff --git a/src/utils.js b/src/utils.js index 086ab49..9404e18 100644 --- a/src/utils.js +++ b/src/utils.js @@ -20,6 +20,15 @@ export function keywordReplace(input, mappings) { return input; } +export function convertClientNameToId(name, clients) { + const found = clients.find(c => c.name === name); + return (found && found.client_id) || name; +} + +export function convertClientNamesToIds(names, clients) { + return names.map(name => convertClientNameToId(name, clients)); +} + export function loadFile(file, mappings) { // Load file and replace keyword mappings const f = path.resolve(file); diff --git a/tests/utils.tests.js b/tests/utils.tests.js index c9229db..43469c6 100644 --- a/tests/utils.tests.js +++ b/tests/utils.tests.js @@ -96,6 +96,20 @@ describe('#utils', function() { expect(utils.duplicateItems(items, 'id')).to.deep.equal(duplicates); }); + + it('should replace client names with IDs or fallback', () => { + const clients = [ + { client_id: '1', name: 'aa' }, + { client_id: '2', name: 'bb' }, + { client_id: '3', name: 'cc' } + ]; + + const names = [ 'dd', 'cc', 'aa' ]; + + const expected = [ 'dd', '3', '1' ]; + + expect(utils.convertClientNamesToIds(names, clients)).to.deep.equal(expected); + }); }); describe('#utils calcChanges', () => { From 9571674dd13b921177c4c99467f2cd37b0057757 Mon Sep 17 00:00:00 2001 From: Shu Shen Date: Thu, 12 Mar 2020 22:19:18 -0700 Subject: [PATCH 2/3] connections: replace client name with ID in idpinitiated Resolves: #87 ESD-4561 #comment partial fix --- src/auth0/handlers/connections.js | 23 ++- tests/auth0/handlers/connections.tests.js | 170 ++++++++++++++++++++++ 2 files changed, 188 insertions(+), 5 deletions(-) diff --git a/src/auth0/handlers/connections.js b/src/auth0/handlers/connections.js index 26c0b0a..28ad280 100644 --- a/src/auth0/handlers/connections.js +++ b/src/auth0/handlers/connections.js @@ -31,11 +31,23 @@ export default class ConnectionsHandler extends DefaultHandler { return super.objString({ name: connection.name, id: connection.id }); } - getClientWithIds(clients, mappings) { - return clients.map((clientNameOrId) => { - const found = mappings.find(c => c.name === clientNameOrId); - return (found && found.client_id) || clientNameOrId; - }); + getFormattedOptions(connection, clients) { + try { + return { + options: { + ...connection.options, + idpinitiated: { + ...connection.options.idpinitiated, + client_id: convertClientNameToId( + connection.options.idpinitiated.client_id, + clients + ) + } + } + }; + } catch (e) { + return {}; + } } async getType() { @@ -60,6 +72,7 @@ export default class ConnectionsHandler extends DefaultHandler { const formatted = assets.connections.map(connection => ({ ...connection, + ...this.getFormattedOptions(connection, clients), enabled_clients: [ ...convertClientNamesToIds( connection.enabled_clients || [], diff --git a/tests/auth0/handlers/connections.tests.js b/tests/auth0/handlers/connections.tests.js index c2047d0..4b7f8fa 100644 --- a/tests/auth0/handlers/connections.tests.js +++ b/tests/auth0/handlers/connections.tests.js @@ -144,6 +144,176 @@ describe('#connections handler', () => { await stageFn.apply(handler, [ { connections: data } ]); }); + it('should convert client name with ID in idpinitiated.client_id', async () => { + const auth0 = { + connections: { + create: (data) => { + expect(data).to.deep.equal({ + enabled_clients: [ 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Tec' ], + name: 'someConnection-2', + strategy: 'custom', + options: { + passwordPolicy: 'testPolicy', + idpinitiated: { + client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Tec', + client_protocol: 'samlp', + client_authorizequery: '' + } + } + }); + return Promise.resolve(data); + }, + update: (params, data) => { + expect(params).to.be.an('object'); + expect(params.id).to.equal('con1'); + expect(data).to.deep.equal({ + enabled_clients: [ 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Tec' ], + options: { + passwordPolicy: 'testPolicy', + idpinitiated: { + client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Teb', + client_protocol: 'samlp', + client_authorizequery: '' + } + } + }); + + return Promise.resolve({ ...params, ...data }); + }, + delete: () => Promise.resolve([]), + getAll: () => [ + { name: 'someSamlConnection', id: 'con1', strategy: 'samlp' } + ] + }, + clients: { + getAll: () => [ + { name: 'client1', client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Tec' }, + { name: 'idp-one', client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Teb' } + ] + }, + pool + }; + + const handler = new connections.default({ client: auth0, config }); + const stageFn = Object.getPrototypeOf(handler).processChanges; + const data = [ + { + name: 'someSamlConnection', + strategy: 'samlp', + enabled_clients: [ 'client1' ], + options: { + passwordPolicy: 'testPolicy', + idpinitiated: { + client_id: 'idp-one', + client_protocol: 'samlp', + client_authorizequery: '' + } + } + }, + { + name: 'someConnection-2', + strategy: 'custom', + enabled_clients: [ 'client1' ], + options: { + passwordPolicy: 'testPolicy', + idpinitiated: { + client_id: 'client1', + client_protocol: 'samlp', + client_authorizequery: '' + } + } + } + ]; + + await stageFn.apply(handler, [ { connections: data } ]); + }); + + + it('should keep client ID in idpinitiated.client_id', async () => { + const auth0 = { + connections: { + create: (data) => { + expect(data).to.deep.equal({ + enabled_clients: [ 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Tec' ], + name: 'someConnection-2', + strategy: 'custom', + options: { + passwordPolicy: 'testPolicy', + idpinitiated: { + client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Ted', + client_protocol: 'samlp', + client_authorizequery: '' + } + } + }); + return Promise.resolve(data); + }, + update: (params, data) => { + expect(params).to.be.an('object'); + expect(params.id).to.equal('con1'); + expect(data).to.deep.equal({ + enabled_clients: [ 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Tec' ], + options: { + passwordPolicy: 'testPolicy', + idpinitiated: { + client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Teb', + client_protocol: 'samlp', + client_authorizequery: '' + } + } + }); + + return Promise.resolve({ ...params, ...data }); + }, + delete: () => Promise.resolve([]), + getAll: () => [ + { name: 'someSamlConnection', id: 'con1', strategy: 'samlp' } + ] + }, + clients: { + getAll: () => [ + { name: 'client1', client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Tec' }, + { name: 'idp-one', client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Teb' } + ] + }, + pool + }; + + const handler = new connections.default({ client: auth0, config }); + const stageFn = Object.getPrototypeOf(handler).processChanges; + const data = [ + { + name: 'someSamlConnection', + strategy: 'samlp', + enabled_clients: [ 'client1' ], + options: { + passwordPolicy: 'testPolicy', + idpinitiated: { + client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Teb', + client_protocol: 'samlp', + client_authorizequery: '' + } + } + }, + { + name: 'someConnection-2', + strategy: 'custom', + enabled_clients: [ 'client1' ], + options: { + passwordPolicy: 'testPolicy', + idpinitiated: { + client_id: 'YwqVtt8W3pw5AuEz3B2Kse9l2Ruy7Ted', + client_protocol: 'samlp', + client_authorizequery: '' + } + } + } + ]; + + await stageFn.apply(handler, [ { connections: data } ]); + }); + + it('should omit excluded clients', async () => { const auth0 = { connections: { From 5fe88c520afd93f4f5953ae7712cd8a5c3d7b711 Mon Sep 17 00:00:00 2001 From: Shu Shen Date: Fri, 27 Mar 2020 15:11:06 -0700 Subject: [PATCH 3/3] Bump version to v4.0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b8c8815..65c1782 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "auth0-source-control-extension-tools", - "version": "4.0.3", + "version": "4.0.4", "description": "Supporting tools for the Source Control extensions", "main": "lib/index.js", "scripts": {