From 8eca44424b98f3ac414e14bffcaed5cd5b60dd63 Mon Sep 17 00:00:00 2001 From: Akshay Ganeshen Date: Sun, 29 Aug 2021 17:33:28 -0400 Subject: [PATCH 1/4] feat: convert @azure/ms-rest-nodeauth to identity Convert usages of `@azure/ms-rest-nodeauth` and `adal-node` packages to use the equivalent `@azure/identity` functions. BREAKING CHANGE: This introduces breaking changes as it replaces the previously used `adal-node` package for Azure authentication with the new `@azure/identity` package. Because of difference in these two libraries we had to remove support for the `msiEndpoint` option of the `azure-active-directory-msi-vm` authentication method, and the `msiEndpoint` and `msiSecret` options of the `azure-active-directory-msi-app-service` authentication option. There could also be other changes in authentication behavior, so be careful when upgrading if you're using one of the Azure specific authentication methods. --- src/connection.ts | 121 ++++++++++------------------------------------ 1 file changed, 26 insertions(+), 95 deletions(-) diff --git a/src/connection.ts b/src/connection.ts index 7520a5f85..689d5b190 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -8,13 +8,11 @@ import { createSecureContext, SecureContext, SecureContextOptions } from 'tls'; import { Readable } from 'stream'; import { - loginWithVmMSI, - loginWithAppServiceMSI, - UserTokenCredentials, - MSIVmTokenCredentials, - MSIAppServiceTokenCredentials, - ApplicationTokenCredentials -} from '@azure/ms-rest-nodeauth'; + ClientSecretCredential, + ManagedIdentityCredential, + TokenCredential, + UsernamePasswordCredential, +} from '@azure/identity'; import BulkLoad, { Options as BulkLoadOptions, Callback as BulkLoadCallback } from './bulk-load'; import Debug from './debug'; @@ -42,7 +40,6 @@ import { createNTLMRequest } from './ntlm'; import { ColumnMetadata } from './token/colmetadata-token-parser'; import { ColumnEncryptionAzureKeyVaultProvider } from './always-encrypted/keystore-provider-azure-key-vault'; import depd from 'depd'; -import { MemoryCache } from 'adal-node'; import { AbortController, AbortSignal } from 'node-abort-controller'; import { Parameter, TYPES } from './data-type'; @@ -50,6 +47,7 @@ import { BulkLoadPayload } from './bulk-load-payload'; import { Collation } from './collation'; import { version } from '../package.json'; +import { URL } from 'url'; // eslint-disable-next-line @typescript-eslint/no-unused-vars const deprecate = depd('tedious'); @@ -211,14 +209,6 @@ interface AzureActiveDirectoryMsiAppServiceAuthentication { * This is optional for retrieve token from azure web app service */ clientId?: string; - /** - * A msi app service environment need to provide `msiEndpoint` for retriving the accesstoken. - */ - msiEndpoint?: string; - /** - * A msi app service environment need to provide `msiSecret` for retriving the accesstoken. - */ - msiSecret?: string; }; } @@ -232,10 +222,6 @@ interface AzureActiveDirectoryMsiVmAuthentication { * This is optional for retrieve token from azure web app service */ clientId?: string; - /** - * A user need to provide `msiEndpoint` for retriving the accesstoken. - */ - msiEndpoint?: string; }; } @@ -1137,22 +1123,10 @@ class Connection extends EventEmitter { throw new TypeError('The "config.authentication.options.clientId" property must be of type string.'); } - if (options.msiEndpoint !== undefined && typeof options.msiEndpoint !== 'string') { - throw new TypeError('The "config.authentication.options.msiEndpoint" property must be of type string.'); - } - - if (options.msiEndpoint !== undefined && options.msiEndpoint !== process.env.MSI_ENDPOINT) { - deprecate( - 'The `config.authentication.options.msiEndpoint` property is deprecated and will be removed in the next major release. ' + - 'To silence this message, ensure that `process.env.MSI_ENDPOINT` and `config.authentication.options.msiEndpoint` are set to the same value.' - ); - } - authentication = { type: 'azure-active-directory-msi-vm', options: { - clientId: options.clientId, - msiEndpoint: options.msiEndpoint + clientId: options.clientId } }; } else if (type === 'azure-active-directory-msi-app-service') { @@ -1160,34 +1134,10 @@ class Connection extends EventEmitter { throw new TypeError('The "config.authentication.options.clientId" property must be of type string.'); } - if (options.msiEndpoint !== undefined && typeof options.msiEndpoint !== 'string') { - throw new TypeError('The "config.authentication.options.msiEndpoint" property must be of type string.'); - } - - if (options.msiSecret !== undefined && typeof options.msiSecret !== 'string') { - throw new TypeError('The "config.authentication.options.msiSecret" property must be of type string.'); - } - - if (options.msiEndpoint !== undefined && options.msiEndpoint !== process.env.MSI_ENDPOINT) { - deprecate( - 'The `config.authentication.options.msiEndpoint` property is deprecated and will be removed in the next major release. ' + - 'To silence this message, ensure that `process.env.MSI_ENDPOINT` and `config.authentication.options.msiEndpoint` are set to the same value.' - ); - } - - if (options.msiSecret !== undefined && options.msiSecret !== process.env.MSI_SECRET) { - deprecate( - 'The `config.authentication.options.msiSecret` property is deprecated and will be removed in the next major release. ' + - 'To silence this message, ensure that `process.env.MSI_SECRET` and `config.authentication.options.msiSecret` are set to the same value.' - ); - } - authentication = { type: 'azure-active-directory-msi-app-service', options: { - clientId: options.clientId, - msiEndpoint: options.msiEndpoint, - msiSecret: options.msiSecret + clientId: options.clientId } }; } else if (type === 'azure-active-directory-service-principal-secret') { @@ -3460,8 +3410,6 @@ class Connection extends EventEmitter { export default Connection; module.exports = Connection; -const authenticationCache = new MemoryCache(); - Connection.prototype.STATE = { INITIALIZED: { name: 'Initialized', @@ -3739,54 +3687,37 @@ Connection.prototype.STATE = { if (fedAuthInfoToken && fedAuthInfoToken.stsurl && fedAuthInfoToken.spn) { const authentication = this.config.authentication as AzureActiveDirectoryPasswordAuthentication | AzureActiveDirectoryMsiVmAuthentication | AzureActiveDirectoryMsiAppServiceAuthentication | AzureActiveDirectoryServicePrincipalSecret; + const tokenScope = new URL('/.default', fedAuthInfoToken.spn).toString(); const getToken = (callback: (error: Error | null, token?: string) => void) => { - const getTokenFromCredentials = (err: Error | undefined, credentials?: UserTokenCredentials | MSIAppServiceTokenCredentials | MSIVmTokenCredentials | ApplicationTokenCredentials) => { - if (err) { - return callback(err); - } - - credentials!.getToken().then((tokenResponse: { accessToken: string | undefined }) => { - callback(null, tokenResponse.accessToken); + const getTokenFromCredentials = (credentials: TokenCredential) => { + credentials.getToken(tokenScope).then((tokenResponse) => { + callback(null, tokenResponse?.token); }, callback); }; if (authentication.type === 'azure-active-directory-password') { - const credentials = new UserTokenCredentials( - '7f98cb04-cd1e-40df-9140-3bf7e2cea4db', - authentication.options.domain ?? 'common', + const credentials = new UsernamePasswordCredential( + authentication.options.domain ?? 'common', // tenantId + '7f98cb04-cd1e-40df-9140-3bf7e2cea4db', // clientId authentication.options.userName, - authentication.options.password, - fedAuthInfoToken.spn, - undefined, // environment - authenticationCache + authentication.options.password ); - getTokenFromCredentials(undefined, credentials); - } else if (authentication.type === 'azure-active-directory-msi-vm') { - loginWithVmMSI({ - clientId: authentication.options.clientId, - msiEndpoint: authentication.options.msiEndpoint, - resource: fedAuthInfoToken.spn - }, getTokenFromCredentials); - } else if (authentication.type === 'azure-active-directory-msi-app-service') { - loginWithAppServiceMSI({ - msiEndpoint: authentication.options.msiEndpoint, - msiSecret: authentication.options.msiSecret, - resource: fedAuthInfoToken.spn, - clientId: authentication.options.clientId - }, getTokenFromCredentials); + getTokenFromCredentials(credentials); + } else if (authentication.type === 'azure-active-directory-msi-vm' || authentication.type === 'azure-active-directory-msi-app-service') { + const msiArgs = authentication.options.clientId ? [ authentication.options.clientId, {} ] : [ {} ]; + const credentials = new ManagedIdentityCredential(...msiArgs); + + getTokenFromCredentials(credentials); } else if (authentication.type === 'azure-active-directory-service-principal-secret') { - const credentials = new ApplicationTokenCredentials( + const credentials = new ClientSecretCredential( + authentication.options.tenantId, authentication.options.clientId, - authentication.options.tenantId, // domain - authentication.options.clientSecret, - fedAuthInfoToken.spn, - undefined, // environment - authenticationCache + authentication.options.clientSecret ); - getTokenFromCredentials(undefined, credentials); + getTokenFromCredentials(credentials); } }; From 46f330fafbd67286c1a448f5d6bb4b4c652f214e Mon Sep 17 00:00:00 2001 From: Akshay Ganeshen Date: Mon, 30 Aug 2021 21:44:03 -0400 Subject: [PATCH 2/4] chore: remove @azure/ms-rest-nodeauth dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index a4073bca2..a10a1f274 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "dependencies": { "@azure/identity": "^1.5.2", "@azure/keyvault-keys": "^4.3.0", - "@azure/ms-rest-nodeauth": "^3.0.10", "@js-joda/core": "^4.0.0", "adal-node": "^0.2.2", "bl": "^5.0.0", From 406ad78af3ee372d01f53680bc94b74dd1805ca9 Mon Sep 17 00:00:00 2001 From: Akshay Ganeshen Date: Sun, 5 Sep 2021 13:34:13 -0400 Subject: [PATCH 3/4] chore: remove adal-node dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index a10a1f274..8569c5313 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "@azure/identity": "^1.5.2", "@azure/keyvault-keys": "^4.3.0", "@js-joda/core": "^4.0.0", - "adal-node": "^0.2.2", "bl": "^5.0.0", "depd": "^2.0.0", "iconv-lite": "^0.6.3", From ed81a16e7015c728ac400f0271ef0cee15697a94 Mon Sep 17 00:00:00 2001 From: Akshay Ganeshen Date: Sun, 5 Sep 2021 15:52:18 -0400 Subject: [PATCH 4/4] chore(lock): update lock to remove azure auth deps --- package-lock.json | 164 ++-------------------------------------------- 1 file changed, 4 insertions(+), 160 deletions(-) diff --git a/package-lock.json b/package-lock.json index 043070384..b41b8b199 100644 --- a/package-lock.json +++ b/package-lock.json @@ -368,75 +368,6 @@ } } }, - "@azure/ms-rest-azure-env": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz", - "integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==" - }, - "@azure/ms-rest-js": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.6.0.tgz", - "integrity": "sha512-4C5FCtvEzWudblB+h92/TYYPiq7tuElX8icVYToxOdggnYqeec4Se14mjse5miInKtZahiFHdl8lZA/jziEc5g==", - "requires": { - "@azure/core-auth": "^1.1.4", - "abort-controller": "^3.0.0", - "form-data": "^2.5.0", - "node-fetch": "^2.6.0", - "tough-cookie": "^3.0.1", - "tslib": "^1.10.0", - "tunnel": "0.0.6", - "uuid": "^8.3.2", - "xml2js": "^0.4.19" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - } - } - }, - "@azure/ms-rest-nodeauth": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-3.0.10.tgz", - "integrity": "sha512-oel7ibYlredh2wo7XwNYMx4jWlbMkIzCC8t8VpdhsAWDJVNSSce+DYj5jjZn1oED+QsCytVM2B7/QTuLN1/yDw==", - "requires": { - "@azure/ms-rest-azure-env": "^2.0.0", - "@azure/ms-rest-js": "^2.0.4", - "adal-node": "^0.2.2" - }, - "dependencies": { - "@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==" - }, - "adal-node": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/adal-node/-/adal-node-0.2.2.tgz", - "integrity": "sha512-luzQ9cXOjUlZoCiWeYbyR+nHwScSrPTDTbOInFphQs/PnwNz6wAIVkbsHEXtvYBnjLctByTTI8ccfpGX100oRQ==", - "requires": { - "@types/node": "^8.0.47", - "async": "^2.6.3", - "axios": "^0.21.1", - "date-utils": "*", - "jws": "3.x.x", - "underscore": ">= 1.3.1", - "uuid": "^3.1.0", - "xmldom": ">= 0.1.x", - "xpath.js": "~1.1.0" - } - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "requires": { - "lodash": "^4.17.14" - } - } - } - }, "@azure/msal-common": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-4.5.1.tgz", @@ -5112,14 +5043,6 @@ "through": ">=2.2.7 <3" } }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -5132,37 +5055,6 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, - "adal-node": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/adal-node/-/adal-node-0.2.2.tgz", - "integrity": "sha512-luzQ9cXOjUlZoCiWeYbyR+nHwScSrPTDTbOInFphQs/PnwNz6wAIVkbsHEXtvYBnjLctByTTI8ccfpGX100oRQ==", - "requires": { - "@types/node": "^8.0.47", - "async": "^2.6.3", - "axios": "^0.21.1", - "date-utils": "*", - "jws": "3.x.x", - "underscore": ">= 1.3.1", - "uuid": "^3.1.0", - "xmldom": ">= 0.1.x", - "xpath.js": "~1.1.0" - }, - "dependencies": { - "@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==" - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "requires": { - "lodash": "^4.17.14" - } - } - } - }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -6380,11 +6272,6 @@ "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", "dev": true }, - "date-utils": { - "version": "1.2.21", - "resolved": "https://registry.npmjs.org/date-utils/-/date-utils-1.2.21.tgz", - "integrity": "sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q=" - }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -7143,11 +7030,6 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, "events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -7544,16 +7426,6 @@ "signal-exit": "^3.0.2" } }, - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -8228,11 +8100,6 @@ "p-is-promise": "^3.0.0" } }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" - }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -8945,7 +8812,8 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "lodash.capitalize": { "version": "4.2.1", @@ -14212,16 +14080,6 @@ "repeat-string": "^1.6.1" } }, - "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, "traverse": { "version": "0.6.6", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", @@ -14370,7 +14228,8 @@ "underscore": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", + "dev": true }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", @@ -14528,11 +14387,6 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=" - }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -14718,16 +14572,6 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, - "xmldom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz", - "integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==" - }, - "xpath.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz", - "integrity": "sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==" - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",